8.3 KB · 수정 2026-09-21 10:50
목차

2026-09-21(월) — 아트조이 AI PC devplan 8080 상시운용 마감 + 포트 감시기 신설

[페페 지시] 「AI PC(100.122.89.28) devplan 8080 을 상시 운용으로 마감하라」. 전제(26.9.21 오전, 같은 날 앞 세션) = tailscale serve → netsh portproxy 0.0.0.0:8080 → 127.0.0.1:8799 교체 완료. 이 세션이 한 일 = ①재부팅 없이 부팅 지속 조건 검증 ②감시기 신설 ③유지보수 보호 ④공개범위 불변 확인.

1. 부팅 지속 — 실측한 것 (재부팅 안 함)

항목 실측값 재부팅 후 살아나나
portproxy HKLM\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4\tcp 에 0.0.0.0/8080 = 127.0.0.1/8799 ✅ 레지스트리 영속 + iphlpsvc Automatic·Running
방화벽 Cody-Devplan-8080 PersistentStore · Enabled · Inbound · Allow · TCP 8080 · remote 100.64.0.0/255.192.0.0 ✅ 정책 저장소라 부팅 시 ActiveStore 로 로드
devplan 서버 \Cody\DevplanServer = wscript C:\cody\devplan_server.vbs · SYSTEM · 부팅 트리거 + 5분 반복 · 배터리/네트워크/유휴 조건 없음 · StartWhenAvailable=True · MultipleInstances=IgnoreNew · 마지막 rc=0 ✅
테일스케일 서비스 Automatic·Running · BackendState=Running ✅
전원 구성표 고성능 · AC 대기모드 0(안 잠든다) · 가동시간 18시간 ✅
실행 파일 C:\Python312\pythonw.exe·C:\cody\serve_devplan.py 둘 다 존재 ✅

재부팅 대신 한 실측 2건(둘 다 통과) - ⓐ portproxy 재바인드 — 행을 delete 하니 8080 리스너가 사라지고(0), add 하니 svchost(iphlpsvc) pid 3928 이 0.0.0.0:8080 을 0.7초 만에 다시 잡았다. 로컬 http://127.0.0.1:8080/devplan/ 200. → 8080 을 선점하는 프로세스가 없고, 부팅 경로에서 바인드가 실패할 구조적 이유가 없다는 뜻. - ⓑ 서버 되살리기 — 8799 pythonw(pid 8832)를 죽이고 schtasks /run "\Cody\DevplanServer" → 1초 만에 새 pid 17724 로 부활, HTTP 200 복귀.

⛒iphlpsvc 재시작(= 가장 완전한 부팅 시뮬레이션)은 일부러 안 했다. Tailscale 서비스가 iphlpsvc 에 의존한다((Get-Service iphlpsvc).DependentServices = Tailscale, NcaSvc). 재시작하면 테일스케일이 내려가고 ssh·AnyDesk 가 전부 테일넷 위에 있어 원격 경로가 통째로 끊긴다. 다시 안 올라오면 아트조이 사무실에서 사람이 손대야 한다 — 얻을 정보보다 잃을 위험이 크다. 게다가 코덱스가 짚은 대표 실패조건(「listenaddress 를 특정 IP 로 주면 부팅 때 그 주소보다 iphlpsvc 가 먼저 떠서 바인드를 놓친다」)은 우리가 0.0.0.0 을 쓰므로 해당이 없다. IPv6 DisabledComponents=142 도 native IPv6(0x10) 는 안 끈 값이라 v4tov4 에 영향 없다(현재 정상 동작이 증거).

2. 🔴 덤으로 잡은 사실 — 8080 을 여는 건 우리 규칙이 아니다

방화벽 규칙 Cody-Devplan-8080 을 삭제했는데 접속이 그대로 200 이었다. 전수조사(인바운드·Enabled·Allow·TCP/Any·8080 또는 Any 포트·프로그램/패키지 미지정) 결과 남는 건 Tailscale-In 둘뿐:

Tailscale-In | remote=Any | local=100.122.89.28
Tailscale-In | remote=Any | local=fd7a:115c:a1e0::a73a:591d

Tailscale-In 은 포트가 Any 지만 LocalAddress 가 테일넷 주소로 묶여 있어 테일넷으로 들어온 트래픽만 매칭된다. → 공개 범위는 변함없이 테일넷 전용(LAN 192.168.1.x·공인 인바운드는 기본 차단 그대로). 우리 규칙은 이중잠금이었다. ⛒결론 = 「HTTP 200 이면 방화벽도 정상」은 거짓. 감시기는 방화벽을 가용성과 분리해서 매 주기 따로 본다.

3. 감시기 — \Cody\artjoy-devplan-watch (미니PC, 5분)

무엇 값
본체 C:\dev\tools\artjoy-ai-setup\devplan_watch.py
진입점 C:\dev\tools\artjoy-ai-setup\_devplan_watch_hidden.vbs(wscript 숨김 · 창 0)
원격 프로브 C:\cody\devplan_probe.ps1(AI PC · 읽기 전용 · ASCII 전용)
예약작업 \Cody\artjoy-devplan-watch · delix Interactive · 5분 반복 · IgnoreNew · 실행시간 제한 4분
로그 C:\_work\artjoy-dev\devplan_watch.log(1MB 회전) · 마지막 1회분 devplan_watch_task.log
상태 C:\_work\artjoy-dev\devplan_watch_state.json

왜 미니PC에서 도나 — 검증해야 할 질문은 「조수은 PC 브라우저가 실제로 열리나」다. AI PC 안에서 자기 포트를 찌르면 테일넷을 타지 않아 그 질문의 답이 안 된다.

점검 5종 = ①http://100.122.89.28:8080/devplan 200 + 본문 마커(data-artjoy-page="devplan" — 200만 보면 엉뚱한 서버도 통과한다) ②8799 리슨 ③portproxy 행(레지스트리로 읽는다) ④방화벽 범위 ⑤테일스케일 BackendState.

복구 — 허용 6개뿐(사전 밖 명령은 실행 자체가 안 된다): server(=schtasks /run \Cody\DevplanServer) · portproxy(행 add) · rebind(행 delete+add) · fw_create · fw_enable · fw_narrow. 알림만 하고 손대지 않는 것 = ssh 불통(전원·테일스케일) · iphlpsvc 정지 · portproxy 행이 «다른 형태» · 방화벽 규칙 중복 · 테일넷 밖으로 열린 남의 규칙 · 8799 는 살아 있는데 HTTP 가 안 오는 hang.

🔴 절대 금지 — 재부팅·shutdown·강제 로그오프·프로세스 강제종료. selftest 가 소스 전체를 정규식(shutdown|Restart-Computer|Stop-Computer|logoff|Restart-Service|taskkill|Stop-Process)으로 훑어 한 줄이라도 있으면 실패한다.

시끄러움 제어 = 1회 실패는 무음(유예) → 2회 연속부터 복구 · 복구는 10분에 1번·사건당 3번까지(넘으면 gave_up = 자동복구 중단, 하루 1번만 상기) · 알림은 사건당 1회(6시간마다 리마인더) · 복귀는 정상 2회 연속이어야 인정(플래핑 방지) · 정상이면 완전 무음.

4. 유지보수 보호

python C:\dev\tools\artjoy-ai-setup\devplan_watch.py maint 30 "8799 서버 교체"   # 최대 180분
python C:\dev\tools\artjoy-ai-setup\devplan_watch.py maint off                  # 풀면 10분 유예

표식 = AI PC C:\cody\MAINTENANCE.json(until·who·why). 살아 있는 동안 복구도 알림도 0. - 고아(만료시각 지남·JSON 깨짐) → 재부팅 따위로 확대하지 않고 MAINTENANCE.expired.json 으로 이름만 바꾸고(지우지 않는다 — 무엇이 있었는지 남아야 사람이 판단한다) 알림 1회 + 10분 유예 후 감시 재개. - ssh 불통이면 표식은 «없음»이 아니라 «불명» → 직전 주기가 유지보수였으면 그대로 유지보수로 본다(복구 금지). - 표식을 걸면 진행 중이던 사건도 접는다(해제 후 0부터 다시 센다).

5. 시험 결과 — 전부 실측

시나리오 기대 결과
자체검사 selftest 통과 ✅ (금지명령 스캔 · 표식 5케이스 · portproxy 4케이스 · 방화벽 9케이스 · 상태기계 전이)
정상 무음 ✅ 로그만 정상. http=200
유지보수 중 portproxy 삭제 복구 0 · 알림 0 ✅ 2주기 돌렸는데 행이 그대로 없었다
유지보수 해제 직후 10분 유예 ✅ 유예/1회실패 — 조용히 넘긴다
1회 실패 무음 ✅
2회 연속 실패(portproxy 없음) 자동복구 + 알림 ✅ 복구 portproxy rc=0 → 200 복귀 → 「🔧 자동복구」
방화벽 규칙 삭제(HTTP 는 정상) 가용성과 별개로 잡아서 재생성 ✅ 「⚠ 공개범위 드리프트」 + fw_create rc=0 · 범위 100.64.0.0/10 그대로
고아 표식(만료시각 과거) 만료 처리 + 알림 1회 ✅ .expired 로 rename
예약작업 실전 숨김 실행 · rc=0 · 무음 ✅ 창 0 · 39초

6. 운영 데이터·공개 범위

무변경. 8799 서버 프로세스는 시험 중 1회 재기동(kill→task)했고 DB·파일은 건드리지 않았다. 포트포워딩 추가 0 · Funnel 0 · tailscale serve 추가 0 · 방화벽은 삭제→동일 범위로 재생성(최종 상태 = 시작과 같다).