Windows GUI → Ubuntu CLI SSH Remote Backend Setup. Windows GUI 앱은 로컬에서 사용하고, 실제 코드 실행·파일 읽기·명령 실행은 Ubuntu CLI 머신에서 수행한다. 구조 : ```text Windows ├─ Codex App / Claude Desktop GUI ├─ OpenSSH Client └─ ~/.ssh/config ↓ SSH Ubuntu Server 24.04 LTS ├─ OpenSSH Server ├─ Node.js 22, Codex CLI, Claude Code ├─ ~/code └─ Samba share: \\<UBUNTU_IP>\code ``` 예시값 : | 항목 | 예시값 | 설명 | | ------------------ | ----------------: | ------------------ | | `<UBUNTU_USER>` | `user_name` | Ubuntu 로그인 사용자명 | | `<UBUNTU_IP>` | `192.168.50.30` | Ubuntu 고정 IP | | `<WINDOWS_IP>` | `192.168.50.10` | Windows 머신 IP | | `<WINDOWS_SUBNET>` | `192.168.50.0/24` | 개발용 내부망 대역 | | `<GATEWAY_IP>` | `192.168.50.1` | 공유기 또는 게이트웨이 | | `<DNS_1>` | `192.168.50.1` | DNS 서버 | | `<NIC_NAME>` | `enp6s18` | Ubuntu 네트워크 인터페이스명 | | | | | --- # 1. Ubuntu Server 설치 Ubuntu는 GUI 없이 CLI 환경으로 설치한다. 권장: ```text Ubuntu Server 24.04 LTS ``` 설치 중 선택값: ```text Language: English Layout / Variant: Korean Choose the base for the installation: Ubuntu Server SSH configuration: Install OpenSSH server ``` 설치가 끝나면 Ubuntu에 로그인한다. --- # 2. Ubuntu 기본 패키지 설치 및 재부팅 ```bash sudo apt update && sudo apt -y full-upgrade sudo apt -y install build-essential curl ca-certificates git ripgrep fd-find unzip tmux jq bubblewrap # Ubuntu 패키지명은 fd-find이고 실행 파일명은 fdfind이므로 fd alias를 만든다. sudo ln -sf /usr/bin/fdfind /usr/local/bin/fd # 시간대 설정 sudo timedatectl set-timezone Asia/Seoul timedatectl sudo reboot ``` --- # 3. Ubuntu Network 설정 ## 3-1. 네트워크 인터페이스명 확인 ```bash ip -br link ip addr ``` 예를 들어 인터페이스명이 `enp6s18`이면 이후 `<NIC_NAME>` 자리에 `enp6s18`을 넣는다. 설치 환경마다 이름이 다를 수 있으므로 하드코딩하지 않는다. ## 3-2. Netplan 파일 확인 및 백업 ```bash ls /etc/netplan ``` 예시로 `50-cloud-init.yaml`이 나온 경우: ```bash sudo nano /etc/netplan/50-cloud-init.yaml ``` ## 3-3. Static IP 설정 예시 아래 예시는 Ubuntu IP를 `192.168.50.30`으로 고정하는 설정이다. ```yaml network: version: 2 renderer: networkd ethernets: enp6s18: dhcp4: false addresses: - 192.168.50.30/24 routes: - to: default via: 192.168.50.1 nameservers: addresses: - 192.168.50.1 - 1.1.1.1 # ctrl x, y, enter ``` 실제 적용 시 아래 값을 바꾼다. ```text enp6s18 → <NIC_NAME> 192.168.50.30 → <UBUNTU_IP> 192.168.50.1 → <GATEWAY_IP>, <DNS_1> ``` ## 3-4. Netplan 적용 로컬 콘솔에서 작업 중이면 아래 순서로 적용한다. ```bash sudo netplan try sudo netplan apply sudo netplan status -a ip addr ip route ``` `netplan try`에서 연결 문제가 생기면 자동 롤백할 수 있다. 원격 SSH 세션에서 네트워크 설정을 바꾸는 경우에는 특히 `netplan try`를 먼저 사용한다. --- # 4. Windows OpenSSH Client / Git / Terminal 설치 관리자 권한 PowerShell에서 실행. 1) Winget 설치 ```powershell Install-PackageProvider -Name NuGet -Force | Out-Null Install-Module -Name Microsoft.WinGet.Client -Force -Repository PSGallery | Out-Null Repair-WinGetPackageManager -Force -Latest ``` 2) 사전 도구 설치 ```powershell winget upgrade --id Microsoft.AppInstaller winget install --id Git.Git -e Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 winget install --id Microsoft.WindowsTerminal -e ``` 3) OpenSSH 확인 ```powershell ssh -V ``` --- # 5. Windows SSH key 생성 일반 PowerShell에서 실행한다. ```powershell New-Item -ItemType Directory -Force $HOME\.ssh | Out-Null ssh-keygen -t ed25519 -C "win10" ``` 권장: ```text 저장 경로: 기본값 사용, 보통 C:\Users\<WindowsUser>\.ssh\id_ed25519 Passphrase: 선택 사항 ``` SSH key에 passphrase를 설정했다면 GUI 앱에서 SSH 연결 시 `ssh-agent` 등록이 필요할 수 있다. 관련 명령은 Troubleshooting 섹션에 있다. --- # 6. Windows `~/.ssh/config` 작성 일반 PowerShell에서 실행한다. ```powershell notepad $HOME\.ssh\config ``` 아래 내용을 저장한다. 파일 이름은 `config.txt`가 아니라 확장자 없는 `config`여야 한다. ```sshconfig Host ubuntu-code HostName 192.168.50.30 User user_name IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes ServerAliveInterval 60 ServerAliveCountMax 3 ``` 실제 적용 시 아래 값을 바꾼다. ```text HostName 192.168.50.30 → HostName <UBUNTU_IP> User user_name → User <UBUNTU_USER> ``` `IdentitiesOnly yes`는 OpenSSH가 엉뚱한 key를 여러 개 시도하다가 실패하는 일을 줄인다. --- # 7. Windows 공개키를 Ubuntu에 전송 일반 PowerShell에서 실행한다. ```powershell $UbuntuUser = "user_name" $UbuntuIP = "192.168.50.30" Get-Content $HOME\.ssh\id_ed25519.pub | ssh "$($UbuntuUser)@$($UbuntuIP)" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" ``` 처음 접속할 때 host key 확인 메시지가 나오면 fingerprint를 확인한 뒤 `yes`를 입력한다. > 이 명령을 여러 번 실행하면 `authorized_keys`에 같은 공개키가 중복으로 들어갈 수 있다. 일반적으로 큰 문제는 아니지만, 깔끔하게 관리하려면 Ubuntu에서 `nano ~/.ssh/authorized_keys`로 중복 줄을 삭제한다. 수동 등록이 필요한 경우 Ubuntu에서 아래처럼 직접 붙여넣을 수 있다. ```bash mkdir -p ~/.ssh && chmod 700 ~/.ssh nano ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ``` 공개키 등록은 Windows 전송 방식과 Ubuntu 수동 붙여넣기 방식 중 하나만 수행한다. --- # 8. Windows에서 SSH 접속 확인 일반 PowerShell에서 실행한다. ```powershell ssh ubuntu-code ``` 성공 기준: ```text Windows PowerShell에서 ssh ubuntu-code 입력 → Ubuntu shell prompt가 열림 ``` 아직 SSH hardening을 적용하지 않는다. 먼저 key 기반 로그인이 정상인지 확인한 뒤에 비밀번호 로그인을 끈다. --- # 9. Ubuntu SSH hardening 이 단계는 반드시 8번에서 `ssh ubuntu-code` 접속이 성공한 뒤에만 수행한다. Ubuntu에서 실행한다. ```bash sudo nano /etc/ssh/sshd_config.d/10-hardening.conf ``` 아래 내용을 입력한다. ```text PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin no KbdInteractiveAuthentication no ``` 문법 검사 후 SSH를 재시작한다. ```bash sudo sshd -t sudo systemctl restart ssh.service ``` Windows에서 새 PowerShell 창을 열고 다시 확인한다. ```powershell ssh ubuntu-code ``` > 기존 SSH 세션 하나는 열어둔 상태에서 새 창으로 재접속을 확인한다. 새 접속이 실패하면 기존 세션에서 hardening 파일을 수정하거나 삭제해 복구할 수 있다. --- # 10. NodeSource 시스템 Node.js 22 설치 nvm은 사용하지 않는다. 원격 GUI 백엔드에서는 비대화식 SSH shell에서 `PATH` 문제가 생길 수 있으므로 시스템 경로에 잡히는 NodeSource APT 설치를 사용한다. Ubuntu에서 실행한다. ```bash curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs which node node -v npm -v ``` 정상 예시: ```text /usr/bin/node v22.x.x ``` 이 문서는 Node 22 계열 고정 설치를 기준으로 한다. `최신 LTS`라는 표현 대신 `Node 22 LTS 고정`으로 이해한다. --- # 11. Codex CLI 설치 및 device-auth 로그인 Ubuntu에서 실행한다. ```bash sudo npm install -g @openai/codex which codex codex --version ``` 로그인은 사용자 홈에 인증 정보를 저장해야 하므로 `sudo` 없이 실행한다. ```bash codex login --device-auth codex login status ``` `--device-auth` 실행 중 device code authentication 활성화가 필요하다는 메시지가 나오면: ```text 1. Windows 브라우저에서 ChatGPT 보안 설정으로 이동 2. Enable device code authentication for Codex 활성화 3. Ubuntu에서 codex login --device-auth 재실행 4. 출력된 URL과 one-time code를 Windows 브라우저에서 입력 5. codex login status로 성공 확인 ``` Windows에서 원격 shell의 PATH 확인: ```powershell ssh ubuntu-code 'command -v codex && codex --version' ``` 업데이트: ```bash sudo npm install -g @openai/codex@latest ``` > `sudo npm install -g`로 설치하면 전역 npm 패키지가 root-owned가 된다. 업데이트도 동일하게 `sudo npm install -g @openai/codex@latest`로 수행한다. 단, `codex login`과 `codex login status`는 절대 `sudo`로 실행하지 않는다. --- # 12. Claude Code 설치 또는 Desktop 자동 설치 사용 Claude Desktop SSH 세션만 사용할 목적이면, Desktop이 최초 SSH 연결 시 원격 머신에 Claude Code를 자동 설치할 수 있다. 그래도 Ubuntu CLI에서도 직접 `claude`를 쓰거나 설치 상태를 명확히 관리하려면 아래 apt 설치 방식을 사용한다. ## 12-A. 권장: apt repository 방식 Ubuntu에서 실행한다. ```bash sudo install -d -m 0755 /etc/apt/keyrings sudo curl -fsSL https://downloads.claude.ai/keys/claude-code.asc \ -o /etc/apt/keyrings/claude-code.asc # GPG key fingerprint 확인 # 출력에 아래 fingerprint가 포함되어야 한다. # 31DD DE24 DDFA B679 F42D 7BD2 BAA9 29FF 1A7E CACE gpg --show-keys /etc/apt/keyrings/claude-code.asc echo "deb [signed-by=/etc/apt/keyrings/claude-code.asc] https://downloads.claude.ai/claude-code/apt/stable stable main" \ | sudo tee /etc/apt/sources.list.d/claude-code.list sudo apt update sudo apt install claude-code claude --version claude doctor ``` 로그인은 사용자 계정으로 실행한다. ```bash claude # 최초 실행 시 로그인 프롬프트를 따른다. ``` 업데이트: ```bash sudo apt update && sudo apt upgrade claude-code ``` ## 12-B. 비권장: npm global 설치 Claude Code는 npm global 설치도 지원하지만, 이 문서에서는 사용하지 않는다. ```bash npm install -g @anthropic-ai/claude-code ``` 특히 아래 방식은 권한 문제와 보안 리스크 때문에 피한다. ```bash sudo npm install -g @anthropic-ai/claude-code ``` --- # 13. Ubuntu 작업 디렉터리 생성 ```bash mkdir -p ~/code sudo chown -R "$USER:$USER" ~/code ``` 권장 작업 위치: ```text /home/<UBUNTU_USER>/code ``` Codex App과 Claude Desktop에서 원격 프로젝트 폴더로 이 디렉터리를 선택한다. --- # 14. Samba 공유 설정 Windows에서 Ubuntu의 `~/code`를 네트워크 드라이브처럼 접근하기 위한 설정이다. ## 14-1. Samba 설치 Ubuntu에서 실행한다. ```bash sudo apt -y install samba ``` ## 14-2. Samba 사용자 등록 Linux 계정과 같은 이름으로 Samba 사용자를 등록한다. ```bash sudo smbpasswd -a user_name sudo smbpasswd -e user_name ``` 실제 적용 시 `user_name`을 `<UBUNTU_USER>`로 바꾼다. Samba 비밀번호는 Linux 로그인 비밀번호와 별개다. ## 14-3. Samba share 추가 Ubuntu에서 실행한다. ```bash sudo nano /etc/samba/smb.conf ``` 파일 맨 아래에 추가한다. ```ini [code] path = /home/user_name/code browseable = yes read only = no create mask = 0644 directory mask = 0755 valid users = user_name force user = user_name ``` 실제 적용 시 `user_name`을 `<UBUNTU_USER>`로 바꾼다. 문법 검사 및 재시작: ```bash sudo testparm sudo systemctl restart smbd sudo systemctl enable smbd sudo systemctl status smbd --no-pager ``` `nmbd`는 NetBIOS browsing이 필요한 경우에만 사용한다. Windows에서 `\\<UBUNTU_IP>\code`로 직접 접근한다면 보통 `445/tcp`와 `smbd`만으로 충분하다. ## 14-4. Windows에서 Samba 접근 PowerShell 또는 파일 탐색기 주소창에서: ```powershell \\192.168.50.30\code ``` 네트워크 드라이브로 매핑하려면: ```powershell $UbuntuIP = "192.168.50.30" $UbuntuUser = "user_name" net use Z: "\\$UbuntuIP\code" /user:$UbuntuUser ``` --- # 15. UFW 방화벽 설정 공유기 포트포워딩을 하지 않더라도 UFW는 켜는 편이 안전하다. SSH와 SMB는 Windows 호스트 또는 개발용 내부망에서만 허용한다. ## 15-1. Windows 1대만 허용하는 권장 설정 Ubuntu에서 실행한다. ```bash sudo ufw allow from 192.168.50.10 to any port 22 proto tcp sudo ufw allow from 192.168.50.10 to any port 445 proto tcp sudo ufw enable sudo ufw status verbose ``` 실제 적용 시 `192.168.50.10`을 `<WINDOWS_IP>`로 바꾼다. ## 15-2. 개발 서브넷 전체를 허용하는 대안 Windows IP가 자주 바뀌면 내부 개발 서브넷을 허용한다. ```bash sudo ufw allow from 192.168.50.0/24 to any port 22 proto tcp sudo ufw allow from 192.168.50.0/24 to any port 445 proto tcp sudo ufw enable sudo ufw status verbose ``` NetBIOS가 필요할 때만 139/tcp를 추가한다. ```bash sudo ufw allow from 192.168.50.0/24 to any port 139 proto tcp ``` > 절대 `0.0.0.0/0`에 SMB를 열지 않는다. 외부 접속이 필요하면 공유기 포트포워딩 대신 VPN 또는 Tailscale 같은 mesh network를 사용한다. --- # 16. Codex App에서 SSH host 추가 Windows에서 먼저 확인한다. ```powershell ssh ubuntu-code ssh ubuntu-code 'command -v codex && codex --version' ``` 그다음 Codex App에서: ```text Settings → Connections → Add SSH host → ubuntu-code 선택 ``` 정상 조건: ```text 1. Windows ~/.ssh/config에 Host ubuntu-code가 있음 2. Windows에서 ssh ubuntu-code가 성공함 3. Ubuntu에서 codex가 login shell PATH에 있음 4. Ubuntu에서 codex login status가 성공 상태임 ``` 이 문서에서는 `~/.codex/config.toml`에 `remote_connections = true`를 기본으로 넣지 않는다. 현재 기본 흐름은 앱의 Settings → Connections에서 SSH host를 추가하는 방식이다. --- # 17. Claude Desktop에서 SSH connection 추가 Windows에서 먼저 확인한다. ```powershell ssh ubuntu-code ssh ubuntu-code 'command -v claude && claude --version' ``` Claude Code를 Ubuntu에 미리 설치하지 않았다면 두 번째 명령은 실패할 수 있다. Claude Desktop은 최초 SSH 연결 시 원격 머신에 Claude Code를 자동 설치할 수 있다. Claude Desktop에서: ```text Code tab → Environment dropdown → + Add SSH connection ``` 권장 입력값: ```text Name: ubuntu-code SSH Host: ubuntu-code SSH Port: 22 Identity File: ~/.ssh/id_ed25519 Start Directory: ~/code ``` 또는 SSH Host에 직접 입력할 수 있다. ```text [email protected] ``` `~/.ssh/config`를 이미 정확히 작성했다면 `SSH Host`에는 `ubuntu-code`만 쓰는 편이 관리하기 쉽다. # ETC. Python 패키지 설치 ``` sudo apt install python3 python3-venv python3-pip pipx ``` --- # 18. Troubleshooting ## 18-1. `Permission denied (publickey,password)` 가능한 원인: ```text - SSH key passphrase가 있는데 ssh-agent에 등록되지 않음 - Windows ~/.ssh/config의 HostName/User/IdentityFile 불일치 - Ubuntu ~/.ssh 또는 authorized_keys 권한 문제 - Ubuntu IP 불일치 - 서버 측 PasswordAuthentication/PubkeyAuthentication 설정 문제 - 최초 host key 확인을 GUI 앱이 처리하지 못함 ``` Windows에서 디버깅: ```powershell ssh -vvv ubuntu-code ssh-add -l ``` Ubuntu에서 디버깅: ```bash ls -ld ~/.ssh ls -l ~/.ssh/authorized_keys sudo journalctl -fu ssh.service ``` 권한 복구: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys ``` ## 18-2. SSH key passphrase를 쓴 경우 ssh-agent 등록 관리자 권한 PowerShell: ```powershell Set-Service ssh-agent -StartupType Automatic Start-Service ssh-agent ``` 일반 PowerShell: ```powershell ssh-add $env:USERPROFILE\.ssh\id_ed25519 ssh-add -l ``` ## 18-3. Host key changed 또는 IP 재사용 문제 Ubuntu IP를 바꿨거나 같은 IP에 다른 머신을 붙였다면 Windows에서 기존 host key를 삭제한다. ```powershell ssh-keygen -R 192.168.50.30 ssh ubuntu-code ``` ## 18-4. Codex App에서 remote 연결 실패 Windows에서 확인: ```powershell ssh ubuntu-code ssh ubuntu-code 'echo $PATH; command -v codex; codex --version; codex login status' ``` Ubuntu에서 확인: ```bash which codex codex --version codex login status ``` 문제 원인별 조치: ```text codex: command not found → NodeSource 시스템 Node로 설치했는지 확인 → sudo npm install -g @openai/codex 재실행 codex login status 실패 → codex login --device-auth 재실행 Windows ssh ubuntu-code 실패 → Codex App 문제가 아니라 SSH 설정 문제부터 해결 ``` ## 18-5. Claude Desktop SSH 연결 실패 Windows에서 확인: ```powershell ssh ubuntu-code ``` Ubuntu에서 Claude Code 설치 상태 확인: ```bash command -v claude claude --version claude doctor ``` Claude Desktop의 SSH Host에는 `ubuntu-code` 또는 `[email protected]`을 입력한다. Identity File을 비워두면 기본 key 또는 SSH config를 사용한다. ## 18-6. Samba 접근 실패 Ubuntu에서 확인: ```bash sudo testparm sudo systemctl status smbd --no-pager sudo ufw status verbose pdbedit -L ``` Windows에서 확인: ```powershell net use net use Z: /delete net use Z: \\192.168.50.30\code /user:user_name ``` Samba 사용자 비밀번호를 다시 설정하려면: ```bash sudo smbpasswd -a user_name sudo smbpasswd -e user_name ``` ## 18-7. Netplan 적용 후 접속 불가 로컬 콘솔에서 백업 파일을 확인한다. ```bash ls -l /etc/netplan sudo nano /etc/netplan/50-cloud-init.yaml sudo netplan try sudo netplan apply ``` IP, gateway, DNS, interface name이 실제 환경과 일치하는지 확인한다. ```bash ip -br link ip addr ip route resolvectl status ``` --- # 19. 최종 점검 체크리스트 Windows PowerShell: ```powershell ssh ubuntu-code ssh ubuntu-code 'hostname; pwd; whoami' ssh ubuntu-code 'command -v node && node -v && npm -v' ssh ubuntu-code 'command -v codex && codex --version && codex login status' ssh ubuntu-code 'command -v claude && claude --version || true' ``` Ubuntu: ```bash sudo sshd -t sudo systemctl status ssh.service --no-pager sudo systemctl status smbd --no-pager sudo ufw status verbose ls -ld ~/code ``` Windows 파일 탐색기: ```text \\192.168.50.30\code ``` Codex App: ```text Settings → Connections → ubuntu-code → ~/code 선택 ``` Claude Desktop: ```text Code tab → Environment dropdown → ubuntu-code → ~/code 시작 ``` --- # 20. 유지보수 명령 Ubuntu 시스템 업데이트: ```bash sudo apt update && sudo apt -y full-upgrade sudo reboot ``` Codex CLI 업데이트: ```bash sudo npm install -g @openai/codex@latest codex --version ``` Claude Code apt 업데이트: ```bash sudo apt update && sudo apt upgrade claude-code claude --version ``` Samba 재시작: ```bash sudo testparm sudo systemctl restart smbd ``` SSH 설정 변경 후 검사: ```bash sudo sshd -t sudo systemctl restart ssh.service ``` --- # 21. 참고 공식 문서 - Codex remote connections: https://developers.openai.com/codex/remote-connections - Codex authentication / device code: https://developers.openai.com/codex/auth - Codex CLI reference: https://developers.openai.com/codex/cli/reference - Claude Code Desktop SSH sessions: https://code.claude.com/docs/en/desktop - Claude Code setup / apt repository: https://code.claude.com/docs/en/setup - Ubuntu Netplan network configuration: https://ubuntu.com/server/docs/explanation/networking/configuring-networks/ - NodeSource Debian/Ubuntu repository: https://deb.nodesource.com/