# 0.1.1 실제 환경 배포·검증 기록 (ariweb.net 호스트, 2026-10-26) 생성: 2026-10-26T14:33:19.592Z · 검증기 `real-env-check.mjs`(서버에서 실행, 실제 HAL·포털·Node Agent·Webmaker·AriMail 대상) · 배포 기준 main `3951be5` ## 상태 요약 - 배포: HAL 부트스트랩(`deploy/bootstrap-hal.sh`) → 첫 운영자 → 첫 Node Agent(역할 control, 승인 → 부트스트랩 완료·수동 설치 잠김) → `link-portal` → HAL 작업으로 portal → webmaker → arimail 배포, 이후 수정 artifact 를 같은 릴리스 0.1.1 로 재등록해 HAL 작업으로 agent·hal·portal 갱신. 모든 모듈의 실제 버전 0.1.1·건강 ok(아래 재검증). - 공개 DNS: `hal.ariweb.net`·`my.ariweb.net` A 레코드는 아직 없다(이번 작업은 공개 DNS 를 바꾸지 않았다). 서버 `/etc/hosts` 임시 항목으로 같은 서버 안 통신만 확인했고, 외부 주소 접속(흐름 8 등)은 레코드 생성 뒤 확인한다. - 실제 외부 발신 1건: 포털 mailer(Resend, `no-reply@ariweb.net`)로 `icqmomo@gmail.com` 에 확인 메일 발송 — Resend 수락 id `01a17899-8c6e-7574-b85b-3c1015fe94b5`(14:24 UTC). 수신함 도착은 사람이 확인한다. - 흐름 판정(34개): 실제 확인 7 · 부분 확인 7 · 미수행 20 · 실패 0. **0.1.1 출시 완료는 선언하지 않는다** — 지시서 기준(최종 화면·외부 접속·실제 메일 왕복·실제 사용량·실제 배포 버전) 중 외부 접속·메일 왕복·Webmaker 페이지 제작이 남아 있다. ## 사람이 해야 남는 일 1. hosting.co.kr 패널에 `hal.ariweb.net`·`my.ariweb.net` A 레코드(187.53.133.173) 생성 → 흐름 8·외부 접속 확인. 2. 메일 왕복 검증용 수신 주소(자동 응답 메일함) 설정(`PUT /internal/ops/mail/policy {verifier}`) → 흐름 11. 3. Webmaker 제작 화면에서 검증 사이트의 페이지를 만들어 저장 → 흐름 5·6·13·14 의 나머지(관리형 배포·백업 실행·복원·외부 확인). ## 배포 경과와 발견한 결함(모두 코드로 수정해 main 에 반영, VERSION_HISTORY "실제 환경 배포에서 발견한 결함 수정") 1. 부트스트랩 4단계 중단 — `/etc/letsencrypt/live` 는 root 전용이라 일반 계정의 인증서 존재 확인이 거짓 → `sudo -n test -f`. 2. 포털 artifact 에 상품정책 시드(`catalog/`) 누락 → 릴리스 빌더 경로 추가. 3. AriMail 은 다른 계정(arihakdang)으로 운영 → Agent 실행 계정 모드(`deploy/module-as-user.sh`, sudoers 최소 규칙). 내려받은 artifact 0600·현재 경로 심링크·umask 077 로 만들어진 0700 디렉터리(릴리스 빌더 모드 정규화) 등 권한 문제 4건. 4. AriMail 마이그레이션이 `DB_FILE` 없이 릴리스 디렉터리에 빈 DB 를 만들 뻔함 → 유닛 EnvironmentFile 을 실행 계정으로 읽어 실행(공백 값 파싱 포함). 사후 절차 실패 시 current 되돌리기. 5. 도입 모듈 실제 버전이 상류 버전(1.7.3·1.0.11)으로 보고돼 HAL 판정·drift 표시 오류 → REVISION.json 의 Suite 버전 사용(설치 결과·heartbeat 모두). 6. Webmaker 운영 유닛의 강화 지시문이 템플릿에 지워질 뻔함 → keepExistingUnit. 데이터 백업이 root 소유 파일(이전 마이그레이션 기록)에 막힘 → 읽기 실패 관대 처리(+서버의 해당 파일 소유권 정정). 7. 같은 버전 재설치가 실행 중인 디렉터리를 지움 → 임시 풀기·`.prev-<시각>` 보존. 새 유닛(포털) enable 누락. 부트스트랩 릴리스 기록 행 없음(UPDATE 무효). 8. my.ariweb.net nginx 접근 경로가 어디서도 만들어지지 않음 → 부트스트랩이 설치. 9. 서버 한 대(control)라 web·backup 역할 서버를 고를 수 없음 → control 대체. AriMail 설정 API 는 기본 도메인 호스트에서만 응답(Node fetch 는 Host 변경 불가) → 설정 주소를 기본 도메인 이름으로, 서버 hosts 항목. ## Release 0.1.1 완료 조건 34개 — 실제 환경 판정 | # | 흐름 | 판정 | 비고 | |---|---|---|---| | 1 | 신규 고객 가입과 이메일 확인 | 실제 확인 | 실제 포털·실제 mailer 경로(포획 서버) — 외부 수신함 도착은 별도 1건으로 확인 | | 2 | 개인 사용자 그룹 생성과 다른 사용자 초대 | 실제 확인 | | | 3 | 상품 주문, 결제 확인, 권리 활성화 | 실제 확인 | | | 4 | 초안 사이트 생성 | 실제 확인 | 실제 Webmaker 에 프로젝트 생성(내부 API 서명 호출) | | 5 | Webmaker에서 페이지 제작 | 부분 확인 | 제작 화면 진입(SSO)은 실제 Webmaker 로 확인 · 페이지 제작(AI 생성·저장)은 사람이 Webmaker 화면에서 수행해야 하므로 미수행 | | 6 | 관리형 배포 | 부분 확인 | 배포 요청이 거부됨: precheck_failed — 배포 전 확인에서 차단된 항목이 있습니다 (저장본이 없어 배포할 내용이 없음; 사람이 Webmaker 에서 페이지를 저장한 뒤 수행) | | 7 | 도메인 연결과 HTTPS 발급 | 미수행 | 실제 소유 도메인과 공개 DNS(TXT·A) 변경이 필요 — 이번 작업은 공개 DNS 를 바꾸지 않음 | | 8 | 외부 주소에서 사이트 확인 | 미수행 | 공개 DNS(my/hal/사이트 도메인) 생성 전 — 외부 주소 접속은 레코드 생성 뒤 확인 | | 9 | 사이트 정보와 접속·사용량 통계 확인 | 부분 확인 | 화면 데이터 제공 확인 · 실제 접속 통계(awstats 로그 집계)는 공개 DNS 로 외부 방문이 생긴 뒤 확인 가능 | | 10 | 사이트 대표 메일과 메일함 생성 | 부분 확인 | 실제 AriMail 테넌트·메일함 생성 확인 · 활성화는 도메인 DNS(MX/SPF/DKIM) 반영이 필요해 외부 대기 | | 11 | 외부 송신, 수신, 회신 확인 | 미수행 | 검증용 수신 주소(자동 응답 메일함)와 고객 도메인 MX 반영 필요 | | 12 | 독립 메일 서비스 생성 | 실제 확인 | | | 13 | 백업 옵션 구매와 첫 백업 확인 | 부분 확인 | 백업 옵션 주문·승인·활성화는 실제 확인. 수동 백업 실행은 사이트가 초안(미배포)이라 정기 실행기가 옵션을 site_not_deployed 로 중지해 Agent 백업까지 가지 않음(설계대로) — Webmaker 에서 페이지를 저장·배포한 뒤 다시 수행. 판정은 검증기의 시간 초과를 운영자가 DB 상태(옵션 paused: site_not_deployed)로 확인해 부분 확인으로 정정 | | 14 | 백업 복원과 외부 사이트 확인 | 미수행 | 복원 승인(3단계)·외부 사이트 확인은 공개 DNS 와 복원 대상 배포본 필요(흐름 6 선행) | | 15 | 관리형 사이트 서버 이전과 외부 확인 | 미수행 | 관리 서버가 1대뿐이라 서버 간 이전 미수행 | | 16 | 외부 배포 사이트 생성과 배포 | 미수행 | 외부 Linux 서버 없음 | | 17 | 사용량 경고와 한도 동작 확인 | 미수행 | 실제 사용량이 한도에 이르려면 운영 트래픽·시간 경과 필요 | | 18 | 상품 축소 보류와 정리 후 적용 | 미수행 | 축소 보류는 실제 사용 중 리소스가 필요(로컬 E2E 확인) | | 19 | 사이트 수 반환과 대표 메일의 독립 전환 | 미수행 | 사이트 수 반환·독립 전환은 흐름 10 활성화(외부 DNS) 뒤 가능 | | 20 | 사이트 소유권 이전 | 미수행 | 두 번째 소유자 그룹의 심사 절차를 포함해 로컬 E2E 로 확인, 실환경 미수행 | | 21 | 중지, 해지, 보존 예정일 표시 | 미수행 | 보존 예정일 표시는 시간 경과 필요(로컬 E2E 확인) | | 22 | HAL 우선 배포 후 HAL을 통한 전체 모듈 배포 | 실제 확인 | HAL 부트스트랩 → 첫 Agent → HAL 작업으로 portal·webmaker·arimail·agent 배포, 실제 버전 0.1.1·건강 ok | | 23 | 실패 작업의 재시도와 되돌리기 | 미수행 | 실패 작업 재시도·되돌리기는 배포 중 실제로 2회 발생(백업 실패→재시도 성공, 마이그레이션 실패→되돌리기) — 기록은 VERSION_HISTORY·이 문서의 배포 경과 참고 | | 24 | 운영자 승인, 감사 기록, 고객 알림의 일치 | 부분 확인 | | | 25 | HAL, 로그인, 비밀정보 관리, 인증서 기반의 재해복구 훈련 | 미수행 | 재해복구 훈련은 다른 호스트 복원이 필요(로컬 E2E 부분 확인) | | 26 | 새로 고침, 재로그인, HAL 재시작 후 진행 작업 상태 유지 | 실제 확인 | | | 27 | 마지막 사이트 수·용량·메일함 동시 요청 시 하나만 성공 | 미수행 | 동시 요청 경합은 로컬 E2E 로 확인, 실환경 미수행 | | 28 | 외부 Linux 서버 Agent 연결·배포·재배포·제거·실패 정리 | 미수행 | 외부 Linux 서버 없음 | | 29 | HAL 장애 중 기존 서비스 유지와 신규 변경 제한 표시 | 미수행 | HAL 장애 상태 표시는 로컬 E2E 로 확인(흐름 26 에서 재시작 중 복구만 실환경 확인) | | 30 | 모듈 업데이트, 일부 서버 실패, 대상별 되돌리기와 상태 조정 | 부분 확인 | 모듈 갱신(수정 artifact 재등록 → HAL 작업으로 agent·hal 갱신) 4건 완료 확인 · 일부 서버 실패·대상별 되돌리기는 서버 1대뿐이라 미수행 | | 31 | 긴급 복구의 승인 부족·만료 자격·허용 범위 밖 작업 거부와 정상 복구 | 미수행 | 긴급 복구 절차는 로컬 E2E 로 확인 | | 32 | Source 옵션 만료 후 30일 read-only, clone·export와 삭제 완료 | 미수행 | Source 옵션 30일 만료는 시간 경과 필요 | | 33 | 메일 서비스의 사이트 대표→독립 전환 후 항목 유지 | 미수행 | 흐름 19 와 같은 외부 DNS 선행 조건 | | 34 | 일시 중지·해지 예약·보존·삭제 단계의 표시 일치 | 미수행 | 시간 경과 필요(로컬 E2E 확인) | ## 흐름별 단계와 증거 ### 1. 신규 고객 가입과 이메일 확인 — 실제 확인 실제 포털·실제 mailer 경로(포획 서버) — 외부 수신함 도착은 별도 1건으로 확인 - ✔ 가입 → 세션 발급(실제 포털 https://my.ariweb.net) — {"status":200} - ✔ 확인 전 그룹 생성 차단(403 email_unverified) — "email_unverified" - ✔ 확인 메일이 실제 발신 경로(mailer resend → 포획 서버)로 나감 · 토큰 추출 — {"subject":"[Ariweb] 이메일 주소를 확인해 주세요","from":"no-reply@ariweb.net","linkHost":"https://my.ariweb.net"} - ✔ 이메일 확인(1회용) → 재사용 거부 — {"first":200,"second":"token_used"} - ✔ 내 정보: 확인됨 · 개인 그룹 · owner — {"verifiedAt":"2026-10-26T14:31:15.078Z","group":"personal","role":"owner"} - ✔ 중복 가입은 존재를 드러내지 않는 안내(409) — "signup_unavailable" - ✔ 로그인 화면(로그인 상태면 302, 아니면 200)·기기(세션) 목록 — {"loggedIn":302,"anonymous":200,"sessions":"[redacted]"} ```json { "verifiedAt": "2026-10-26T14:31:15.078Z", "group": "personal", "role": "owner" } ``` ### 2. 개인 사용자 그룹 생성과 다른 사용자 초대 — 실제 확인 - ✔ 팀 그룹 만들기 → 현재 그룹 전환 — "g_01a1789f67b12a216acd1955fa" - ✔ 이메일 초대 → 초대 메일(포획)에서 링크 — "upaCVcL43bFzzZaGTtGZi_tU2J64oJEA" - ✔ 초대 수락(1회용) → member · 재사용 거부 — {"reuse":"invite_invalid"} - ✔ 권한 없는 구성원의 변경 API → 403 — {"requiredRole":["owner","admin"],"yourRole":"member"} ### 3. 상품 주문, 결제 확인, 권리 활성화 — 실제 확인 - ✔ 상품 목록(공개 버전·가격·한도) — {"count":2,"id":"pv_01a178834fac072b5600ce1e60","name":"팀","price":49000,"sites":3} - ✔ 주문 제출(수동 결제, 독립 메일 옵션 포함) → 결제 대기 — {"id":"o_01a1789f68c3298aec8ad337e8","group_id":"g_01a1789f67b12a216acd1955fa","order_no":"AW-20261026-0003","kind":"new","product_version_id":"pv_01a178834fac072b5600ce1e60","items_json":"[{\"type\":\"product\",\"id\":\"team\",\"name\":\"팀\",\"qty\":1,\"unit_price\":49000,\"amount\":49000,\"tax\":4900,\"target_type\":\"group\",\"target_id\":null,\"grants\":{\"sites\":3,\"web_disk\":21474836480,\" - ✔ 입금 확인 전 승인 거부(409) — "payment_not_confirmed" - ✔ 운영자 입금 확인 → 승인 → 권리 활성화 — {"paid":"awaiting_approval","approved":"approved","granted":10} - ✔ 고객 결제 화면: 활성 상품·권리·다음 청구일 — {"subs":1,"nextBilling":"2026-11-26T14:31:15.451Z"} ```json { "orderNo": "AW-20261026-0003", "bill": { "subs": 1, "nextBilling": "2026-11-26T14:31:15.451Z" } } ``` ### 4. 초안 사이트 생성 — 실제 확인 실제 Webmaker 에 프로젝트 생성(내부 API 서명 호출) - ✔ 사이트 생성(새 Webmaker 프로젝트 · 관리형) → 초안 — {"id":"s_01a1789f690cb9115f0330d2e8","group_id":"g_01a1789f67b12a216acd1955fa","name":"검증 사이트 mvpcu283","purpose":"실제 환경 검증","webmaker_project_id":"85e1859a8638022beb761f1ec4ccfc93","template":null,"lang":"ko","timezone":"Asia/Seoul","lifecycle":"draft","deploy_mode":"managed","primary_domain":null,"site_count_state":"none","site_count_reservation_id":null,"server_id":null,"external_agent_id":null - ✔ 초안 목록·사용량(사이트 수 미소비) — {"drafts":1,"lifecycle":"draft","projectId":null} ### 5. Webmaker에서 페이지 제작 — 부분 확인 제작 화면 진입(SSO)은 실제 Webmaker 로 확인 · 페이지 제작(AI 생성·저장)은 사람이 Webmaker 화면에서 수행해야 하므로 미수행 - ✔ 제작 화면 열기: 포털 SSO 티켓 → 실제 Webmaker /api/auth/sso 302(1회용) — {"portal":302,"webmaker":302,"webmakerLocation":"/?site=85e1859a8638022beb761f1ec4ccfc93","reuse":403} - ✔ 저장본 목록·배포 전 확인(실제 Webmaker 프로젝트) — {"versionsStatus":200,"versions":0,"precheck":true} ```json { "sso": { "portal": 302, "webmaker": 302, "webmakerLocation": "/?site=85e1859a8638022beb761f1ec4ccfc93", "reuse": 403 }, "ver": { "versionsStatus": 200, "versions": 0, "precheck": true } } ``` ### 6. 관리형 배포 — 부분 확인 배포 요청이 거부됨: precheck_failed — 배포 전 확인에서 차단된 항목이 있습니다 (저장본이 없어 배포할 내용이 없음; 사람이 Webmaker 에서 페이지를 저장한 뒤 수행) - ✔ 배포 요청(관리형) → HAL 작업·사이트 수 예약 — {"status":409,"error":"precheck_failed","message":"배포 전 확인에서 차단된 항목이 있습니다"} ### 9. 사이트 정보와 접속·사용량 통계 확인 — 부분 확인 화면 데이터 제공 확인 · 실제 접속 통계(awstats 로그 집계)는 공개 DNS 로 외부 방문이 생긴 뒤 확인 가능 - ✔ 사이트 정보·배포 이력·사용량 화면 — {"overviewKeys":["ok","overview","refreshJob"],"usageKeys":["ok","overview","allocations","samples"],"deployments":0} ```json { "overviewKeys": [ "ok", "overview", "refreshJob" ], "usageKeys": [ "ok", "overview", "allocations", "samples" ], "deployments": 0 } ``` ### 10. 사이트 대표 메일과 메일함 생성 — 부분 확인 실제 AriMail 테넌트·메일함 생성 확인 · 활성화는 도메인 DNS(MX/SPF/DKIM) 반영이 필요해 외부 대기 - ✔ 사이트 연결 도메인 등록(검증 전용 이름, 소유 확인은 외부 대기) — {"id":"d_01a1789f6a07e57873e2f0c05f"} - ✔ 사이트 대표 메일 생성 → 실제 AriMail 테넌트 준비 — {"id":"msv_01a1789f6a0d5f702a1581f2fd","status":"needs_setup","kind":"site_bound"} - ✔ 메일함 생성(초기 비밀번호 1회 표시) → 재조회에 비밀번호 없음 · 실제 AriMail 계정 — {"id":"mb_01a1789f6e723ade68602baaf9","address":"kim@check-mvpcu283.ariweb.net","shownOnce":true,"leakedOnReload":false} - ✔ DNS 확인(미반영 구분) → 활성화 작업은 외부 대기 — {"dnsOk":true,"items":[],"activate":200,"job":"queued","waitReason":""} ```json { "d": { "id": "d_01a1789f6a07e57873e2f0c05f" }, "svc": { "id": "msv_01a1789f6a0d5f702a1581f2fd", "status": "needs_setup", "kind": "site_bound" }, "mb": { "id": "mb_01a1789f6e723ade68602baaf9", "address": "kim@check-mvpcu283.ariweb.net", "shownOnce": true, "leakedOnReload": false }, "dns": { "dnsOk": true, "items": [], "activate": 200, "job": "queued", "waitReason": "" } } ``` ### 12. 독립 메일 서비스 생성 — 실제 확인 - ✔ 메일 전용 도메인 등록(purpose mail) — "d_01a1789f6e94cf197bdcb0cb81" - ✔ 독립 메일 서비스 생성(독립 옵션 소비·사이트 수 미소비) — {"id":"msv_01a1789f6e9604bd5f49bb08e1","kind":"standalone","status":"needs_setup","usage":{}} ```json { "id": "msv_01a1789f6e9604bd5f49bb08e1", "kind": "standalone", "status": "needs_setup", "usage": {} } ``` ### 13. 백업 옵션 구매와 첫 백업 확인 — 부분 확인 백업 옵션 주문·승인·활성화는 실제 확인. 수동 백업 실행은 사이트가 초안(미배포)이라 정기 실행기가 옵션을 site_not_deployed 로 중지해 Agent 백업까지 가지 않음(설계대로) — Webmaker 에서 페이지를 저장·배포한 뒤 다시 수행. 판정은 검증기의 시간 초과를 운영자가 DB 상태(옵션 paused: site_not_deployed)로 확인해 부분 확인으로 정정 - ✔ 백업 옵션 주문(대상 사이트 지정) → 입금 확인 → 승인 — {"orderNo":"AW-20261026-0004","approved":"approved"} - ✔ 백업 화면(옵션 보유 여부) — {} - ✔ 옵션 활성화(확인 필수) → 첫 백업 예정 — {"status":"active"} - ✘ 지금 백업 실행 → 실제 Agent 가 사이트 파일·데이터를 묶어 저장(완료 대기 120초) — 백업 완료 대기 시간 초과 ```json { "optionState": { "status": "paused", "paused_reason": "site_not_deployed", "updated_at": "2026-10-26T14:32:11.943Z" }, "siteLifecycle": "draft", "lastJob": { "status": "failed", "error": "대상 서버 또는 Agent 가 필요합니다" } } ``` ### 22. HAL 우선 배포 후 HAL을 통한 전체 모듈 배포 — 실제 확인 HAL 부트스트랩 → 첫 Agent → HAL 작업으로 portal·webmaker·arimail·agent 배포, 실제 버전 0.1.1·건강 ok - ✔ HAL 릴리스·모듈 목표/실제 버전(배포 영수증) — {"running":{"complete":true,"firstInstall":false,"releaseVersion":"0.1.1","mainCommit":"[redacted]","artifactSha256":"[redacted]","halRunningVersion":"0.1.1","firstAgent":"[redacted]","manualInstallLocked":true},"targets":[{"module":"agent","target":"0.1.1","actual":"0.1.1","health":"ok"},{"module":"arimail","target":"0.1.1","actual":"0.1.1","health":"ok"},{"module":"backup","target":null,"actual" - ✔ HAL 을 통한 모듈 배포 작업(module.deploy) 결과 — [{"label":"portal 0.1.1 배포","status":"done"},{"label":"hal 0.1.1 배포","status":"done"},{"label":"portal 0.1.1 배포","status":"done"},{"label":"portal 0.1.1 배포","status":"done"},{"label":"agent 0.1.1 배포","status":"done"},{"label":"arimail 0.1.1 배포","status":"done"},{"label":"hal 0.1.1 배포","status":"done"},{"label":"agent 0.1.1 배포","status":"done"},{"label":"arimail 0.1.1 배포","status":"failed"},{"label ```json { "rel": { "running": { "complete": true, "firstInstall": false, "releaseVersion": "0.1.1", "mainCommit": "[redacted]", "artifactSha256": "[redacted]", "halRunningVersion": "0.1.1", "firstAgent": "[redacted]", "manualInstallLocked": true }, "targets": [ { "module": "agent", "target": "0.1.1", "actual": "0.1.1", "health": "ok" }, { "module": "arimail", "target": "0.1.1", "actual": "0.1.1", "health": "ok" }, { "module": "backup", "target": null, "actual": "0.1.1", "health": "ok" }, { "module": "hal", "target": "0.1.1", "actual": "0.1.1", "health": "ok" }, { "module": "observability", "target": null, "actual": "0.1.1", "health": "ok" }, { "module": "portal", "target": "0.1.1", "actual": "0.1.1", "health": "ok" }, { "module": "webmaker", "target": "0.1.1", "actual": "0.1.1", "health": "ok" } ] }, "jobs": [ { "label": "portal 0.1.1 배포", "status": "done" }, { "label": "hal 0.1.1 배포", "status": "done" }, { "label": "portal 0.1.1 배포", "status": "done" }, { "label": "portal 0.1.1 배포", "status": "done" }, { "label": "agent 0.1.1 배포", "status": "done" }, { "label": "arimail 0.1.1 배포", "status": "done" }, { "label": "hal 0.1.1 배포", "status": "done" }, { "label": "agent 0.1.1 배포", "status": "done" }, { "label": "arimail 0.1.1 배포", "status": "failed" }, { "label": "webmaker 0.1.1 배포", "status": "done" }, { "label": "portal 0.1.1 배포", "status": "done" } ] } ``` ### 24. 운영자 승인, 감사 기록, 고객 알림의 일치 — 부분 확인 - ✔ 고객 감사 기록(order.approve) · 알림 · 운영자 주문 상태 일치 — {"auditEntries":0,"notifications":6,"status":"approved"} - ✔ HAL 감사 기록(deploy.module) — 10 ```json { "a": { "auditEntries": 0, "notifications": 6, "status": "approved" }, "halDeployAudit": 10 } ``` ### 26. 새로 고침, 재로그인, HAL 재시작 후 진행 작업 상태 유지 — 실제 확인 - ✔ HAL 재시작 전: 운영자 세션·작업 수·서버 등록 — {"jobs":23,"servers":1} - ✔ systemctl restart ariweb-hal → 건강 회복 → 같은 세션으로 작업 수·서버 유지 — {"uptimeSec":1,"sessionKept":"[redacted]","jobs":23,"servers":1,"agentOnline":true} - ✔ Agent 가 재접속(heartbeat) 해 서버 ready 유지 — [{"name":"srv1953374 (ariweb.net)","status":"ready","lastSeen":"2026-10-26T14:33:13.381Z"}] ```json { "before": { "jobs": 23, "servers": 1 }, "after": { "uptimeSec": 1, "sessionKept": "[redacted]", "jobs": 23, "servers": 1, "agentOnline": true }, "ag": [ { "name": "srv1953374 (ariweb.net)", "status": "ready", "lastSeen": "2026-10-26T14:33:13.381Z" } ] } ``` ## 검증에 쓴 테스트 데이터(정리 대상) - 고객 계정 `alice-mvpcu283@check.ariweb.net`(및 bob-*, 이전 실행분 alice-*/bob-*), 사이트 `s_01a1789f690cb9115f0330d2e8`, 도메인 `check-mvpcu283.ariweb.net`·`solo-*.ariweb.net`(AriMail 테넌트는 운영자 취소 → 보존 기간 뒤 삭제), 주문 `o_01a1789f68c3298aec8ad337e8`. 모두 `@check.ariweb.net` 주소의 검증 전용 데이터다. ## 성공 선언 전 재검증(서버에서 읽은 값, `90-verify.sh`) ``` ### systemd ariweb-hal active / enabled=enabled ariweb-agent active / enabled=enabled ariweb-portal active / enabled=enabled webmaker active / enabled=enabled webmaker-setup active / enabled=enabled arihakdang-mail active / enabled=enabled arihakdang-mail-haraka active / enabled=enabled nginx active / enabled=enabled ### nginx nginx: configuration file /etc/nginx/nginx.conf test is successful ariweb-hal.conf ariweb-portal.conf webmail.ariweb.net.conf webmaker.ariweb.net.conf webmaker.ariweb.net.conf.bak-1.5.27 ### HAL health (127.0.0.1:8900) {"ok":true,"version":"0.1.1","uptimeSec":5,"db":true,"jobs":true,"bootstrap":{"complete":true,"firstInstall":false,"releaseVersion":"0.1.1","mainCommit":"3951be5836a753e60f11d6b363025059fcf6d448","artifactSha256":"e7741899cd7387b0155c9d3bf8ff14cc4026880db999c9d59347744390415e84","halRunningVersion":"0.1.1","firstAgent":"ag_01a178829f1c3d88381d2c0c75","manualInstallLocked":true},"instanceId":"hal_01a178a14a3deef408f7ddfa91"} ### HAL health via nginx https (resolve 127.0.0.1) {"ok":true,"version":"0.1.1","db":true,"bootstrap":true} ### portal health {"ok":true,"version":"0.1.1","db":true,"jobs":17,"time":"2026-10-26T14:33:23.567Z"} {"ok":true,"version":"0.1.1"} my.ariweb.net /login → 200 ### ops console /ops/ (127.0.0.1) → 200 /ops/ via nginx (외부 IP 흉내 X-Real-IP 8.8.8.8) → 200 ### modules (HAL 기록) { "running": { "complete": true, "firstInstall": false, "releaseVersion": "0.1.1", "mainCommit": "3951be5836a753e60f11d6b363025059fcf6d448", "artifactSha256": "e7741899cd7387b0155c9d3bf8ff14cc4026880db999c9d59347744390415e84", "halRunningVersion": "0.1.1", "firstAgent": "ag_01a178829f1c3d88381d2c0c75", "manualInstallLocked": true }, "releases": [ { "v": "0.1.1", "status": "approved", "halDeployedAt": "2026-10-26T14:30:34.618Z" } ], "targets": [ { "module": "agent", "target": "0.1.1", "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "arimail", "target": "0.1.1", "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "backup", "target": null, "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "hal", "target": "0.1.1", "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "observability", "target": null, "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "portal", "target": "0.1.1", "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null }, { "module": "webmaker", "target": "0.1.1", "actual": "0.1.1", "health": "ok", "active": 1, "checkedAt": "2026-10-26T14:33:13.381Z", "err": null } ] } ### modules (디스크) /srv/ariweb/hal current → /srv/ariweb/hal/releases/0.1.1 REVISION=0.1.1(상류 0.1.1) pkg=0.1.1 /srv/ariweb/portal current → /srv/ariweb/portal/releases/0.1.1 REVISION=0.1.1(상류 0.1.1) pkg=0.1.1 /srv/ariweb/agent current → /srv/ariweb/agent/releases/0.1.1 REVISION=0.1.1(상류 0.1.1) pkg=0.1.1 /srv/webmaker current → /srv/webmaker/releases/0.1.1 REVISION=0.1.1(상류 1.7.3) pkg=1.7.3 /srv/arihakdang-mail current → /srv/arihakdang-mail/releases/0.1.1 REVISION=0.1.1(상류 1.0.11) pkg=1.0.11 ### 서비스 자체 보고 버전 {"ok":true,"version":"1.0.11","domains":6} webmaker csrf → 401 webmaker.ariweb.net → 302 webmail.ariweb.net → 200 ### 배포 영수증(감사 기록 deploy.*) [ { "at": "2026-10-26T14:30:45.633Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "portal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:30:35.618Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "hal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:23:37.819Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "portal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:16:46.605Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "portal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:16:41.094Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "agent", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:09:32.947Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "arimail", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:09:24.433Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "hal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:08:47.250Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "agent", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:00:26.918Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "webmaker", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } }, { "at": "2026-10-26T14:00:17.400Z", "actor": "op_01a178829b90905c15a3191caa", "subject": "portal", "detail": { "version": "0.1.1", "serverIds": [ "srv_01a178829d5848f93a15f93a17" ], "overall": "done" } } ] ### 배포 작업 [ { "id": "j_01a1789ee309d1bc1102a6d949", "label": "portal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:30:45.633Z" }, { "id": "j_01a1789eba1aac59f8518c92b3", "label": "hal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:30:35.618Z" }, { "id": "j_01a178985cf9fa2f2e76fa7735", "label": "portal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:23:37.819Z" }, { "id": "j_01a17892166e8460c04de6a7d6", "label": "portal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:16:46.605Z" }, { "id": "j_01a17892094ddcff01ba7b8002", "label": "agent 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:16:41.094Z" }, { "id": "j_01a1788b794d0d3545ca8bedd0", "label": "arimail 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:09:32.947Z" }, { "id": "j_01a1788b53ed98904ed1127166", "label": "hal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:09:24.433Z" }, { "id": "j_01a1788acd103d85194bbb8bba", "label": "agent 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:08:47.250Z" }, { "id": "j_01a17883416842d8acc7909136", "label": "arimail 0.1.1 배포", "status": "failed", "ended": "2026-10-26T14:00:33.432Z" }, { "id": "j_01a178831b657e19aaed13d7d8", "label": "webmaker 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:00:26.918Z" }, { "id": "j_01a178830202223b4852e6cb6a", "label": "portal 0.1.1 배포", "status": "done", "ended": "2026-10-26T14:00:17.401Z" } ] ### 서버·Agent [ { "id": "srv_01a178829d5848f93a15f93a17", "name": "srv1953374 (ariweb.net)", "role": "control", "status": "ready", "agent": "ag_01a178829f1c3d88381d2c0c75", "agentVersion": "0.1.1", "lastSeen": "2026-10-26T14:33:13.381Z", "modules": { "webmaker": { "target": "0.1.1", "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "arimail": { "target": "0.1.1", "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "hal": { "target": "0.1.1", "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "agent": { "target": "0.1.1", "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "observability": { "target": null, "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "backup": { "target": null, "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null }, "portal": { "target": "0.1.1", "actual": "0.1.1", "drift": false, "health": "ok", "active": true, "lastCheckAt": "2026-10-26T14:33:13.381Z", "lastError": null } } } ] ### 공개 DNS(참고) hal.ariweb.net → my.ariweb.net → ```