# 리눅스용 자체 포함 실행 파일을 만든다. (윈도우 PowerShell 용) # bash 가 필요 없다. VS Code 기본 터미널에서 그대로 돌아간다. # # .\deploy\publish-linux.ps1 # .\deploy\publish-linux.ps1 -Target ubuntu@서버주소 # 만들고 복사까지 # # 경로·서비스 이름이 다르면: # .\deploy\publish-linux.ps1 -Target ubuntu@서버 ` # -RemoteDir /home/ubuntu/gameserver -Service GameServer # # 서버에는 .NET 을 설치할 필요가 없다. param( [string]$Target = "", [string]$RemoteDir = "/srv/genesis", # 비우면 서버에서 자동으로 찾는다. [string]$Service = "" ) $ErrorActionPreference = "Stop" # 저장소 루트로 이동 (이 스크립트는 deploy/ 안에 있다) $root = Split-Path -Parent $PSScriptRoot Set-Location $root $project = "GameServer/GameServer.csproj" $out = "artifacts/linux-x64" Write-Host "== 1) 빌드 ==" -ForegroundColor Cyan if (Test-Path $out) { Remove-Item $out -Recurse -Force } dotnet publish $project ` -c Release ` -r linux-x64 ` --self-contained true ` -p:PublishSingleFile=true ` -p:EnableCompressionInSingleFile=true ` -p:DebugType=none ` -p:DebugSymbols=false ` -o $out ` --nologo if ($LASTEXITCODE -ne 0) { throw "publish 실패" } # 개발용 설정은 서버로 보내지 않는다. Remove-Item "$out/appsettings.Development.json" -Force -ErrorAction SilentlyContinue # 서버에서 바로 띄울 실행 스크립트. # - ASPNETCORE_URLS 가 없으면 localhost:5000 에만 묶여 외부에서 안 보인다. # - 윈도우에서 복사하면 실행 권한이 사라지므로 스스로 chmod 한다. # 반드시 LF 로 저장해야 한다. CRLF 면 리눅스에서 "bad interpreter" 로 죽는다. $runSh = @( '#!/usr/bin/env bash', '# 서버에서 이 폴더로 들어와 ./run.sh 하면 바로 뜬다.', '# PORT=8080 ./run.sh 처럼 포트를 바꿀 수 있다.', 'set -euo pipefail', 'cd "$(dirname "$0")"', '', 'PORT="${PORT:-5281}"', '', 'chmod +x ./GameServer 2>/dev/null || true', 'mkdir -p wwwroot/uploads', '', '# 0.0.0.0 이어야 바깥에서 접속된다. 127.0.0.1 로 두면 서버 안에서만 보인다.', 'export ASPNETCORE_URLS="http://0.0.0.0:${PORT}"', 'export ASPNETCORE_ENVIRONMENT=Production', '', '# genesis.env 가 있으면 거기 값이 appsettings.json 보다 우선한다.', 'if [ -f ./genesis.env ]; then', ' set -a; . ./genesis.env; set +a', 'fi', '', 'echo "http://0.0.0.0:${PORT} 에서 실행합니다. (Ctrl+C 로 종료)"', 'exec ./GameServer', '' ) -join "`n" # UTF-8(BOM 없음) + LF 로 기록 $utf8NoBom = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllText((Join-Path $root "$out/run.sh"), $runSh, $utf8NoBom) # 배포 후 확인 스크립트도 함께 넣는다. Copy-Item (Join-Path $PSScriptRoot "healthcheck.sh") "$out/" -Force -ErrorAction SilentlyContinue $size = "{0:N0} MB" -f ((Get-ChildItem $out -Recurse -File | Measure-Object Length -Sum).Sum / 1MB) Write-Host "" Write-Host " 산출물: $out ($size)" -ForegroundColor Green if ([string]::IsNullOrWhiteSpace($Target)) { Write-Host "" Write-Host " 서버로 올리려면:" -ForegroundColor Yellow Write-Host " .\deploy\publish-linux.ps1 -Target user@서버주소" Write-Host "" Write-Host " 직접 복사한다면:" Write-Host " scp -r $out/* user@서버주소:$RemoteDir/" Write-Host " ssh user@서버주소 `"cd $RemoteDir && chmod +x run.sh && ./run.sh`"" exit 0 } Write-Host "" Write-Host "== 2) 업로드 ==" -ForegroundColor Cyan Write-Host " 대상: ${Target}:$RemoteDir" # scp 는 지우지 않고 덮어쓰기만 한다. # 산출물에 wwwroot/uploads 가 없으므로 서버의 사진은 그대로 남는다. ssh $Target "mkdir -p '$RemoteDir'" if ($LASTEXITCODE -ne 0) { throw "서버 접속 실패" } scp -r "$out/*" "${Target}:$RemoteDir/" if ($LASTEXITCODE -ne 0) { throw "복사 실패" } Write-Host "" Write-Host "== 3) 마무리 ==" -ForegroundColor Cyan # 서버에서 실행할 명령. 작은따옴표 here-string 이라 PowerShell 이 손대지 않는다. $remoteScript = @' set -e cd "__DIR__" chmod +x GameServer run.sh mkdir -p wwwroot/uploads echo " 실행 권한 설정 완료" SVC="__SVC__" if [ -z "$SVC" ]; then for c in GameServer genesis gameserver portfolio; do if systemctl list-unit-files 2>/dev/null | grep -q "^$c.service"; then SVC="$c"; break; fi done fi if [ -n "$SVC" ]; then sudo systemctl restart "$SVC" && echo " $SVC 서비스 재시작" else echo " systemd 서비스를 찾지 못했습니다. ./run.sh 로 직접 실행하세요." fi '@ $remoteScript = $remoteScript.Replace('__DIR__', $RemoteDir).Replace('__SVC__', $Service) $remoteScript | ssh $Target "bash -s" Write-Host "" Write-Host "완료. 서버에서 실행하려면:" -ForegroundColor Green Write-Host " ssh $Target" Write-Host " cd $RemoteDir && ./run.sh" Write-Host "" Write-Host " (계속 띄워 두려면 README 5절의 systemd 등록을 참고하세요)"