Cloudflare Tunnel 및 Authentik SSO를 사용한 자체 호스팅 원격 VSCode

발행: (2026년 3월 3일 오전 06:47 GMT+9)
14 분 소요
원문: Dev.to

Source: Dev.to

개요

원격으로 실험실 프로젝트를 작업하면 보통 모든 장치에 VPN이나 SSH 키가 필요합니다. code‑server가 이를 해결합니다 – 브라우저 탭에서 전체 VS Code 환경을 제공하고, Google SSO 뒤에 잠겨 있으며, Mac Mini에서 24시간 연중무휴로 실행됩니다.

구성 요소

구성 요소목적
code‑server (by Coder)브라우저에서 VS Code를 실행하며, LinuxServer.io에서 Docker 이미지로 패키징되었습니다
Cloudflare Tunnel아웃바운드 전용 터널 – 라우터에 열려 있는 포트가 없습니다
Authentik (by Authentik Security)Google OAuth2를 이용한 자체 호스팅 SSO
Nginx Proxy Manager (by jc21)모든 요청에 대해 포워드 인증을 적용하는 리버스 프록시

SSH는 작동하지만, 모든 장치에 클라이언트와 키가 필요하고 전체 편집기 경험을 잃게 됩니다.
code‑server는 확장 기능, 통합 터미널, 그리고 최신 브라우저에서 Claude Code를 제공합니다. 실행되고 프록시가 설정되면 iPad에서도 노트북만큼 잘 작동합니다.

Request Flow

Browser → Cloudflare Tunnel Edge → Nginx Proxy Manager → Authentik outpost check
                                                               ↓ (if authenticated)
                                                          code‑server
  • Nginx Proxy Manager는 auth_request를 사용하여 모든 요청을 Authentik의 내장 아웃포스트와 확인합니다.
  • 인증되지 않은 경우 Authentik 로그인 페이지로 이동합니다 – 이 경우 Google OAuth2 프롬프트가 표시됩니다.

코드‑서버용 Docker Compose

services:
  code-server:
    image: lscr.io/linuxserver/code-server:latest
    container_name: code-server
    environment:
      - PUID=501
      - PGID=20
      - TZ=America/Chicago
      - PASSWORD=${CODE_SERVER_PASSWORD}
      - SUDO_PASSWORD=${CODE_SERVER_PASSWORD}
      - DEFAULT_WORKSPACE=/config/workspace
    volumes:
      - /your/config:/config
      - /your/projects:/config/workspace/Projects
    ports:
      - 8484:8443
    restart: unless-stopped

비밀 정보

Compose 파일 옆에 .env 파일을 생성하세요:

CODE_SERVER_PASSWORD=your-password-here
chmod 600 .env   # 오직 당신의 사용자만 읽을 수 있습니다

중요: 환경 변수를 변경한 후 항상 docker compose up -d 를 (다시) 실행하세요.
docker restart는 컨테이너 생성 시의 원래 환경을 재사용하지만, docker compose up -d는 Compose 파일 .env 를 다시 읽습니다.

Nginx Proxy Manager 구성

  1. Create a proxy host for code.yourdomain.com

    • Forward Hostname: 서버의 로컬 IP ( localhost 가 아님)
    • Forward Port: 8484
  2. WebSockets Support: ON (code‑server에 필요)

  3. Force SSL: OFF – Cloudflare가 엣지에서 TLS를 종료하고 NPM에 평문 HTTP를 보냅니다. Force SSL를 활성화하면 무한 리다이렉트 루프가 발생합니다.

  4. Patch the generated NPM config (add Authentik blocks before the main location / block):

auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;

location /outpost.goauthentik.io {
    proxy_pass http://your-server-ip:9010/outpost.goauthentik.io;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

location @goauthentik_proxy_signin {
    internal;
    return 302 /outpost.goauthentik.io/start?rd=https://$http_host$request_uri;
}

rd=https://… 매개변수는 성공적인 로그인 후 code‑server로 다시 리다이렉트합니다. 이 매개변수가 없으면 Authentik이 자체 대시보드로 이동시킵니다.

  1. Reload Nginx after editing the config:
docker exec nginx-proxy-manager nginx -s reload

Common Pitfalls & Fixes

증상원인해결 방법
컴포즈를 편집한 후 자격 증명이 업데이트되지 않음docker compose up -d 대신 docker restart를 실행함docker compose up -d 사용
&가 포함된 비밀번호가 컴포즈를 깨뜨림YAML이 &를 앵커로 처리함비밀을 .env 파일로 옮기고 ${VAR}를 참조
Force‑SSL 리다이렉트 루프NPM이 HTTPS를 강제하고 Cloudflare가 이미 HTTP를 전송함NPM에서 Force‑SSL 비활성화
확장 프로그램 누락code‑server가 Microsoft Marketplace가 아니라 Open VSX Registry를 사용함Open VSX에서 제공되는 확장 프로그램만 설치 (아래 목록 참고)

확장 프로그램 설치

대부분의 확장 프로그램은 Open VSX 레지스트리에서 제공됩니다. 다음은 제가 사용한 예시입니다:

for ext in \
  anthropic.claude-code \
  llvm-vs-code-extensions.lldb-dap \
  mechatroner.rainbow-csv \
  ms-azuretools.vscode-containers \
  ms-python.debugpy \
  ms-python.python \
  swiftlang.swift-vscode \
  tomoki1207.pdf; do
  docker exec -u abc code-server \
    /app/code-server/bin/code-server --install-extension "$ext"
done

참고: github.copilot-chatms-python.vscode-pylance는 Open VSX에 없으며 설치할 수 없습니다.

Claude Code 추가 (Node.js 필요)

LinuxServer.io code-server 이미지에는 Claude Code가 CLI 에이전트에 필요로 하는 Node.js가 포함되어 있지 않습니다.

시작 스크립트 (config/custom-cont-init.d/install-claude.sh)

#!/bin/bash
# Install Node.js if missing
if ! command -v node &> /dev/null; then
  apt-get update -qq && apt-get install -y -qq nodejs npm > /dev/null 2>&1
fi

# Install Claude CLI if missing
if ! command -v claude &> /dev/null; then
  npm install -g @anthropic-ai/claude-code > /dev/null 2>&1
fi

LinuxServer.io 이미지에서는 컨테이너 시작 시 custom-cont-init.d/에 있는 모든 파일을 자동으로 실행하므로, Node와 Claude CLI가 docker compose up -d 사이클에서도 지속됩니다.

Claude Code 인증 함정

Claude Code는 두 가지 인증 방법을 지원합니다:

  1. OAuth 로그인 – Claude Pro/Max 구독을 사용합니다.
  2. API 키 – Anthropic API 계정에 대한 사용량 기반 청구를 사용합니다.

헤드리스 컨테이너에서는 콜백이 컨테이너에 도달할 수 없기 때문에 OAuth 브라우저 흐름이 실패합니다.

해결 방법 (macOS)

데스크톱 머신에서 이미 인증되어 있다면, OAuth 토큰은 시스템 키체인에 저장됩니다:

security find-generic-password -s "Claude Code-credentials" -w

이 명령은 accessToken 필드가 포함된 JSON 블롭을 반환합니다(예: sk-an…). 해당 토큰을 컨테이너에 내보내거나 Claude Code용 환경 변수로 설정하십시오.

요약

  1. Deploy code-server를 Docker Compose를 통해 배포합니다.
  2. Expose를 Cloudflare Tunnel → Nginx Proxy Manager → Authentik을 통해 노출합니다.
  3. Authentik의 auth_request 블록을 사용해 NPM을 Configure하고 Force‑SSL를 비활성화합니다.
  4. 필요한 확장 프로그램을 Install합니다 (Open VSX만).
  5. Node.js와 Claude Code CLI를 설치하는 시작 스크립트를 Add합니다.
  6. 키체인 내보내기(macOS) 또는 API 키를 통해 Claude Code 인증을 Handle합니다.

이제 최신 브라우저(아이패드 포함)에서 접근 가능한 완전한 기능의 VS Code 환경을 갖게 되었으며, Google SSO로 보안이 강화되고 Mac Mini에서 지속적으로 실행됩니다. 즐거운 코딩 되세요!

Anthropic OAuth 토큰 설정

# .env file (in the container)
ANTHROPIC_API_KEY=sk-ant-oat01-your-token-here
  • **OAuth 토큰 (sk-ant‑oat…)**은 구독을 통해 라우팅됩니다 (종량제 아님).
  • **API 토큰 (sk-ant‑api…)**은 토큰당 API 계정에 청구됩니다.
  • console.anthropic.com에서 키를 생성하면 API 키를 받게 되며 토큰당 요금이 부과됩니다.
  • 키체인에 저장된 OAuth 토큰은 기존 플랜을 사용합니다.

컨테이너에서 Claude Code 실행

기본 제공되는 Claude Code는 다음을 할 수 있습니다:

  • 작업 공간에서 파일을 읽고 쓸 수 있습니다.

기본적으로 할 수 없습니다:

  • Docker 명령 실행.
  • GitHub에 푸시.
  • 만든 사용자 정의 스킬 사용.

왜 단순한 해결책은 안 될까?

  • Docker 소켓 마운트 → 호스트에서 루트 권한을 부여 (컨테이너 탈출 위험).
  • SSH 키 추가 / sudo 로 도구 설치 → 실제 보안 위험을 초래.

sudo 없이 GitHub CLI 설치

# Get the latest GH version
GH_VERSION=$(curl -s https://api.github.com/repos/cli/cli/releases/latest \
               | grep '"tag_name"' | cut -d'"' -f4 | sed 's/v//')

# Download the tarball
curl -sL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_arm64.tar.gz" \
     -o /tmp/gh.tar.gz

# Extract and install to a writable directory
mkdir -p /config/bin
tar -xz -f /tmp/gh.tar.gz -C /tmp
cp /tmp/gh_${GH_VERSION}_linux_arm64/bin/gh /config/bin/gh

# Add to PATH for future sessions
echo 'export PATH="/config/bin:$PATH"' >> /config/.bashrc
  • /config영구 볼륨이므로 바이너리가 컨테이너 재생성 시에도 유지됩니다.
  • 세분화된 개인 액세스 토큰(PAT)으로 인증하고, Claude가 필요한 저장소에만 범위를 제한합니다. 이렇게 하면 컨테이너가 손상될 경우 피해 범위가 제한됩니다.

Docker 소켓 대신 Portainer 사용하기

Docker 소켓을 마운트하는 것은 컨테이너에 호스트의 루트 권한을 부여하는 것과 동일합니다.
보다 안전한 방법은 Claude가 Portainer의 REST API와 통신하도록 하는 것입니다.

  1. Portainer 액세스 토큰 생성

    • Portainer → Account Settings → Access Tokens → Add access token
    • claude-code-server와 같은 이름을 지정합니다.
  2. 컨테이너의 .env 파일에 토큰 저장

    PORTAINER_URL=https://portainer.yourdomain.com
    PORTAINER_TOKEN=your-token-here
  3. 컨테이너 내부에서 연결 테스트

    curl -s -H "X-API-Key: $PORTAINER_TOKEN" \
         $PORTAINER_URL/api/endpoints

이제 Claude는 컨테이너를 생성하고, 서비스 정보를 조회하며, 이미지를 풀링하는 등 호스트에 대한 상승된 접근 권한 없이 작업을 수행할 수 있습니다. 토큰은 범위가 지정되고, 감사 가능하며, 언제든지 취소할 수 있습니다.

사용자 정의 Claude 코드 스킬 추가 (슬래시 명령)

사용자 정의 스킬은 호스트의 ~/.claude/commands/에 존재합니다. 컨테이너 내부에서는 이것이 /config/.claude/commands/에 매핑되지만, 기본적으로는 존재하지 않습니다.

해결 방법 – docker‑compose.yml에 볼륨 마운트 추가

volumes:
  - /your/config:/config
  - /your/projects:/config/workspace/Projects
  - ~/.claude/commands:/config/.claude/commands:ro   # 읽기 전용 마운트
  • :ro 플래그는 마운트를 읽기 전용으로 만들며, Claude는 스킬을 사용할 수 있지만 컨테이너 내부에서 수정할 수는 없습니다.
  • 컨테이너를 재시작하면 다음 세션에서 스킬이 표시됩니다.

에이전트 정의 및 볼트 접근

볼트 노트에 저장된 에이전트 정의는 볼트가 작업 공간 폴더로 마운트되어 있기 때문에 이미 접근할 수 있습니다. 추가 설정이 필요 없습니다.

지속적인 개발 환경

인증된 VS Code

  • URL: https://code.yourdomain.com
  • iPad, iPhone, 모든 노트북에서 작동합니다.
  • 세션, 확장 프로그램, 설정 및 작업 공간은 /config 볼륨에 저장되므로 이미지 업데이트 후에도 유지됩니다.

Obsidian Vault

  • 작업 공간 폴더로 마운트됩니다.
  • 브라우저에서 편집한 노트가 iCloud와 즉시 동기화됩니다.

TL;DR 체크리스트

  • ANTHROPIC_API_KEY 설정을 OAuth 토큰(sk-ant‑oat…)으로 지정합니다.
  • gh 설치/config/bin에 (sudo 없이) 합니다.
  • Docker 소켓보다 Portainer API를 선호하고; PORTAINER_URLPORTAINER_TOKEN.env에 저장합니다.
  • ~/.claude/commands:/config/.claude/commands:ro사용자 정의 스킬을 읽기 전용으로 마운트합니다.
  • VS Code와 Obsidian을 위해 영구 볼륨(/config, vault, projects)을 활용합니다.

이 단계들을 따르면 Claude Code가 외부 서비스와 안전하게 상호작용할 수 있으며, 컨테이너 환경을 깔끔하고 재현 가능하게 유지합니다.

0 조회
Back to Blog

관련 글

더 보기 »

일이 정신 건강 위험이 될 때

markdown !Ravi Mishrahttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...