19 KiB
클라우드 서버 설정 가이드 (hz-prod-01)
시놀로지(Synology DSM)에서 클라우드 VPS(
178.104.200.7)로 이전. 이 문서는 서버에서 실제 수집된 데이터 기반이며, 운영 하네스로 사용한다.
참조 인덱스
| # | 섹션 | 핵심 내용 |
|---|---|---|
| 1 | 서버 기본 정보 | 호스트명, IP, OS, CPU/RAM/디스크, 타임존 |
| 2 | 접속 정보 | SSH 접속, 사용자, 인증 방식 |
| 3 | 소프트웨어 스택 | Python, .NET, PG, Nginx, Docker Compose, fail2ban |
| 3.1 | 런타임 | 버전/경로 일람 |
| 3.2 | Python 가상 환경 | ~/.venv, python3 사용 규칙 |
| 3.3 | 주요 Python 패키지 | 시스템/venv 패키지 구분 |
| 4 | 서비스 아키텍처 | 포트 맵, Nginx 리버스 프록시 |
| 4.1 | 포트 맵 | 22, 80, 443, 2222, 3000, 5000, 5001, 5432 |
| 4.2 | Nginx 리버스 프록시 | 도메인 가상 호스트 기반 분기 |
| 5 | Gitea | Docker Compose 설정, 시크릿, 데이터 경로 |
| 5.1 | Docker Compose | gitea:1.26.4, PG 연동 |
| 5.2 | 시크릿 관리 | /opt/stacks/gitea/.env |
| 5.3 | 데이터 | Gitea 볼륨, giteadb |
| 6 | Gitea Act Runner (CI) | 6× 러너, 네트워크, 구성 디렉토리 |
| 6.1 | 컨테이너 현황 | 러너 6개 실행 상태 |
| 6.2 | 러너 설정 | hz-prod-runner, gitea_default 네트워크 |
| 6.3 | 러너 구성 디렉토리 | ~/gitea-runner[-N]/ |
| 7 | QuantEngine Blazor Admin | systemd, symlink 배포, DLL 구성 |
| 7.1 | systemd 서비스 | quantengine.service 전문 |
| 7.2 | 배포 구조 | 타임스탬프 디렉토리 + symlink 교체 |
| 7.3 | 주요 DLL | Web, Core, Infrastructure, MudBlazor, Dapper |
| 8 | PostgreSQL 18 | v18.4, localhost 바인드, Docker 연동 |
| 9 | 보안 | SSH hardening, UFW, fail2ban, 네트워크 격리 |
| 9.1 | SSH 보안 설정 | 공개키 전용, root 차단 |
| 9.2 | UFW 방화벽 | ENABLED=yes, 포트 개방/차단 |
| 9.3 | fail2ban | SSH 브루트포스 방어 |
| 9.4 | Docker 네트워크 격리 | 로컬바인드 정책 |
| 10 | 디렉토리 맵 | /home/kjh2064/, /opt/stacks/, /opt/backups/ |
| 11 | 시놀로지 → 클라우드 마이그레이션 매핑 | 항목별 구↔신 비교표 |
| 12 | 운영 명령 치트시트 | 서비스 관리, 배포, 러너 등록, SSH |
| 13 | 검증 하네스 | 헬스체크, 엔드포인트, 마이그레이션 체크리스트 |
관련 문서 상호 참조
| 문서 | 역할 |
|---|---|
AGENTS.md |
운영 헌법, Directory Routing 인덱스 |
GITEA_SECRETS_SETUP.md |
Gitea 시크릿 설정/검증 가이드 |
ROADMAP_WBS.md |
.gs → Python 및 xlsx → sqlite WBS |
docs/GITEA_TOKEN_HOME_RUNBOOK.md |
Gitea 토큰 관리 런북 |
spec/00_execution_contract.yaml |
실행 계약 원본 권위 |
governance/agents_index.yaml |
거버넌스 규칙 인덱스 |
1. 서버 기본 정보
| 항목 | 값 |
|---|---|
| 호스트명 | hz-prod-01 |
| IP | 178.104.200.7 |
| OS | Ubuntu 26.04 LTS (Resolute Raccoon) |
| 커널 | 7.0.0-22-generic (x86_64, PREEMPT_DYNAMIC) |
| CPU | AMD EPYC-Rome, 2 vCPU |
| 메모리 | 3.7 GiB (사용 ~958 MiB, 가용 ~2.8 GiB) |
| 스왑 | 2.0 GiB |
| 디스크 | /dev/sda1 38 GB (사용 8.5 GB / 28 GB 가용, 24%) |
| 타임존 | Asia/Seoul (KST, +0900), NTP 동기화 활성 |
2. 접속 정보
| 항목 | 값 |
|---|---|
| SSH 접속 | ssh kjh2064@178.104.200.7 |
| SSH 포트 | 22 (기본) |
| 사용자 | kjh2064 (uid=1000) |
| 그룹 | kjh2064, sudo, users, docker |
| 인증 방식 | 공개키 전용 (PasswordAuthentication no) |
| Root 로그인 | 비활성 (PermitRootLogin no) |
| Max Auth Tries | 3 |
| Keep-Alive | ClientAliveInterval 300, ClientAliveCountMax 2 |
3. 소프트웨어 스택
3.1. 런타임
| 소프트웨어 | 버전 | 경로 |
|---|---|---|
| Python | 3.14.4 | /usr/bin/python3 |
| .NET SDK | 10.0.109 | /usr/lib/dotnet/sdk |
| .NET Runtime | ASP.NET Core 10.0.9 + NETCore 10.0.9 | /usr/lib/dotnet/shared/ |
| PostgreSQL | 18.4 | postgresql@18-main.service |
| Nginx | 시스템 패키지 | nginx.service |
| Docker Compose | v5.2.0 | Docker 플러그인 |
| fail2ban | 1.1.0 | fail2ban.service |
3.2. Python 가상 환경
경로: ~/.venv
Python: 3.14.4
주의: 이 서버에서는
python3을 사용한다 (시놀로지/Windows와 다름). CI 워크플로우와 로컬 서버 모두python3을 사용하므로 통일됨.
3.3. 주요 Python 패키지 (시스템)
boto3, cryptography, Jinja2, jsonschema, fail2ban 등 시스템 레벨로 설치됨.
프로젝트 의존성은 ~/.venv에 별도 관리.
4. 서비스 아키텍처
4.1. 포트 맵
| 포트 | 서비스 | 바인드 | 비고 |
|---|---|---|---|
| 22 | SSH | 0.0.0.0 |
공개키 전용 |
| 80 | Nginx (HTTP) | 0.0.0.0 |
443 HTTPS로 리다이렉트 |
| 443 | Nginx (HTTPS) | 0.0.0.0 |
SSL 가상 호스트 진입점 |
| 2222 | Gitea SSH | 0.0.0.0 |
Git SSH 접속 |
| 3000 | Gitea Web | 127.0.0.1 |
Nginx 프록시 경유 (gitea.taxbaik.com) |
| 5000 | QuantEngine Blazor | 127.0.0.1 |
Nginx 프록시 경유 (quant.taxbaik.com) |
| 5001 | TaxBaik 홈페이지 | 127.0.0.1 |
Nginx 프록시 경유 (taxbaik.com / www.taxbaik.com) |
| 5432 | PostgreSQL | 127.0.0.1 + 172.17.0.1 |
로컬 + Docker 네트워크 |
4.2. Nginx 리버스 프록시
도메인 기반 가상 호스트(Virtual Host) 방식을 사용하여 각 도메인 요청을 내부 서비스로 연결하고, SSL(HTTPS)을 필수로 적용합니다. HTTP(80) 포트 요청은 자동으로 HTTPS(443)로 리다이렉트됩니다.
상세 Nginx 설정 백업은 deploy/nginx-taxbaik-domains.conf에 위치합니다.
가상 호스트 설정 개요
- TaxBaik 홈페이지 (
https://taxbaik.com,https://www.taxbaik.com) ➜http://127.0.0.1:5001/taxbaik/ - Gitea (코드 저장소) (
https://gitea.taxbaik.com) ➜http://127.0.0.1:3000 - QuantEngine (Blazor Admin) (
https://quant.taxbaik.com) ➜http://127.0.0.1:5000/
라우팅 요약:
https://taxbaik.com&https://www.taxbaik.com➜ TaxBaik 홈페이지 (통합 앱)https://gitea.taxbaik.com➜ Gitea Web UIhttps://quant.taxbaik.com➜ QuantEngine Blazor Adminssh://git@gitea.taxbaik.com:2222➜ Gitea Git SSH
5. Gitea
5.1. Docker Compose
# /opt/stacks/gitea/docker-compose.yml
services:
gitea:
image: docker.gitea.com/gitea:1.26.4
container_name: gitea
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: host.docker.internal:5432
GITEA__database__NAME: giteadb
GITEA__database__USER: gitea
GITEA__database__PASSWD: "${GITEA_DB_PASSWORD}"
GITEA__server__DOMAIN: "${SERVER_IP}"
GITEA__server__ROOT_URL: "http://${SERVER_IP}/"
GITEA__server__SSH_DOMAIN: "${SERVER_IP}"
GITEA__server__SSH_PORT: "2222"
GITEA__security__INSTALL_LOCK: "true"
GITEA__service__DISABLE_REGISTRATION: "true"
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:3000:3000"
- "2222:22"
5.2. 시크릿 관리
.env파일:/opt/stacks/gitea/.env(소유자 전용,600)- 포함 변수:
GITEA_DB_PASSWORD,SERVER_IP
5.3. 데이터
- Gitea 데이터:
/opt/stacks/gitea/gitea/ - DB: PostgreSQL
giteadb(Docker → host.docker.internal:5432 경유)
6. Gitea Act Runner (CI)
6.1. 컨테이너 현황
| 이름 | 이미지 | 상태 |
|---|---|---|
gitea-runner |
gitea/act_runner:latest |
실행 중 |
gitea-runner-2 |
gitea/act_runner:latest |
실행 중 |
gitea-runner-3 |
gitea/act_runner:latest |
실행 중 |
hopeful_galileo |
gitea/act_runner:latest |
실행 중 |
jovial_bouman |
gitea/act_runner:latest |
실행 중 |
upbeat_chatelet |
gitea/act_runner:latest |
실행 중 |
총 6개 러너가 활성 상태. 네트워크는
gitea_defaultDocker 네트워크 사용.
6.4. CI / 배포 분리
.gitea/workflows/ci.yml: 검증 전용. 스펙/공식/리포트/아티팩트 생성까지만 수행한다..gitea/workflows/snapshot_admin_deploy.yml: 실배포 전용.dotnet publish후tools/deploy_quantengine.sh를 이용해/home/kjh2064/quantengine_active로 반영한다.- 수동 배포 금지: 로컬에서
scp/rsync로quantengine_active를 갱신하지 않는다. 배포는 CI가 원격에서만 수행하고, 로컬 스크립트는CI_DEPLOY=1없이 실행되면 실패해야 한다. - 공개 URL
/quant/갱신은snapshot_admin_deploy.yml의 성공 여부를 기준으로 판단한다.
6.2. 러너 설정
# ~/gitea-runner/config.yaml
container:
network: "gitea_default"
- 러너 이름:
hz-prod-runner - 러너 UUID:
d6d9120b-5070-4874-88d7-b86fe817d5a0 - 러너 이미지:
docker.gitea.com/runner-images:ubuntu-latest(2.33 GB)
6.3. 러너 구성 디렉토리
~/gitea-runner/ # 1번 러너
~/gitea-runner-2/ # 2번 러너
~/gitea-runner-3/ # 3번 러너
7. QuantEngine Blazor Admin
7.1. systemd 서비스
# /etc/systemd/system/quantengine.service
[Unit]
Description=Quant Engine Blazor Admin Web App (.NET 10)
After=network.target
[Service]
WorkingDirectory=/home/kjh2064/quantengine_active
ExecStart=/usr/bin/dotnet /home/kjh2064/quantengine_active/QuantEngine.Web.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=quantengine
User=kjh2064
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://127.0.0.1:5000
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
7.2. 배포 구조
~/quantengine_active → ~/deployments/quantengine_20260625_182821 (symlink)
~/deployments/
├── quantengine_20260625_155649/
├── quantengine_20260625_164548/
├── quantengine_20260625_164928/
└── quantengine_20260625_182821/ ← 현재 활성
배포 방식: 타임스탬프 디렉토리 생성 → symlink 교체 → systemctl restart quantengine
7.3. 주요 DLL
QuantEngine.Web.dll— 웹 진입점QuantEngine.Core.dll— 핵심 도메인QuantEngine.Application.dll— 애플리케이션 서비스QuantEngine.Infrastructure.dll— 인프라 (DB, 외부 연동)Npgsql.dll— PostgreSQL 드라이버MudBlazor.dll— UI 컴포넌트Dapper.dll— 마이크로 ORM
8. PostgreSQL 18
| 항목 | 값 |
|---|---|
| 버전 | 18.4 (Ubuntu 패키지) |
| 서비스 | postgresql@18-main.service |
| listen_addresses | localhost (기본값, 로컬 전용) |
| 바인드 | 127.0.0.1:5432, 172.17.0.1:5432 (Docker), [::1]:5432 |
| Gitea DB | giteadb (사용자: gitea) |
Docker 컨테이너는
host.docker.internal:5432로 호스트 PG에 접속.listen_addresses는postgresql.conf에서 기본값localhost로 설정됨 (외부 접속 차단).
9. 보안
9.1. SSH 보안 설정
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
9.2. UFW 방화벽
- 상태:
ENABLED=yes(/etc/ufw/ufw.conf) - 로그 레벨:
low - 외부 개방 포트: 22 (SSH), 80 (HTTP), 443 (HTTPS), 2222 (Gitea SSH)
- 내부 전용: 3000 (Gitea Web), 5000 (QuantEngine), 5001 (TaxBaik Web), 5432 (PostgreSQL)
상세 규칙 확인:
sudo ufw status numbered(TTY + sudo 비밀번호 필요)
9.3. fail2ban
fail2ban.service활성 상태- SSH 브루트포스 방어 활성
9.4. Docker 네트워크 격리
- Gitea Web:
127.0.0.1:3000(로컬 전용) - QuantEngine:
127.0.0.1:5000(로컬 전용) - TaxBaik Web:
127.0.0.1:5001(로컬 전용) - PostgreSQL:
127.0.0.1+ Docker bridge (172.17.0.1) - 외부 노출: SSH(22), HTTP(80), HTTPS(443), Gitea SSH(2222)만 개방
10. 디렉토리 맵
/home/kjh2064/
├── quantengine_active → deployments/quantengine_YYYYMMDD_HHMMSS (symlink)
├── deployments/ # QuantEngine 배포 히스토리
│ └── quantengine_YYYYMMDD_HHMMSS/
│ └── wwwroot/
├── gitea-runner/ # Gitea Act Runner 1
├── gitea-runner-2/ # Gitea Act Runner 2
├── gitea-runner-3/ # Gitea Act Runner 3
├── apps/ # 추가 앱
│ └── python-test/.venv/
├── .venv/ # Python 3.14 가상 환경
├── tmp/ # 임시 작업
└── .ssh/ # SSH 키
/opt/stacks/
├── gitea/
│ ├── docker-compose.yml
│ ├── .env # GITEA_DB_PASSWORD, SERVER_IP
│ └── gitea/ # Gitea 데이터 볼륨
└── dotnet-app/ # .NET 관련
/opt/backups/ # 백업
11. 시놀로지 → 클라우드 마이그레이션 매핑
| 항목 | 시놀로지 (구) | 클라우드 (신) |
|---|---|---|
| 프로젝트 경로 | /volume1/projects/data_feed |
미배치 (TBD) |
| Python | python3 (시스템) |
python3 (/usr/bin/python3, 3.14.4) |
| Gitea | Docker on DSM | Docker on Ubuntu (gitea:1.26.4) |
| Gitea SSH | 포트 변동 | 2222 고정 |
| CI Runner | Synology Act Runner | 6× act_runner:latest (Docker) |
| DB | SQLite (파일 기반) | PostgreSQL 18 + SQLite (하이브리드) |
| 웹 Admin | 없음 | QuantEngine Blazor (.NET 10, MudBlazor) |
| 리버스 프록시 | Synology 내장 | Nginx 도메인 가상 호스트 및 SSL (HTTPS) 적용 (deploy/nginx-taxbaik-domains.conf) |
| 보안 | DSM 방화벽 | fail2ban + SSH 공개키 + 서비스 로컬바인드 |
| 시크릿 관리 | .secrets/kis_real.env |
/opt/stacks/gitea/.env |
| OS | Synology DSM 7.x | Ubuntu 26.04 LTS |
| 타임존 | (설정 의존) | Asia/Seoul (NTP 동기화) |
12. 운영 명령 치트시트
서비스 관리
# QuantEngine
sudo systemctl status quantengine
sudo systemctl restart quantengine
sudo journalctl -u quantengine -f
# Gitea
cd /opt/stacks/gitea && docker compose up -d
docker compose logs -f gitea
# Nginx
sudo systemctl reload nginx
sudo nginx -t
# PostgreSQL
sudo systemctl status postgresql@18-main
sudo -u postgres psql
# Docker 전체 상태
docker ps -a
QuantEngine 배포
# CI에서만 배포
# 로컬에서 scp/rsync로 quantengine_active를 갱신하지 않는다.
# 배포는 .gitea/workflows/snapshot_admin_deploy.yml 실행 결과로만 반영한다.
Gitea Act Runner 등록
# 새 러너 등록 (Gitea 웹 → Settings → Actions → Runners에서 토큰 복사)
docker run -d \
--name gitea-runner-N \
--restart unless-stopped \
--network gitea_default \
-v /var/run/docker.sock:/var/run/docker.sock \
gitea/act_runner:latest
SSH 접속 및 Git 원격 설정
# Windows 로컬에서 서버 SSH 접속
ssh kjh2064@178.104.200.7
# 로컬 프로젝트의 Git Remote URL 변경 (Gitea 도메인 기반 HTTPS 적용)
# 1) 현재 설정된 remote url 확인
git remote -v
# 2) 새로운 도메인 주소로 원격 URL 변경
git remote set-url origin https://gitea.taxbaik.com/kjh2064/QuantEngineByItz.git
# Gitea Git SSH 접속 (기존 2222 포트 유지)
git remote set-url origin ssh://git@gitea.taxbaik.com:2222/kjh2064/QuantEngineByItz.git
13. 검증 하네스
13.1. 서버 헬스 체크
ssh kjh2064@178.104.200.7 "
echo '=== Services ==='
systemctl is-active quantengine nginx docker postgresql@18-main fail2ban
echo '=== Docker ==='
docker ps --format '{{.Names}}: {{.Status}}'
echo '=== Disk ==='
df -h /
echo '=== Memory ==='
free -h | head -2
"
기대 결과:
- 5개 서비스 모두
active - Docker 컨테이너 7개 (gitea + runner ×6)
Up - 디스크 사용률 < 80%
- 메모리 가용 > 1 GiB
13.2. 엔드포인트 접근 확인
# Gitea Web
curl -s -o /dev/null -w "%{http_code}" http://178.104.200.7/
# 기대: 200
# QuantEngine
curl -s -o /dev/null -w "%{http_code}" http://178.104.200.7/quant/
# 기대: 200
# Gitea SSH
ssh -T -p 2222 git@178.104.200.7 2>&1 | head -1
# 기대: "Hi there, ..." Gitea 응답
13.3. data_feed 프로젝트 마이그레이션 체크리스트
- 프로젝트 경로 결정 및 clone
- Python venv에 프로젝트 의존성 설치 (
pip install -r requirements.txt) - KIS 시크릿 설정 (
~/.secrets/kis_real.env) - crontab 또는 systemd timer 등록
GatherTradingData.json동기화 경로 확정- SQLite canonical DB 경로 확정
- CI 워크플로우 러너 라벨 확인
- GAS 배포 스크립트 서버 경로 업데이트
14. 트러블슈팅 (Troubleshooting)
14.1. Certbot / APT 패키지 설치 시 Microsoft 리포지토리 404 오류
- 증상:
sudo apt-get update실행 시 Microsoft 패키지 저장소에서404 Not Found에러가 발생하며 패키지 목록 갱신이 중단되고, 이로 인해certbot설치가sudo: certbot: command not found에러로 실패하는 현상. - 원인: Ubuntu 26.04 (Resolute) 환경에서 Microsoft의 잘못된 리포지토리(26.04 경로에 focal/20.04 릴리스가 설정된 상태)를 참조하여 발생.
- 해결 방안:
- 문제가 되는 Microsoft apt 소스 설정 파일을 삭제하거나 비활성화합니다.
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - APT 패키지 목록을 다시 업데이트하고 Certbot 및 Nginx 플러그인을 설치합니다.
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx - 인증서 발급 및 설정을 적용합니다.
sudo certbot --nginx -d taxbaik.com -d www.taxbaik.com -d gitea.taxbaik.com -d quant.taxbaik.com --register-unsafely-without-email --agree-tos --non-interactive
- 문제가 되는 Microsoft apt 소스 설정 파일을 삭제하거나 비활성화합니다.
수집 일시: 2026-06-26 09:55 KST (추가 업데이트: 2026-07-01) 수집 방법:
ssh kjh2064@178.104.200.7라이브 명령 및 트러블슈팅 사례 수집 provenance: 모든 값은 서버 실시간 명령 출력 및 실제 오류 대처 조치 로그에서 추출. 임의 값 없음.