Files
pve9-repo-fix/UNIFIED_INSTALL_DESIGN.md
Claude d0cd2b1137 Add unified PharmQ PVE setup script + design doc
Single script that handles: PVE repo fix, Tailscale/Headscale VPN registration,
PBS Windows VM restore, Ubuntu CT creation with API environment,
pharmacy + device registration in farmq.db, and gateway account creation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:31:05 +00:00

10 KiB

PharmQ PVE 원클릭 통합 설치 스크립트 설계

목표

PVE host 1대에서 스크립트 1번 실행으로 모든 것을 완료:

  1. PVE 구독 리포 수정 (no-subscription)
  2. PVE host에 Tailscale 설치 + Headscale 등록
  3. PBS 등록 + Windows VM(팜IT3000) 복원
  4. Ubuntu CT 자동 생성 (API 서버용)
  5. CT 내부에 Tailscale 설치 + Headscale 등록 + API 환경 구축
  6. farmq.db에 약국 + 장비 2개 등록
  7. gateway.db에 관리자 계정 생성
  8. 로그인 정보 출력

실행 방법

# PVE host의 shell에서 실행
curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/pharmq-setup.sh | bash

Phase 구조 (총 8단계)

Phase 1: PVE Repository Fix (자동, ~30초)

  • proxmox-archive-keyring 확인
  • no-subscription 리포 설정 (deb822)
  • enterprise 리포 비활성화
  • apt-get update

Phase 2: PVE Host Tailscale 등록 (자동, ~20초)

  • Tailscale 패키지 설치 (이미 있으면 스킵)
  • tailscaled 서비스 시작
  • tailscale up --login-server=http://head.pharmq.kr --authkey=... --hostname=PXXXX-pve-pharmq
  • PVE host VPN IP 획득 → $PVE_VPN_IP
  • 주의: hostname은 Phase 3에서 약국 코드 확정 후 tailscale set --hostname=...으로 변경

Phase 3: 약국 정보 수집 (대화형, 사용자 입력)

  • 약국명 (필수)
  • 요양기관부호 (선택)
  • 주소, 약국장, 연락처 (선택)
  • MSSQL 서버 IP (기본: 192.168.0.201\PM2014 — Windows VM 복원 후 변경될 수 있음)

참고: curl | bash 파이프 실행 시 read/dev/tty에서 읽음

Phase 4: PBS 등록 + Windows VM 복원 (반자동, ~5분)

PBS에서 팜IT3000 Windows VM을 복원하는 단계.

4-1. PBS 스토리지 등록 (자동)

pvesm add pbs "PBS-Auto" \
  --server "100.64.0.10" \
  --port "8007" \
  --datastore "PBS-DVA" \
  --username "0bin@pbs" \
  --password "@Trajet6640" \
  --fingerprint "24:42:c6:..." \
  --namespace "PQ"
  • 이미 등록돼있으면 스킵

4-2. PBS API 인증 + 백업 목록 조회 (자동)

# PBS API 로그인 → ticket 획득
# GET /api2/json/admin/datastore/PBS-DVA/groups?ns=PQ
# VM 백업 목록 표시

4-3. 복원할 VM 선택 (사용자 입력)

=== VM 백업 ===
  1. VM 100   - 3개 백업 (최근: 2026-04-05 14:00)
     └─ 팜IT3000 Windows Server 템플릿
  2. VM 200   - 2개 백업 (최근: 2026-04-03 10:00)
     └─ 기본 Windows 10

복원할 VM 번호: 1
복원 VMID [기본: 200]: 200
저장 스토리지 [기본: local-lvm]: local-lvm

4-4. VM 복원 실행 (자동)

# 최신 스냅샷 자동 선택
qmrestore "PBS-Auto:backup/vm/$TEMPLATE_VMID/$LATEST_SNAPSHOT" $TARGET_VMID \
  --storage local-lvm --unique 1

4-5. Windows VM 시작 (자동)

qm start $TARGET_VMID
sleep 30  # Windows 부팅 대기
  • VM의 LAN IP → $MSSQL_SERVER 로 사용 (기본 192.168.0.201\PM2014)

Phase 5: Ubuntu CT 생성 (자동, ~2분)

5-1. 템플릿 준비

pveam update
pveam download local ubuntu-24.04-standard_24.04-2_amd64.tar.zst
# 이미 있으면 스킵

5-2. VMID 자동 선택

  • 200~299 범위에서 사용 가능한 VMID 자동 탐색 (VM과 겹치지 않게)
  • pct list + qm list로 기존 VM/CT 확인

5-3. LAN IP 자동 선택

  • 192.168.0.100~199 범위에서 사용 가능한 IP 탐색
  • ping -c1 -W1로 충돌 확인

5-4. CT 생성

pct create $CT_VMID local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname ubuntu-api \
  --cores 4 --memory 8192 \
  --rootfs local-lvm:30 \
  --net0 name=eth0,bridge=vmbr0,ip=192.168.0.$X/24,gw=192.168.0.1 \
  --nameserver 8.8.8.8 \
  --password 'trajet6640' \
  --unprivileged 1 \
  --features nesting=1

5-5. TUN 디바이스 설정 (Tailscale 필수)

echo 'lxc.cgroup2.devices.allow: c 10:200 rwm' >> /etc/pve/lxc/$CT_VMID.conf
echo 'lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file' >> /etc/pve/lxc/$CT_VMID.conf

5-6. CT 시작

pct start $CT_VMID
sleep 5  # 부팅 대기

Phase 6: CT 내부 환경 구축 (자동, ~3분)

모든 명령은 pct exec $CT_VMID -- bash -c '...'로 실행

6-1. 기본 패키지

apt-get update
apt-get install -y curl git python3-pip python3-dev python3-venv \
  pkg-config unixodbc unixodbc-dev build-essential

6-2. Microsoft ODBC Driver 18 (FreeTDS 아님!)

curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/24.04/prod noble main" > /etc/apt/sources.list.d/mssql-release.list
apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql18
# tdsodbc 절대 설치하지 않음 — named instance 접속 불가

6-3. Tailscale 설치 + Headscale 등록

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list
apt-get update && apt-get install -y tailscale
systemctl enable --now tailscaled
sleep 3
tailscale up --login-server=http://head.pharmq.kr \
  --authkey=$PREAUTH_KEY \
  --hostname=$PHARMACY_CODE-ubuntu-api \
  --accept-routes --accept-dns=false
  • CT VPN IP 획득 → $CT_VPN_IP

6-4. API 서버 코드 클론 + 설치

git clone https://git.0bin.in/thug0bin/person-lookup-web.git /srv/person-lookup-web-local
cd /srv/person-lookup-web-local
pip3 install -r requirements.txt --break-system-packages
# 추가 누락 패키지 (P0019 freeze 기준)
pip3 install brother_ql pytz qrcode netifaces pydantic anthropic httpx PyYAML rich --break-system-packages

6-5. .env 파일 생성

cat > /srv/person-lookup-web-local/.env << EOF
MSSQL_SERVER=$MSSQL_SERVER
MSSQL_USER=sa
MSSQL_PASSWORD=tmddls214!%(
PHARMACY_CODE=$PHARMACY_CODE
EOF

6-6. systemd 서비스 등록

cat > /etc/systemd/system/pharmq-api.service << EOF
[Unit]
Description=PharmQ API Server
After=network.target

[Service]
Type=simple
WorkingDirectory=/srv/person-lookup-web-local
ExecStart=/usr/bin/python3 app.py
Restart=always
RestartSec=5
Environment=FLASK_ENV=production

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now pharmq-api

Phase 7: 약국 + 장비 등록 (자동, ~5초)

7-1. farmq.db — 약국 생성 (CT를 primary 장비로)

curl -s -X POST https://demo.pharmq.kr/api/pharmacy \
  -H "Content-Type: application/json" \
  -d '{
    "pharmacy_name": "$PHARMACY_NAME",
    "vpn_ip": "$CT_VPN_IP",
    "device_type": "linux_server",
    "device_name": "$PHARMACY_CODE-ubuntu-api",
    "hostname": "ubuntu-api",
    "hira_code": "$HIRA_CODE",
    "address": "$ADDRESS",
    "owner_name": "$OWNER_NAME",
    "phone": "$PHONE",
    "api_port": 8082
  }'
# → pharmacy_code 응답 (P0022 등)

7-2. farmq.db — PVE host 장비 추가 등록 NEW API

curl -s -X POST https://demo.pharmq.kr/api/pharmacy/$PHARMACY_CODE/device \
  -H "Content-Type: application/json" \
  -d '{
    "tailscale_ip": "$PVE_VPN_IP",
    "device_name": "$PHARMACY_CODE-pve-pharmq",
    "device_type": "proxmox_host",
    "device_role": "main_server",
    "hostname": "$PVE_HOSTNAME",
    "is_primary": false
  }'

7-3. gateway.db — 관리자 계정 생성

curl -s -X POST https://gateway.pharmq.kr/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "username": "$PHARMACY_CODE_LOWER",
    "email": "$PHARMACY_CODE_LOWER@pharmq.internal",
    "password": "12341234",
    "name": "$PHARMACY_NAME 관리자",
    "phone": "$PHONE",
    "primary_pharmacy_code": "$PHARMACY_CODE",
    "role": "admin"
  }'

Phase 8: 검증 + 결과 출력 (자동, ~10초)

  1. CT API 서버 헬스체크: curl http://$CT_VPN_IP:8082/api/status
  2. Windows VM 상태 확인: qm status $VM_VMID
  3. PVE → CT 네트워크 확인: ping -c3 $CT_VPN_IP
  4. 최종 결과 출력:
============================================
  PharmQ 원클릭 설치 완료!
============================================

약국 코드:    P0022
약국명:       OO약국

[Windows VM - 팜IT3000]
  VMID:       200
  MSSQL:      192.168.0.201\PM2014

[PVE Host]
  VPN IP:     100.64.0.XX
  hostname:   P0022-pve-pharmq

[Ubuntu API CT]
  VPN IP:     100.64.0.YY
  hostname:   P0022-ubuntu-api
  CT VMID:    204
  LAN IP:     192.168.0.103
  API:        http://100.64.0.YY:8082

로그인 정보:
  URL:        https://pharmq.kr
  ID:         p0022
  PW:         12341234

⚠ 최초 로그인 후 비밀번호를 변경하세요!
============================================

주의사항

  1. ODBC Driver: FreeTDS(tdsodbc) 절대 설치 금지. MSSQL named instance 접속 불가
  2. Preauth Key: 현재 키 b4692... 만료일 2026-09-22 (충분)
  3. CT VMID: 200~299 자동 탐색, VM과 겹치지 않게
  4. DNS: CT에 --nameserver 8.8.8.8 필수 (Headscale DNS만 쓰면 apt 불가)
  5. TUN 디바이스: CT 생성 후 start 전에 설정 필수
  6. 중복 실행: 같은 PVE에서 다시 돌리면 새 약국 코드 생성됨 (기존 것 덮어쓰지 않음)
  7. PBS 접근: VPN 연결 후에만 PBS(100.64.0.10) 접근 가능 → Phase 2 이후 실행

API 엔드포인트 (완료)

엔드포인트 용도 상태
POST /api/pharmacy 약국 생성 + 1번째 장비 등록 기존
POST /api/pharmacy/<code>/device 추가 장비 등록 신규 추가
POST /api/auth/register 관리자 계정 생성 기존 (gateway)

PBS 설정 (하드코딩)

항목
PBS 서버 100.64.0.10:8007
사용자 0bin@pbs
비밀번호 @Trajet6640
데이터스토어 PBS-DVA
네임스페이스 PQ
Fingerprint 24:42:c6:0f:a8:...

파일 구조

pve9-repo-fix/
├── pharmq-setup.sh            ← 통합 스크립트 (메인)
├── fix-pve9-repos.sh          ← 기존 Phase 1 (참고용, 통합에 흡수)
├── headscale-auto-register.sh ← 기존 (참고용, 통합에 흡수)
├── pbs_allinone.sh            ← 기존 PBS (참고용, Phase 4에 흡수)
├── UNIFIED_INSTALL_DESIGN.md  ← 이 문서
└── README.md