# 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. 로그인 정보 출력 ## 실행 방법 ```bash # 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 스토리지 등록 (자동) ```bash 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 인증 + 백업 목록 조회 (자동) ```bash # 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 복원 실행 (자동) ```bash # 최신 스냅샷 자동 선택 qmrestore "PBS-Auto:backup/vm/$TEMPLATE_VMID/$LATEST_SNAPSHOT" $TARGET_VMID \ --storage local-lvm --unique 1 ``` #### 4-5. Windows VM 시작 (자동) ```bash qm start $TARGET_VMID sleep 30 # Windows 부팅 대기 ``` - VM의 LAN IP → `$MSSQL_SERVER` 로 사용 (기본 `192.168.0.201\PM2014`) ### Phase 5: Ubuntu CT 생성 (자동, ~2분) #### 5-1. 템플릿 준비 ```bash 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 생성 ```bash 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 필수) ```bash 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 시작 ```bash pct start $CT_VMID sleep 5 # 부팅 대기 ``` ### Phase 6: CT 내부 환경 구축 (자동, ~3분) 모든 명령은 `pct exec $CT_VMID -- bash -c '...'`로 실행 #### 6-1. 기본 패키지 ```bash 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 아님!) ```bash 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 등록 ```bash 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 서버 코드 클론 + 설치 ```bash 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 파일 생성 ```bash 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 서비스 등록 ```bash 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 장비로) ```bash 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 ```bash 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 — 관리자 계정 생성 ```bash 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//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 ```