Windows에서 VirtualBox를 사용하여 Linux 환경에서 개발하고 계신 분들, 이런 고민이 있으신가요?
"VM을 시작하고, VSCode를 열고, SSH 연결하고... 매번 준비가 번거로워요!"
"VSCode에서 개발 프로필을 만들었는데, SSH 연결하면 기본값으로 열려요..."
"VM의 GUI는 사용하지 않는데, 리소스와 창이 낭비되는 것 같아요..."
이 글에서는 이러한 고민을 해결하고 개발 워크플로우를 크게 개선하는 방법을 소개합니다. 호스트 OS의 VSCode 기반 에디터에서 게스트 OS(Linux Mint를 예로 들지만, 다른 Linux 배포판에도 적용 가능)에 원활하게 연결하고, 최종적으로는 데스크톱 바로가기 하나로 VM 시작(헤드리스), SSH 연결, VSCode 시작까지 자동화하는 것을 목표로 합니다.
📌 사전 요구사항
호스트 OS: Windows 11
게스트 OS: VirtualBox의 Linux(이 글에서는 Linux Mint 22를 예로 들지만, Ubuntu 등 다른 Debian 기반 배포판에도 동일한 단계로 설정 가능)
에디터(호스트 OS): VSCode 또는 그 파생 에디터(이하 VSCode로 표기)
VirtualBox Guest Additions가 게스트 OS에 설치되어 있어야 함
⚠️ 면책 조항
이 글의 내용은 특정 검증 환경(연구실 개발 환경)을 기반으로 하며, 사용자 환경에서는 동일하게 작동하지 않을 수 있습니다.
작업을 수행할 때는 만일을 대비하여 가상 머신 스냅샷 생성이나 파일 백업 등 각자의 환경에 맞는 안전 조치를 취하세요.
글의 정보는 작성 시점의 것입니다. 각종 도구나 소프트웨어의 버전 업으로 내용이 오래되거나 단계가 변경될 수 있습니다.
필요에 따라 VirtualBox, VSCode, SSH, 사용 중인 Linux 배포판 등의 공식 문서도 함께 참조하세요.
☁️ 1. VSCode에서 게스트 OS로 SSH 연결 준비
먼저 호스트 OS의 VSCode에서 게스트 OS의 Linux 환경으로 SSH로 연결할 수 있도록 설정합니다.
1.1. VirtualBox 네트워크 설정 변경
SSH 연결을 받기 위해 VirtualBox의 네트워크 설정에서 포트 포워딩을 설정합니다.
VirtualBox 매니저를 열고 대상 가상 머신(예: Linux Mint)을 선택한 후 종료합니다.
가상 머신의 "설정"을 열고 "네트워크" 섹션으로 이동합니다.
"어댑터 1"(또는 사용할 어댑터)에서 다음과 같이 설정합니다.
연결됨: NAT
NAT를 선택하면 게스트 OS는 호스트 OS의 IP 주소를 공유하여 외부 네트워크에 연결하면서, 포트 포워딩으로 호스트 OS에서 게스트 OS로의 특정 통신을 허용할 수 있습니다.
"고급"을 펼치고 "포트 포워딩" 버튼을 클릭합니다.
규칙을 새로 추가(오른쪽의 + 버튼)하고 다음과 같이 설정합니다(게스트 IP는 비워둬도 됩니다).
이름
프로토콜
호스트 IP
호스트 포트
게스트 IP
게스트 포트
SSH
TCP
2222
22
호스트 포트 2222: 호스트 OS에서 SSH 연결을 대기하는 포트입니다. 다른 서비스와 충돌하지 않는 임의의 번호로 변경 가능합니다.
게스트 포트 22: 게스트 OS의 SSH 서버가 대기하는 표준 포트입니다.
1.2. 게스트 OS에서 SSH 서버 구축 및 자동 시작 설정
다음으로 게스트 OS(Linux Mint)에 SSH 서버를 설치하고 시작 및 자동 시작 설정을 합니다.
대상 가상 머신을 시작합니다.
게스트 OS의 터미널을 열고 다음 명령을 실행하여 OpenSSH 서버를 설치합니다.
Guest OS
첫 연결 시에는 지문 확인을 요구하므로 yes를 입력하고, 그 후 게스트 OS의 사용자 비밀번호를 입력합니다. 로그인되면 성공입니다.
1.5. VSCode에서 SSH 연결 설정
VSCode에서 쉽게 SSH 연결할 수 있도록 설정합니다.
호스트 OS의 VSCode를 시작합니다.
Remote - SSH 확장 기능 설치:
설치되어 있지 않다면, VSCode의 확장 기능 마켓플레이스에서 "Remote - SSH"(ms-vscode-remote.remote-ssh)를 검색하여 설치합니다.
SSH Config 파일 설정:
SSH 연결 설정을 SSH Config 파일에 기록합니다. 이 파일은 일반적으로 호스트 OS의 사용자 디렉토리 아래의 .ssh 폴더(예: C:\Users\[사용자 이름]\.ssh\config)에 있습니다. 파일이 없으면 새로 만드세요.
다음 내용을 추가하거나 새로 만듭니다.
.ssh/config
Host your_ssh_alias HostName localhost User your_guest_username Port 22222
your_ssh_alias: 임의의 연결 이름(예: vbox-mint). VSCode의 연결 목록에 표시됩니다.
your_guest_username: 게스트 OS의 사용자 이름.
Port 22222: VirtualBox의 포트 포워딩에서 설정한 호스트 포트.
VSCode에서 SSH 연결:
VSCode의 왼쪽 하단에 있는 녹색 "원격 창 열기" 아이콘(일반적으로 >< 모양)을 클릭합니다.
첫 연결 시에는 연결 대상 OS의 종류를 묻는 경우가 있습니다. "Linux"를 선택하세요.
새로운 VSCode 창이 열리고 게스트 OS의 사용자 비밀번호 입력을 요구합니다. 비밀번호를 입력하여 연결되면 성공입니다. 창의 왼쪽 하단에 SSH: your_ssh_alias로 표시됩니다.
이제 호스트 OS의 VSCode에서 게스트 OS의 파일 시스템에 접근하고 터미널도 게스트 OS의 것을 직접 사용할 수 있습니다.
여기까지의 설정에서의 과제:
매번 SSH 연결 시 비밀번호 입력 필요(이는 SSH 키 인증으로 개선 가능하지만, 이 글에서는 다루지 않습니다).
VSCode에서 특정 개발 프로필(확장 기능 세트 등)을 사용하여 연결하려면 추가 단계가 필요할 수 있습니다.
게스트 OS를 VirtualBox 매니저에서 수동으로 시작해야 하며, GUI 창이 표시됩니다.
다음 섹션에서는 이러한 과제를 해결하기 위한 자동화 단계로 진행합니다.
🤖 2. 시작 및 연결 자동화
목표는 데스크톱 바로가기를 한 번 클릭하는 것만으로 다음 처리를 자동으로 수행하는 것입니다.
VirtualBox의 게스트 OS를 헤드리스 모드(GUI 없음)로 시작.
게스트 OS의 SSH 서버가 시작될 때까지 대기.
지정한 VSCode 프로필과 작업 공간으로 게스트 OS에 SSH 연결된 상태에서 VSCode 시작.
2.1. VBoxManage 명령줄 도구 사용 준비
VirtualBox를 명령줄에서 조작하기 위해 VBoxManage.exe의 경로를 설정합니다.
Windows의 "설정" → "시스템" → "정보"로 이동하여 "고급 시스템 설정"을 클릭합니다.
"환경 변수" 버튼을 클릭합니다.
"시스템 변수"의 "Path"를 선택하고 "편집"을 클릭합니다.
"새로 만들기"를 클릭하고 VirtualBox의 설치 디렉토리(일반적으로 C:\Program Files\Oracle\VirtualBox)를 추가합니다.
OK를 눌러 모든 대화 상자를 닫고, 설정을 적용하기 위해 PC를 재시작하거나 새로운 명령 프롬프트/PowerShell 창을 엽니다.
명령 프롬프트 또는 PowerShell에서 VBoxManage --version을 실행하여 버전 정보가 표시되면 경로가 설정된 것입니다.
자동화 스크립트에서 사용할 VM의 이름을 확인합니다.
Host OS
VBoxManage list vms
표시된 목록에서 대상 VM의 이름(예: "Linux Mint 22" 또는 "MyLinuxVM" 등, 따옴표 포함)을 메모해 둡니다. 이후 이 VM 이름을 Your_VM_Name으로 합니다.
2.2. 게스트 OS의 SSH 준비 완료 알림 설정
게스트 OS가 시작되어 SSH 연결 준비가 완료되었음을 호스트 OS에 알리는 메커니즘을 구축합니다. 이를 위해 VirtualBox의 Guest Properties 기능을 사용합니다.
대상 가상 머신을 시작합니다.
게스트 OS 측: SSH 준비 완료 알림 스크립트 생성
게스트 OS의 홈 디렉토리 등에 SSH 서비스의 시작을 확인하고 Guest Property를 설정하는 스크립트를 만듭니다. 예를 들어, ~/bin/set-ssh-ready.sh로 다음과 같은 내용으로 만듭니다. ~/bin 디렉토리가 없으면 만드세요.
set-ssh-ready.sh
set-ssh-ready.sh
#!/bin/bash# SSH 서비스(sshd 또는 ssh)가 활성 상태인지 확인if systemctl is-active --quiet ssh || systemctl is-active --quiet sshd; then # VBoxControl 명령이 존재하는지 확인(Guest Additions의 일부) if command -v VBoxControl >/dev/null 2>&1; then /usr/bin/VBoxControl guestproperty set "/guestinfo/ssh.ready" "true" else echo "VBoxControl not found. Make sure Guest Additions are installed." >&2 fifi
스크립트에 실행 권한을 부여합니다.
Guest OS
$ mkdir -p ~/bin$ chmod +x ~/bin/set-ssh-ready.sh
게스트 OS 측: systemd 서비스 파일 생성
위 스크립트를 네트워크와 SSH 서비스가 시작된 후에 실행하기 위한 systemd 서비스 유닛 파일을 만듭니다.
sudo nano /etc/systemd/system/set-ssh-ready.service 등으로 에디터를 열고 다음 내용을 기록합니다. your_guest_username은 실제 게스트 OS의 사용자 이름으로 바꾸세요.
set-ssh-ready.service
Guest OS
[Unit]Description=Set SSH Ready guest property for VirtualBoxAfter=network.target ssh.service sshd.service[Service]User=your_guest_usernameGroup=your_guest_usernameExecStart=/home/your_guest_username/bin/set-ssh-ready.shType=oneshot[Install]WantedBy=multi-user.target
중요: ExecStart의 경로는 실제 스크립트의 위치와 사용자 이름에 맞게 조정하세요.
After 지시문에 sshd.service도 추가해 두면 배포판에 따라 SSH 데몬의 서비스 이름이 다른 경우에 대응하기 쉬워집니다.
{ "folders": [ { // "your_ssh_alias"는 1.5에서 설정한 SSH 호스트 이름 // "your_guest_username"은 게스트 OS의 사용자 이름 // "your_project_folder"는 게스트 OS 내의 프로젝트 폴더 이름 "uri": "vscode-remote://ssh-remote+your_ssh_alias/home/your_guest_username/your_project_folder" } ], "remoteAuthority": "ssh-remote+your_ssh_alias", // SSH 호스트 이름 지정 "settings": { // 작업 공간 고유의 설정이 있으면 기록 }, "tasks": { // 이 작업 공간에서 사용할 작업(예: VM 종료) "version": "2.0.0", "tasks": [ { "label": "Shutdown Guest VM", "type": "shell", "command": "VBoxManage controlvm \"Your_VM_Name\" poweroff", // 호스트 OS에서 실행되는 명령 "problemMatcher": [], "group": "build", "presentation": { "reveal": "always", "close": true } } ] }}
uri의 경로나 remoteAuthority는 자신의 환경에 맞게 정확하게 설정하세요.
tasks 내의 VM 종료 작업은 VSCode의 명령 팔레트(Ctrl+Shift+P)에서 Tasks: Run Task를 선택하고 Shutdown Guest VM을 실행하여 VM을 종료할 수 있습니다. 이는 호스트 OS 측의 명령으로 실행된다는 점에 주의하세요.
2.4. 호스트 OS 측: 자동 시작용 PowerShell 스크립트 생성
VM 시작, SSH 준비 대기, VSCode 시작을 연속해서 수행하는 PowerShell 스크립트를 만듭니다.
호스트 OS의 임의의 위치(예: C:\Users\[사용자 이름]\Scripts)에 .ps1이라는 확장자로 스크립트 파일을 만듭니다(예: launch-linux-dev-env.ps1).
다음 스크립트를 참고하여 파일에 내용을 기록합니다. <...>의 플레이스홀더 부분은 자신의 환경에 맞게 반드시 변경하세요.
launch-linux-dev-env.ps1
launch-linux-dev-env.ps1
<#.SYNOPSIS VirtualBox VM을 헤드리스로 시작하고, SSH 연결 준비가 완료될 때까지 대기한 후, 지정한 프로필과 작업 공간으로 VSCode를 시작합니다..DESCRIPTION 1. 지정된 VM이 실행 중이 아니면 헤드리스 모드로 시작합니다. 2. VM이 시작되고 Guest Property "/guestinfo/ssh.ready"가 "true"가 될 때까지 대기합니다. 3. 지정된 VSCode의 실행 경로, 프로필 이름, 작업 공간 파일로 VSCode를 시작합니다..NOTES Author: Riku-Mono Last Updated: 2025-06-07 Requires: VirtualBox command line tools (VBoxManage) in PATH. Guest OS configured to set "/guestinfo/ssh.ready" property.#>[CmdletBinding()]param()#======================================================================# 🔧 설정 (여기를 환경에 맞게 변경하세요)#======================================================================# VirtualBox 관련 설정$VMName = "<Your_VM_Name>" # 예: "Linux Mint 22" (VBoxManage list vms로 확인한 이름)# VSCode 관련 설정# VSCode 실행 파일의 경로. 일반적으로 다음 중 하나입니다.# $EditorPath = "$env:LOCALAPPDATA\Programs\Microsoft VS Code\Code.exe" # User Installer$EditorPath = "$env:ProgramFiles\Microsoft VS Code\Code.exe" # System Installer (필요에 따라 주석 해제)# $EditorPath = "<Path_To_Your_VSCode_Executable>" # 위 이외의 경우$EditorProfile = "<your_vscode_profile_name>" # 예: "dev-linux" (VSCode에서 사용할 프로필 이름. 없으면 새로 생성됨)$WorkspacePath = "<Path_To_Your_code-workspace_File>" # 예: "C:\Users\YourUser\Documents\VSCodeWorkspaces\my-linux-project.code-workspace" (2.3에서 만든 파일)# 타임아웃 설정(초): VM 시작과 SSH 준비의 대기 시간. 사양에 맞게 조정하세요.$VMStartTimeoutSec = 120$SSHReadyTimeoutSec = 120#======================================================================# 🧯 공통 함수#======================================================================function Write-Log { param( [Parameter(Mandatory=$true)] [string]$Message, [ValidateSet("Info", "Success", "Waiting", "Warning", "Error")] [string]$Severity = "Info" ) $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $Prefix = switch ($Severity) { "Info" { "ℹ️ [INFO]" } "Success" { "✅ [SUCCESS]" } "Waiting" { "⏳ [WAITING]" } "Warning" { "⚠️ [WARNING]" } "Error" { "🛑 [ERROR]" } default { " [LOG]" } } Write-Host "$Timestamp $Prefix $Message"}function Exit-Script { param ( [string]$Message = "스크립트를 종료합니다." ) Write-Log $Message -Severity Error Start-Sleep -Seconds 5 # 메시지를 읽을 시간 exit 1}function Test-VBoxInstalled { try { & VBoxManage --version | Out-Null return $true } catch { Write-Log "VirtualBox (VBoxManage)가 설치되어 있지 않거나 경로가 설정되어 있지 않습니다." -Severity Error return $false }}function Get-VMState { param ( [Parameter(Mandatory=$true)] [string]$TargetVMName ) try { $VMInfo = VBoxManage showvminfo $TargetVMName --machinereadable | Select-String -Pattern "^VMState=" if ($VMInfo) { return ($VMInfo -split "=")[1].Trim('"') } return "notfound" # VM을 찾을 수 없는 경우 } catch { Write-Log "VM '$TargetVMName'의 상태를 가져오는 데 실패했습니다: $($_.Exception.Message)" -Severity Error return "error" }}#======================================================================# 🚀 VM 시작 처리#======================================================================function Start-VMHeadless { param( [Parameter(Mandatory=$true)] [string]$TargetVMName ) Write-Log "VM '$TargetVMName'을(를) 헤드리스 모드로 시작합니다..." try { # SSH 준비 완료 플래그를 리셋(혹시 모르니) VBoxManage guestproperty set $TargetVMName "/guestinfo/ssh.ready" "" | Out-Null $Result = & VBoxManage startvm $TargetVMName --type headless 2>&1 if ($LASTEXITCODE -ne 0) { Write-Log "VM '$TargetVMName' 시작에 실패했습니다: $Result" -Severity Error return $false } Write-Log "VM '$TargetVMName' 시작 명령을 보냈습니다." -Severity Info return $true } catch { Write-Log "VM '$TargetVMName' 시작 중 오류가 발생했습니다: $($_.Exception.Message)" -Severity Error return $false }}#======================================================================# ⏳ VM 시작 및 SSH 준비 완료 대기 처리#======================================================================function WaitFor-VMStateAndSSHReady { param( [Parameter(Mandatory=$true)] [string]$TargetVMName, [Parameter(Mandatory=$true)] [string]$DesiredState, # 예: "running" [int]$VMTimeout, [int]$SSHTimeout ) Write-Log "VM '$TargetVMName'이(가) '$DesiredState' 상태가 될 때까지 대기 중... (타임아웃: ${VMTimeout}초)" $Stopwatch = [System.Diagnostics.Stopwatch]::StartNew() while ($Stopwatch.Elapsed.TotalSeconds -lt $VMTimeout) { $CurrentState = Get-VMState -TargetVMName $TargetVMName if ($CurrentState -eq $DesiredState) { Write-Log "VM '$TargetVMName'이(가) '$DesiredState' 상태가 되었습니다.($($Stopwatch.Elapsed.ToString('hh\:mm\:ss')) 경과)" -Severity Success $Stopwatch.Stop() break } Write-Log "현재 VM 상태: '$CurrentState'... ($($Stopwatch.Elapsed.ToString('hh\:mm\:ss')) 경과)" -Severity Waiting Start-Sleep -Seconds 2 } if ($Stopwatch.IsRunning) { # 타임아웃한 경우 $Stopwatch.Stop() Write-Log "타임아웃: VM '$TargetVMName'이(가) '$DesiredState' 상태가 되지 않았습니다." -Severity Error return $false } Write-Log "게스트 OS의 SSH 연결 준비를 대기 중... (타임아웃: ${SSHTimeout}초)" $Stopwatch.Restart() while ($Stopwatch.Elapsed.TotalSeconds -lt $SSHTimeout) { try { $Result = VBoxManage guestproperty get $TargetVMName "/guestinfo/ssh.ready" if ($Result -match "Value: true") { Write-Log "SSH 연결 준비가 완료되었습니다.($($Stopwatch.Elapsed.ToString('hh\:mm\:ss')) 경과)" -Severity Success return $true } Write-Log "SSH 준비 상태 확인 중... ($($Stopwatch.Elapsed.ToString('hh\:mm\:ss')) 경과): $Result" -Severity Waiting } catch { Write-Log "Guest Property를 가져오는 데 실패했습니다. VM이 완전히 시작되지 않았을 수 있습니다. ($($Stopwatch.Elapsed.ToString('hh\:mm\:ss')) 경과)" -Severity Warning } Start-Sleep -Seconds 5 } Write-Log "타임아웃: SSH 연결 준비가 완료되지 않았습니다." -Severity Error Write-Log "VM '$TargetVMName'을(를) 종료합니다." -Severity Warning try { VBoxManage controlvm $TargetVMName poweroff | Out-Null } catch { Write-Log "VM '$TargetVMName' 종료 중 오류가 발생했습니다: $($_.Exception.Message)" -Severity Error } return $false}#======================================================================# 🖥️ VSCode 시작 처리#======================================================================function Start-VSCode { param( [Parameter(Mandatory=$true)] [string]$EditorExecPath, [string]$TargetProfile, [string]$TargetWorkspacePath ) Write-Log "VSCode를 시작합니다..." Write-Log " 실행 경로: $EditorExecPath" Write-Log " 프로필: $TargetProfile" Write-Log " 작업 공간: $TargetWorkspacePath" if (-not (Test-Path $EditorExecPath -PathType Leaf)) { Write-Log "지정된 VSCode 실행 경로를 찾을 수 없습니다: $EditorExecPath" -Severity Error return $false } if (-not (Test-Path $TargetWorkspacePath -PathType Leaf) -and $TargetWorkspacePath) { Write-Log "지정된 작업 공간 파일을 찾을 수 없습니다: $TargetWorkspacePath" -Severity Warning Write-Log "작업 공간 없이 계속합니다." $TargetWorkspacePath = $null # 작업 공간 없이 시작 } $Arguments = New-Object System.Collections.Generic.List[string] if ($TargetProfile) { $Arguments.Add("--profile") $Arguments.Add "$TargetProfile" } if ($TargetWorkspacePath) { $Arguments.Add "`"$TargetWorkspacePath`"" # 경로는 따옴표로 묶음 } try { Start-Process -FilePath $EditorExecPath -ArgumentList $Arguments Write-Log "VSCode 시작 명령을 보냈습니다." -Severity Info return $true } catch { Write-Log "VSCode 시작에 실패했습니다: $($_.Exception.Message)" -Severity Error return $false }}#======================================================================# ⭐ 메인 처리#======================================================================Write-Log "개발 환경 시작 스크립트를 시작합니다."# 0. VirtualBox가 사용 가능한지 확인if (-not (Test-VBoxInstalled)) { Exit-Script "VirtualBox (VBoxManage) 준비가 되어 있지 않습니다."}# 1. VM 상태 확인 및 시작 처리$CurrentVMState = Get-VMState -TargetVMName $VMNameif ($CurrentVMState -eq "running") { Write-Log "VM '$VMName'이(가) 이미 실행 중입니다." -Severity Info} elseif ($CurrentVMState -eq "poweroff" -or $CurrentVMState -eq "aborted" -or $CurrentVMState -eq "saved") { Write-Log "VM '$VMName'이(가) 현재 '$CurrentVMState' 상태입니다. 시작합니다." if (-not (Start-VMHeadless -TargetVMName $VMName)) { Exit-Script "VM '$VMName' 시작에 실패했습니다." }} elseif ($CurrentVMState -eq "notfound") { Exit-Script "VM '$VMName'을(를) 찾을 수 없습니다. VM 이름을 확인하세요."} else { Exit-Script "VM '$VMName'이(가) 예상치 못한 상태($CurrentVMState)입니다. 수동으로 확인하세요."}# 2. VM 시작 완료 및 SSH 준비 완료 대기if (-not (WaitFor-VMStateAndSSHReady -TargetVMName $VMName -DesiredState "running" -VMTimeout $VMStartTimeoutSec -SSHTimeout $SSHReadyTimeoutSec)) { Exit-Script "VM 준비가 타임아웃되었습니다."}# 3. VSCode 시작if (-not (Start-VSCode -EditorExecPath $EditorPath -TargetProfile $EditorProfile -TargetWorkspacePath $WorkspacePath)) { Exit-Script "VSCode 시작에 실패했습니다."}Write-Log "개발 환경 시작 처리가 완료되었습니다." -Severity SuccessStart-Sleep -Seconds 3 # 완료 메시지 표시용
데스크톱에 바로가기 생성:
데스크톱에서 마우스 오른쪽 버튼을 클릭하고 "새로 만들기" → "바로가기"를 선택합니다.
"항목의 위치를 입력하세요" 필드에 다음과 같이 입력합니다. <Path_To_Your_Script_File.ps1>은 위에서 만든 PowerShell 스크립트의 전체 경로로 바꾸세요.
"다음"을 클릭하고 바로가기에 임의의 이름(예: Linux 개발 환경 시작)을 지정하고 "완료"를 클릭합니다.
2.5. 시작 테스트 및 확인
만든 데스크톱 바로가기를 더블 클릭하여 실행합니다.
PowerShell 창이 열리고 로그 메시지가 표시되면서 처리가 진행됩니다.
VM이 시작됩니다(헤드리스이므로 VirtualBox의 GUI는 표시되지 않음).
SSH 준비 완료 대기.
VSCode가 시작됩니다.
VSCode가 시작되고 지정한 프로필로, 게스트 OS에 SSH 연결된 상태(왼쪽 하단에 SSH: your_ssh_alias로 표시)에서 지정한 작업 공간이 열리면 성공입니다. 첫 연결이나 프로필이 새로운 경우에는 비밀번호 입력이나 확인 대화 상자가 표시될 수 있습니다.
정상적으로 작동하지 않는 경우 확인할 점:
PowerShell 스크립트 내의 각 경로(VM 이름, VSCode 실행 경로, 작업 공간 경로)가 올바른지.
PowerShell 스크립트의 실행 정책(-ExecutionPolicy Bypass로 일시적으로 허용하고 있지만, 영구 설정은 Set-ExecutionPolicy 명령으로 확인하세요).
VBoxManage 명령이 경로가 설정되어 올바르게 실행되는지.
게스트 OS 측의 set-ssh-ready.sh 스크립트와 set-ssh-ready.service의 설정, 권한, 경로가 올바른지.
게스트 OS의 Guest Additions가 올바르게 설치되어 작동하는지.
VirtualBox의 네트워크 설정(포트 포워딩)이 올바른지.
게스트 OS의 방화벽 설정이 올바른지.
VSCode의 SSH Config 파일의 내용이 올바른지.
PowerShell 창에 표시되는 오류 메시지를 확인하세요.
💬 마지막으로
여기까지의 설정으로 데스크톱의 바로가기 하나로 개발 환경이 준비됩니다.
개발 워크플로우 개선 예
만든 바로가기를 실행합니다.
VSCode가 시작되고 게스트 OS에 SSH 연결이 설정됩니다(첫 연결이나 키 설정에 따라 비밀번호 입력 필요).
VSCode에서 코딩을 시작합니다.
VSCode 내의 터미널(이는 게스트 OS의 터미널입니다)에서 개발 서버(예: npm run dev, python manage.py runserver 등)를 시작합니다.
개발 서버가 게스트 OS의 특정 포트(예: 3000, 8000)에서 리스닝하는 경우, VSCode의 Remote-SSH 기능이 자동으로 해당 포트를 호스트 OS의 localhost의 동일 포트로 포워딩해 주는 경우가 많습니다. "포트" 탭에서 확인 및 수동 설정도 가능합니다.
호스트 OS의 브라우저에서 http://localhost:3000이나 http://localhost:8000 등으로 접속하여 동작을 확인합니다.
개발 종료 후 VM을 종료합니다.
VSCode의 명령 팔레트(Ctrl+Shift+P)에서 Tasks: Run Task를 실행하고 Shutdown Guest VM(2.3의 작업 공간 파일에서 정의한 작업)을 선택합니다.
또는 아래에서 설명하는 종료용 바로가기를 사용합니다.
추가하면 편리한 팁
SSH 키 인증 설정:
매번의 비밀번호 입력을 생략하기 위해 SSH 키 인증을 설정하는 것을 강력히 권장합니다. 호스트 OS에서 SSH 키 쌍을 생성하고 공개 키를 게스트 OS의 ~/.ssh/authorized_keys에 등록합니다.
개발용 서버 시작 작업 커스터마이즈 (.vscode/tasks.json):
프로젝트 폴더의 루트에 .vscode/tasks.json 파일을 만들어 VSCode에서 여러 개발 서버 시작 등을 일괄로 수행하는 작업을 정의할 수 있습니다.
예를 들어, 프론트엔드와 백엔드 서버를 동시에 시작하는 작업은 다음과 같이 기록할 수 있습니다.(내용은 프로젝트에 맞게 변경하세요)
.vscode/tasks.json (게스트 OS의 프로젝트 폴더 내에 배치)
.vscode/tasks.json
{ "version": "2.0.0", "tasks": [ { "label": "Dev Server: Frontend", "type": "shell", "command": "npm run dev", // 프론트엔드 시작 명령 "options": { "cwd": "${workspaceFolder}/frontend" // 프론트엔드 디렉토리 }, "problemMatcher": [], "isBackground": true // 백그라운드에서 실행 }, { "label": "Dev Server: Backend", "type": "shell", // 백엔드 시작 명령(가상 환경 활성화, 환경 변수 설정 등을 포함한 예) "command": "source ~/venvs/myproject_venv/bin/activate && export DB_USER='<db_user>' && python manage.py runserver 0.0.0.0:8000", "options": { "cwd": "${workspaceFolder}/backend" // 백엔드 디렉토리 }, "problemMatcher": [], "isBackground": true }, { "label": "Start All Dev Servers", "dependsOn": ["Dev Server: Frontend", "Dev Server: Backend"], "dependsOrder": "parallel", // 병렬 실행 "group": { "kind": "build", "isDefault": true // 빌드 작업의 기본값으로 설정 }, "problemMatcher": [] } ]}
명령 팔레트에서 Tasks: Run Task → Start All Dev Servers로 실행할 수 있습니다.
VM 종료용 바로가기:
VM을 빠르게 종료하기 위한 전용 바로가기를 데스크톱에 만듭니다.
"데스크톱에서 마우스 오른쪽 버튼 클릭" → "새로 만들기" → "바로가기"
"항목의 위치를 입력하세요"에 다음과 같이 입력합니다(Your_VM_Name은 실제 VM 이름으로 바꾸세요).
"다음"을 클릭하고 바로가기에 임의의 이름(예: VM 종료)을 지정하고 "완료"를 클릭합니다.
Q&A
Q: VSCode에서 Remote-SSH 연결 후 일부 확장 기능이 작동하지 않습니다.
A: Remote-SSH에서는 확장 기능이 "UI 확장 기능(로컬에서 작동)"과 "작업 공간 확장 기능(원격 SSH 서버에서 작동)"으로 분류됩니다. 필요한 확장 기능이 원격 측(게스트 OS)에 설치되어 있는지 확인하세요. 확장 기능 사이드바에서 각 확장 기능이 어디에 설치되어 있는지 확인하고, 필요한 경우 "SSH: your_ssh_alias에 설치"를 선택하세요.
Q: 게스트 OS의 Python 인터프리터나 Node.js 등이 VSCode에 인식되지 않습니다.
A: VSCode 창이 원격 서버에 연결되어 있는지 확인하세요(왼쪽 하단에 SSH: your_ssh_alias로 표시). 그 위에서 VSCode의 명령 팔레트에서 예를 들어 Python: Select Interpreter나 Node.js의 경우 nvm이나 nodenv 등으로 버전이 올바르게 선택되어 있는지 게스트 OS의 터미널에서 확인하세요. VSCode의 설정(settings.json)에서 명시적으로 경로를 지정해야 하는 경우도 있습니다.
이 글은 제 환경에서의 자동화 해결책의 한 예입니다.
여러분의 환경에 맞는 더 좋은 방법을 찾아 더 나은 개발 생활을 보내세요!