From ef666e6fc0e69deb50ee57aa56d8e2ce5051f2e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 9 Mar 2026 18:36:33 +0900 Subject: [PATCH] docs: migrate infrastructure troubleshooting from robeing --- journey/README.md | 16 ++ ...17_starsandi_dns_nginx_ssl_분리적용.md | 51 +++++++ ...루트포스_차단_및_fail2ban_교정.md | 35 +++++ ..._bot_account_compromise_and_eradication.md | 76 ++++++++++ ...nclaw_gateway_상주프로세스_정리.md | 38 +++++ ..._219_51_접속불가_임시백업복구.md | 40 +++++ ...사고_복구_및_의존포트_점검.md | 140 ++++++++++++++++++ ...8001_연결점검_23서버_전달사항.md | 56 +++++++ ...51123_ufw_외부포트_차단_하드닝.md | 70 +++++++++ ...복구_서비스연속성_조치내역.md | 116 +++++++++++++++ ...ot_및_배포실패_근본원인_해결.md | 42 ++++++ ...05_51124_다운_상태_및_복구예정.md | 9 ++ ..._gitea_lfs_permission_denied_502_복구.md | 44 ++++++ ...이전_네트워크변경_운영기록.md | 18 +++ ...AS_권한정렬_및_실업로드_검증.md | 73 +++++++++ ...SOT_전환_및_CIFS_실마운트_복구.md | 74 +++++++++ ...untime_secrets_분리_적용_및_검증.md | 76 ++++++++++ 17 files changed, 974 insertions(+) create mode 100644 journey/troubleshooting/260217_starsandi_dns_nginx_ssl_분리적용.md create mode 100644 journey/troubleshooting/260226_51123_SSH_브루트포스_차단_및_fail2ban_교정.md create mode 100644 journey/troubleshooting/260226_51124_bot_account_compromise_and_eradication.md create mode 100644 journey/troubleshooting/260226_51124_openclaw_gateway_상주프로세스_정리.md create mode 100644 journey/troubleshooting/260226_NAS_192_168_219_51_접속불가_임시백업복구.md create mode 100644 journey/troubleshooting/260303_51123_DB5432_차단사고_복구_및_의존포트_점검.md create mode 100644 journey/troubleshooting/260303_51123_gateway_rb8001_연결점검_23서버_전달사항.md create mode 100644 journey/troubleshooting/260303_51123_ufw_외부포트_차단_하드닝.md create mode 100644 journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md create mode 100644 journey/troubleshooting/260305_23임시배포_envdeploy_ssot_및_배포실패_근본원인_해결.md create mode 100644 journey/troubleshooting/260305_51124_다운_상태_및_복구예정.md create mode 100644 journey/troubleshooting/260306_51123_gitea_lfs_permission_denied_502_복구.md create mode 100644 journey/troubleshooting/260307_51123_성수이전_네트워크변경_운영기록.md create mode 100644 journey/troubleshooting/260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md create mode 100644 journey/troubleshooting/260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md create mode 100644 journey/troubleshooting/260307_gateway_SSOT_runtime_secrets_분리_적용_및_검증.md diff --git a/journey/README.md b/journey/README.md index 56a32fe..3e02b68 100644 --- a/journey/README.md +++ b/journey/README.md @@ -19,6 +19,22 @@ - 실행 중 문제가 생기면 `worklog`가 아니라 `troubleshooting`으로 기록합니다. ## 현재 문서 +- [260307 gateway SSOT runtime/secrets 분리 적용 및 검증](./troubleshooting/260307_gateway_SSOT_runtime_secrets_분리_적용_및_검증.md) +- [260307 NAS(192.168.0.101) SSOT 전환 및 CIFS 실마운트 복구](./troubleshooting/260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md) +- [260307 Gitea LFS NAS 권한정렬 및 실업로드 검증](./troubleshooting/260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md) +- [260307 51123 서버 성수 이전 네트워크 변경 운영기록](./troubleshooting/260307_51123_성수이전_네트워크변경_운영기록.md) +- [260306 51123 Gitea LFS 권한 오류 502 복구](./troubleshooting/260306_51123_gitea_lfs_permission_denied_502_복구.md) +- [260305 51124 다운 상태 및 복구 예정](./troubleshooting/260305_51124_다운_상태_및_복구예정.md) +- [260305 23 임시배포 env.deploy SSOT 및 배포실패 근본원인 해결](./troubleshooting/260305_23임시배포_envdeploy_ssot_및_배포실패_근본원인_해결.md) +- [260304 51123 임시복구 서비스 연속성 조치내역](./troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md) +- [260303 51123 DB 5432 차단사고 복구 및 의존 포트 점검](./troubleshooting/260303_51123_DB5432_차단사고_복구_및_의존포트_점검.md) +- [260303 51123 서버 UFW 외부 포트 차단 하드닝](./troubleshooting/260303_51123_ufw_외부포트_차단_하드닝.md) +- [260303 23 서버 전달사항: gateway-rb8001 연결 점검 결과](./troubleshooting/260303_51123_gateway_rb8001_연결점검_23서버_전달사항.md) +- [260226 51124 bot 계정 SSH 침해 대응 및 박멸 기록](./troubleshooting/260226_51124_bot_account_compromise_and_eradication.md) +- [260226 51124 openclaw-gateway 상주 프로세스 정리](./troubleshooting/260226_51124_openclaw_gateway_상주프로세스_정리.md) +- [260226 51123 SSH 브루트포스 차단 및 fail2ban 교정](./troubleshooting/260226_51123_SSH_브루트포스_차단_및_fail2ban_교정.md) +- [260226 NAS(192.168.219.51) 접속불가 임시 백업 복구](./troubleshooting/260226_NAS_192_168_219_51_접속불가_임시백업복구.md) +- [260217 starsandi DNS/nginx/SSL 분리 적용](./troubleshooting/260217_starsandi_dns_nginx_ssl_분리적용.md) - [51123 구 IP 하드코딩과 런타임 SSOT 불일치 이슈](./troubleshooting/260309_51123_구IP하드코딩_런타임SSOT불일치_이슈.md) - [24서버 우분투 터미널 불가, 네트워크 대역 오류, python3-apt 복구 기록](./troubleshooting/260309_24서버_우분투터미널불가_네트워크대역오류_python3apt복구.md) - [23서버 워크스페이스 인프라 구조정리 이슈](./troubleshooting/260307_23서버_워크스페이스_인프라_구조정리_이슈.md) diff --git a/journey/troubleshooting/260217_starsandi_dns_nginx_ssl_분리적용.md b/journey/troubleshooting/260217_starsandi_dns_nginx_ssl_분리적용.md new file mode 100644 index 0000000..42a6773 --- /dev/null +++ b/journey/troubleshooting/260217_starsandi_dns_nginx_ssl_분리적용.md @@ -0,0 +1,51 @@ +# 260217 starsandi DNS/nginx/SSL 분리 적용 + +## 배경 +- 목표: 51123 서버에서 `ro-being.com`과 `starsandi.com`을 충돌 없이 분리 운영. +- 요구사항: + - DNS: `A @ -> 124.55.18.179`, `CNAME www -> @` + - nginx: `starsandi.com`, `www.starsandi.com` 전용 서버 블록 분리 + - HTTPS: certbot으로 인증서 발급 및 80 -> 443 적용 + - 경로: starsandi 앱은 현재 `basePath=/starsandi` 유지 + +## 원인 및 이슈 +- 초기 조회에서 `starsandi.com`이 Namecheap 주차 IP(`192.64.119.114`)로 응답되어 인증서 발급 타이밍 이슈 존재. +- 권한 DNS(8.8.8.8, 1.1.1.1) 기준으로는 `124.55.18.179` 조회되어 전파 진행 중 상태 확인. + +## 적용 내용 + +### 1) nginx 도메인 분리 +- 파일 추가: `/etc/nginx/sites-available/starsandi.conf` +- 심볼릭 링크: `/etc/nginx/sites-enabled/starsandi.conf` +- 핵심 설정: + - `server_name starsandi.com www.starsandi.com;` + - `location = / { return 301 /starsandi; }` (basePath 유지) + - `location /starsandi { proxy_pass http://127.0.0.1:3010; ... }` + +### 2) ro-being 경로 충돌 방지 +- 파일 수정: `/etc/nginx/sites-enabled/default` +- 변경 내용: + - `ro-being.com` 블록의 `/startsandi`, `/zari`, `/starsandi` 요청을 `https://starsandi.com...`으로 301 리다이렉트 + +### 3) SSL(certbot) +- 실행 명령: + - `sudo certbot --nginx -d starsandi.com -d www.starsandi.com --non-interactive --agree-tos -m admin@starsandi.com --redirect` +- 결과: + - 인증서 발급 성공 + - 경로: `/etc/letsencrypt/live/starsandi.com/fullchain.pem` + - 만료일: `2026-05-18` + - certbot이 nginx 설정에 443 블록 자동 반영 + +## 검증 결과 +- `sudo nginx -t` 성공 +- `sudo systemctl reload nginx` 성공 +- 로컬 강제 해석(`--resolve`) 검증: + - `http://starsandi.com` -> `https://starsandi.com/` 301 + - `https://starsandi.com` -> `/starsandi` 301 + - `https://www.starsandi.com` -> `/starsandi` 301 + - `https://ro-being.com/starsandi` -> `https://starsandi.com/starsandi` 301 + +## 운영 메모 +- DNS 캐시/전파 구간에서는 일부 클라이언트가 Namecheap 응답(주차/포워딩)을 잠시 볼 수 있음. +- 실제 서비스 판별은 `dig @8.8.8.8 starsandi.com A`, `dig @1.1.1.1 starsandi.com A`로 재확인. +- 용어 표기는 서버 규칙에 따라 `robeing` 기준 유지. diff --git a/journey/troubleshooting/260226_51123_SSH_브루트포스_차단_및_fail2ban_교정.md b/journey/troubleshooting/260226_51123_SSH_브루트포스_차단_및_fail2ban_교정.md new file mode 100644 index 0000000..c75fcc8 --- /dev/null +++ b/journey/troubleshooting/260226_51123_SSH_브루트포스_차단_및_fail2ban_교정.md @@ -0,0 +1,35 @@ +# 260226 51123 SSH 브루트포스 차단 및 fail2ban 교정 + +## 시간 +- 기준일: 2026-02-26 + +## 배경 +- 51123 SSH(포트 51123)로 무차별 대입 시도가 대량 유입됨 +- 집계 기준(당일): `Failed password 56,613`, `Invalid user 48,030` + +## 조치 +1. UFW 수동 차단 +- 허용(관리자 예외): `112.146.113.214`, `220.85.143.128` +- 차단(반복 실패 상위): `134.209.249.168`, `164.92.167.107`, `209.38.245.39` + +2. fail2ban 설정 교정 +- 파일: `/etc/fail2ban/jail.d/ssh-custom.conf` +- 핵심 변경: + - `port = 51123` (기존 `ssh` 포트 기본값 의존 제거) + - `ignoreip = 127.0.0.1/8 ::1 192.168.219.0/24 112.146.113.214 220.85.143.128` + - `sshd`: `maxretry=5`, `findtime=600`, `bantime=86400` + - `sshd-aggressive`: `maxretry=3`, `findtime=300`, `bantime=604800` + +3. 서비스 반영 +- `systemctl restart fail2ban` +- `fail2ban-client status`로 `sshd`, `sshd-aggressive` 정상 활성 확인 + +## 확인 결과 +- fail2ban 재시작 후 양쪽 jail에서 실시간 차단 동작 확인 +- 화이트리스트 IP는 수동 `unbanip` 실행으로 차단 예외 재확인 +- SSH 설정은 `Port 51123`, `PermitRootLogin no`, `PasswordAuthentication yes` 상태 + +## 후속 권장 +1. 가능하면 `PasswordAuthentication no`로 전환(키 기반만 허용) +2. 비상 접속 계정 1개만 비밀번호 허용 + 소스 IP 제한 +3. 월 1회 `fail2ban`/`ufw` 룰 정리 및 화이트리스트 검증 diff --git a/journey/troubleshooting/260226_51124_bot_account_compromise_and_eradication.md b/journey/troubleshooting/260226_51124_bot_account_compromise_and_eradication.md new file mode 100644 index 0000000..cc28a7e --- /dev/null +++ b/journey/troubleshooting/260226_51124_bot_account_compromise_and_eradication.md @@ -0,0 +1,76 @@ +# 51124 bot 계정 SSH 침해 대응 및 박멸 기록 + +**날짜**: 2026-02-26 +**작성자**: admin +**관련 파일**: `/var/log/auth.log*`, `/home/bot/.configrc7/*`, `/var/spool/cron/crontabs/bot` + +--- + +## 문제 상황 +- 51124 서버에서 비정상 고메모리 프로세스(`kauditd0`) 발견 +- 실체 확인 결과 `/home/bot/.configrc7/a/kswapd00` 실행 파일로 위장 동작 +- `bot` crontab에 재실행 지속성(`*/30 * * * * /tmp/.kswapd00 || /home/bot/.configrc7/a/kswapd00`) 존재 + +## 침해 지표(IOC) +- 프로세스/파일 + - `kauditd0`, `kswapd00`, `edac0` + - `/home/bot/.configrc7/a/*`, `/home/bot/.configrc7/b/*` + - `/tmp/.kswapd00`, `/tmp/.X28-unix/.rsync/c/aptitude` +- SSH/지속성 + - `~/.ssh/authorized_keys`에 `mdrfckr` 주석의 `ssh-rsa` 키 주입 흔적 + - `chattr +/-ia`를 이용한 `.ssh` 잠금 시도 +- 네트워크 + - 공격 유입 성공 IP: `179.43.139.82` + - 감염 프로세스 외부 연결 IP: `179.43.139.85:80` + +## 로그 기반 사실 확인 +- `2026-02-18 18:46:05 KST`: `Accepted password for bot from 179.43.139.82` +- `2026-02-18 18:54:06 KST`: `Accepted password for bot from 179.43.139.82` +- `root` 계정 `Accepted` 로그인 성공 기록은 보관 로그 기준 미검출 +- `admin` 계정은 정상 운영 접속으로 보이는 `Accepted` 기록 다수 존재 + +## 원인 판정 +- SSH 비밀번호 인증 허용 상태(`passwordauthentication yes`)에서 `bot` 계정 비밀번호 기반 침입 성공 +- `bot` 계정이 `sudo`/`docker` 권한 보유(`sudo ALL`) 상태여서 감염 스크립트 설치 및 지속성 확보가 가능했던 구조 + +## 조치 내역 +1. 악성 프로세스 종료 + - `kauditd0/kswapd00/edac0` 관련 프로세스 킬 +2. 지속성 제거 + - `crontab -u bot -r`로 `bot` 사용자 크론 제거 +3. 악성 파일 제거 + - `/home/bot/.configrc7`, `/tmp/.kswapd00`, `/tmp/.X28-unix/.rsync` 삭제 +4. 백도어 키 제거 + - `/home/bot/.ssh/authorized_keys`의 `mdrfckr` 키 제거 + - 백업: `/home/bot/.ssh/authorized_keys.bak.20260226212628` +5. 계정 비밀번호 교체 + - `2026-02-26` 기준 `admin`, `root`, `bot` 비밀번호 변경 완료 + +## 검증 결과 +- `kauditd0/kswapd00/edac0` 프로세스 미검출 +- `bot` crontab 미존재 확인 +- IOC 경로(`/home/bot/.configrc7`, `/tmp/.kswapd00`, `/tmp/.X28-unix/.rsync`) 미존재 확인 +- `mdrfckr` 키 미검출 확인 +- 서비스 영향 없음: `docker ps` 전체 `Up`, `curl http://localhost:8001/health` HTTP 200 + +## 남은 리스크 +- 보관 로그 한계로 과거 데이터 조회/유출 여부를 100% 확정할 수 없음 +- `bot` 계정으로 읽기 접근된 비밀값(API 키, 토큰, DB 접속정보)은 노출 가능성 배제 불가 + +## 후속 권고 +1. SSH 하드닝 + - `PasswordAuthentication no` + - `AllowUsers admin` 등 접속 사용자 제한 +2. 계정 정리 + - `bot` 계정 업무 불필요 시 잠금(`usermod -L`) 또는 삭제 + - `sudo`/`docker` 최소 권한 재설계 +3. 비밀값 로테이션 + - `.env` 기반 토큰/Gitea 토큰/외부 API 키 전면 교체 +4. 모니터링 강화 + - `auth.log`의 `Accepted password` 이상 탐지 알림 + - 크론/시스템 서비스 신규 등록 이벤트 모니터링 + +## 교훈 +- 비밀번호 SSH 허용 + 고권한 사용자 조합은 자동화 봇넷 침해에 매우 취약함 +- 박멸은 `프로세스 종료`만으로 끝나지 않고 `크론/파일/SSH 키`까지 함께 제거해야 재감염을 막을 수 있음 +- 침해 대응 후에는 서비스 정상 여부(`docker ps`, healthcheck)와 보안 후속조치를 같은 작업 단위로 처리해야 함 diff --git a/journey/troubleshooting/260226_51124_openclaw_gateway_상주프로세스_정리.md b/journey/troubleshooting/260226_51124_openclaw_gateway_상주프로세스_정리.md new file mode 100644 index 0000000..3ce11f9 --- /dev/null +++ b/journey/troubleshooting/260226_51124_openclaw_gateway_상주프로세스_정리.md @@ -0,0 +1,38 @@ +# 51124 openclaw-gateway 상주 프로세스 정리 + +**날짜**: 2026-02-26 +**작성자**: admin +**관련 파일**: `/home/admin/.nvm/versions/node/v24.4.0/lib/node_modules/openclaw/package.json`, `/proc/1127450/*` + +--- + +## 문제 상황 +- 메모리 상위 프로세스 점검 중 `openclaw-gateway`(PID 1127458) 발견 +- 51124 운영 대상 서비스 목록(AGENTS.md)에는 `openclaw`가 포함되지 않아 비관리 상주 프로세스로 판단 +- 장기 상주 상태로 메모리 점유 및 운영 혼선 가능성 존재 + +## 사실 확인 +- 시작 시각: `2026-02-05 09:33:48 KST` (`ps -o lstart` 기준) +- 실행 주체: `admin` 계정 SSH 세션(`session-60400.scope`, `SSH_CLIENT=192.228.158.63`) +- 실행 형태: systemd 서비스/크론 등록 없음, 수동 실행 후 orphan 상주 +- 프로세스 체인: `systemd(1) -> openclaw(PID 1127450) -> openclaw-gateway(PID 1127458)` +- 패키지 정체: npm 글로벌 `openclaw@2026.2.2-3` (`description: WhatsApp gateway CLI ...`) + +## 해결 방안 +1. 비관리 프로세스 종료 + - `pkill -f '^openclaw$'` + - `pkill -f 'openclaw-gateway'` +2. 잔여 프로세스/포트 검증 + - `ps`, `pgrep`, `ss -tlnp` 재확인으로 `openclaw` 관련 미검출 확인 +3. 리소스 재확인 + - 종료 전후 메모리 비교에서 `free/available` 증가, swap 사용량 감소 확인 + +## 검증 결과 +- `openclaw`, `openclaw-gateway` 프로세스 미검출 +- openclaw 관련 리슨 포트 미검출 +- 운영 필수 컨테이너(`rb8001`, `skill-*`, `robeing_monitor`) 영향 없음 + +## 교훈 +- 운영 대상 외 프로세스는 발견 즉시 실행 주체/시작 시각/자동실행 경로(systemd·cron)까지 함께 확인해야 함 +- 비관리 상주 프로세스는 종료 후 반드시 `ps/pgrep/ss` 3중 검증으로 잔존 여부를 확인해야 함 +- 운영 문서(DOCS)에 즉시 기록해 동일 유형 이슈 재발 시 판단 시간을 단축해야 함 diff --git a/journey/troubleshooting/260226_NAS_192_168_219_51_접속불가_임시백업복구.md b/journey/troubleshooting/260226_NAS_192_168_219_51_접속불가_임시백업복구.md new file mode 100644 index 0000000..b5ee469 --- /dev/null +++ b/journey/troubleshooting/260226_NAS_192_168_219_51_접속불가_임시백업복구.md @@ -0,0 +1,40 @@ +# 260226 NAS(192.168.219.51) 접속불가 임시 백업 복구 + +## 시간 +- 기준일: 2026-02-26 +- 발생 시각: 2026-02-26 20:4x KST +- 임시 복구 완료: 2026-02-26 20:55 KST + +## 증상 +- `51123`에서 `/mnt/nas` 접근 시 `Host is down` 발생 +- `192.168.219.51`에 `ping` 100% 손실 +- SMB(445) 접근 시 `No route to host` + +## 원인 판정 +- `51123`/`51124` 양쪽에서 동일하게 `192.168.219.51` 불통 확인 +- 로컬 서버(51123) 네트워크 자체는 정상(`192.168.219.1`, `192.168.219.52` 통신 정상) +- 판정: 서버 로컬 이슈가 아니라 NAS 전원/링크/스위치 구간 장애 가능성 높음 + +## 즉시 조치 (백업 공백 방지) +1. 기존 `/mnt/nas` 마운트 해제 +2. 로컬 대체 경로 생성: `/mnt/hdd/nas-fallback/backup/{weekly,current,archives}` +3. bind 마운트 적용: `/mnt/hdd/nas-fallback` -> `/mnt/nas` +4. `weekly-backup.sh` 수동 실행으로 동작 검증 + +## 검증 결과 +- `/mnt/nas/backup/weekly/20260226` 생성 확인 +- `weekly-backup-20260226.log` 기준 백업 완료 크기: `30M` +- 임시 상태에서 주간 백업 크론 경로(`/mnt/nas/backup/weekly`) 정상 유지 + +## 원복 절차 (NAS 복구 후) +1. NAS(192.168.219.51) 통신 복구 확인 (`ping`, SMB 445) +2. `sudo umount /mnt/nas` +3. `sudo mount /mnt/nas` (fstab의 CIFS 원마운트 복귀) +4. `/mnt/nas/backup` 실제 NAS 경로 접근 확인 +5. 임시 데이터(`/mnt/hdd/nas-fallback/backup`)를 NAS로 동기화 후 정리 + +## 참고 +- 기존 NAS 백업 체계 문서: `./250729_서버백업및로그관리체계구축.md` + +## 후속 문서 +- 다음 단계: [260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구](./260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md) diff --git a/journey/troubleshooting/260303_51123_DB5432_차단사고_복구_및_의존포트_점검.md b/journey/troubleshooting/260303_51123_DB5432_차단사고_복구_및_의존포트_점검.md new file mode 100644 index 0000000..68e0dfc --- /dev/null +++ b/journey/troubleshooting/260303_51123_DB5432_차단사고_복구_및_의존포트_점검.md @@ -0,0 +1,140 @@ +# 260303 51123 DB 5432 차단 사고 복구 및 의존 포트 점검 + +## 발생 일시 +- 장애 징후 시작: 2026-03-03 10:59 KST 전후 +- 원인 확인/복구: 2026-03-03 11:18~11:22 KST + +## 문제 요약 +- 51124의 `skill-email`이 `192.168.219.45:5432` 연결 타임아웃으로 `ReadTimeout/500`을 반환. +- 앱 로직 문제가 아니라 DB 접속 경로(포트 5432) 차단으로 인한 네트워크 레벨 장애. + +## 직접 원인 +- 2026-03-03 오전 포트 하드닝 작업 중, UFW의 `5432/tcp` 외부 허용 규칙을 제거함. +- 이때 51124(`192.168.219.52`)의 DB 직접 접근도 함께 차단됨. + +## 사실 확인 (51123) +1. PostgreSQL 리스닝: 정상 +- `ss -lntp` 결과: `0.0.0.0:5432`, `[::]:5432` LISTEN + +2. PostgreSQL 설정: 원격 수신 가능 +- `postgresql.conf`: `listen_addresses='*'`, `port=5432` +- `pg_hba.conf`: `host all all 0.0.0.0/0 scram-sha-256` + +3. 방화벽: 장애 시점 기준 5432 허용 누락 +- `ufw status`에서 `5432` 허용 규칙이 없었음 + +## 조치 +- 최소권한 원칙으로 51124 IP만 5432 허용 재개: + +```bash +sudo ufw allow from 192.168.219.52 to any port 5432 proto tcp +``` + +## 복구 검증 +1. 네트워크 +- 51124 -> 51123 포트 테스트: + - `5432 open` (복구) + - `3000 blocked`, `7474 blocked` (의도된 차단 유지) + - `7687/9000/8100/8000/9200 open` + +2. 컨테이너 내부 +- `skill-email` 컨테이너에서 `192.168.219.45:5432` TCP 연결 성공 (`tcp_ok`). +- `skill-email` 컨테이너에서 `asyncpg`로 `select 1` 성공 (`asyncpg_ok 1`). + +3. 서비스 +- `rb8001 /health` 정상(`200`). +- 장애 핵심 경로였던 DB 접속 타임아웃은 네트워크 기준 해소. + +## 분리 이슈 (별도 추적 필요) +- 복구 후에도 `skill-email`의 `/messages`, `/messages/{id}` 일부 호출에서 `500`이 재현됨. +- 근거: + - DB 네트워크/인증/쿼리 기본 경로는 정상(`5432 open`, `asyncpg_ok 1`). + - 그럼에도 `docker logs skill-email`에 `메시지 조회 중 오류`/`메시지 상세 조회 중 오류`가 지속. +- 판단: 이번 5432 차단 사고와는 별개의 애플리케이션 레이어 오류 가능성이 높음. + +## 분리 이슈 최종 판정 (2026-03-03 11:40 KST) +- 위 "별도 앱 오류"로 분리했던 건 오판이었고, 실제로는 같은 5432 방화벽 영향이었다. +- auth-server 컨테이너 DB 설정: + - `DATABASE_URL=postgresql://robeings:robeings@host.docker.internal:5432/main_db` +- 당시 UFW는 `5432`를 `192.168.219.52`만 허용해서, Docker 브리지(172.17/18/20/21 대역)에서 들어오는 auth-server DB 연결이 차단됨. +- 결과적으로 `auth-server /auth/naverworks/passport/refresh`에서 `asyncpg.connect` `TimeoutError`가 발생했고, 이를 호출하던 `skill-email /messages*`가 연쇄 500. + +### 추가 조치 (최종 복구) +```bash +sudo ufw allow from 172.16.0.0/12 to any port 5432 proto tcp +``` + +### 최종 검증 +- `auth-server` 컨테이너 내부 DB 테스트: `auth_db_ok 1` +- `http://127.0.0.1:9000/auth/naverworks/passport/refresh` 호출: 타임아웃 미발생(즉시 405 반환, 경로 응답 정상) +- 51124 `skill-email` 호출: + - `GET /messages?provider=naverworks&user_id=...&limit=3` -> `200 OK` (약 0.54s) + +## 영향 범위 점검 결과 (51124 -> 51123 의존) +다음 서비스/환경변수들이 `192.168.219.45:5432`를 사용 중: +- `skill_email` +- `skill-calendar` +- `skill-news` +- `skill-rag-file` +- `rb8001` +- `robeing-monitor` +- 일부 `admin-dashboard` 구성(호스트 브리지 기반) + +즉, 5432 차단 시 `skill-email`만이 아니라 위 서비스 전반에서 동일 장애 가능. + +실행중 컨테이너 환경변수 점검 결과(2026-03-03 11:22 KST): +- `rb8001`: `5432`, `7687`, `9000`, `8100` 의존 +- `skill-email`: `5432`, `9000` 의존 +- `skill-calendar`, `skill-slack`, `skill-rag-file`, `robeing_monitor`: `5432` 의존 +- `admin-dashboard-backend`: `172.17.0.1:5432` 의존(호스트 브리지) + +## 재발 방지 +1. 포트 하드닝 전 의존성 체크 필수 +- 51124에서 `192.168.219.45:` 참조를 `.env`/`compose`에서 선조회 + +2. 변경 절차 고정 +- `차단 전`: 의존 포트 목록 작성 +- `차단 직후`: 51124 원격 TCP 매트릭스 테스트 +- `완료 전`: 핵심 서비스 헬스 + 최근 오류로그 교차 확인 + +3. UFW 정책 원칙 +- 전면 허용(`Anywhere`) 대신 **의존 출발지 단위 최소 허용**으로 운영 +- `5432`는 최소 `192.168.219.52` + Docker 브리지 `172.16.0.0/12`를 포함해야 함 + +## 운영 보강: 서버별 마운트 아키텍처 분기 +NAS 관련 장애 점검은 51123/51124가 서로 다른 구조임을 전제로 수행해야 함. + +- 51123: NAS/fallback 구조 + - `/mnt/nas`, `/mnt/hdd/nas-fallback` + - `/etc/fstab`에 CIFS 항목(`//192.168.219.51/home /mnt/nas cifs ...`) +- 51124: sshfs 연계 구조 + - `/mnt/51123data`, `/mnt/51123logs` (sshfs) + - NAS CIFS/fallback 항목 없음 + +즉, 같은 NAS 불통이어도 "경로가 다르다"는 사실 자체는 장애가 아니라 서버별 아키텍처 차이임. + +### NAS 실패 판정 규칙 +- `No route to host`와 `Timeout`은 둘 다 **연결 실패**로 동일 분류한다. +- 에러 문구 차이는 시점/라우팅 상태에 따라 달라질 수 있으므로, 원인 분류 키로 사용하지 않는다. + +### 완료 전 필수 게이트 (고정) +1. 컨테이너 env 기반 의존성 스캔 +2. 51124 -> 51123 포트 매트릭스 (`5432/9000/8100/7687`) +3. 핵심 API 실호출 + - `auth-server /auth/naverworks/passport/refresh` + - `skill-email /messages*` +4. 서버별 스토리지 분기 점검 + - 51123: NAS/fallback 경로 + - 51124: sshfs 경로 + +## 명령어 체크리스트 +```bash +# 51123 +ss -lntp | grep 5432 +sudo ufw status numbered + +# 51124에서 51123 연결 점검 +for p in 5432 3000 7474 7687 9000 8100 8000 9200; do + timeout 2 bash -lc "cat < /dev/null > /dev/tcp/192.168.219.45/$p" && echo "$p open" || echo "$p blocked" +done +``` diff --git a/journey/troubleshooting/260303_51123_gateway_rb8001_연결점검_23서버_전달사항.md b/journey/troubleshooting/260303_51123_gateway_rb8001_연결점검_23서버_전달사항.md new file mode 100644 index 0000000..7bc47af --- /dev/null +++ b/journey/troubleshooting/260303_51123_gateway_rb8001_연결점검_23서버_전달사항.md @@ -0,0 +1,56 @@ +# 23 서버 전달사항: 게이트웨이-8001 연결 점검 결과 + +**날짜**: 2026-03-03 +**작성자**: Codex +**관련 파일**: `robeing-gateway/app/main.py`, `robeing-gateway/app/routers/slack.py`, `robeing-gateway/app/services/slack_proxy.py` + +--- + +## 문제 상황 +- 요청사항: `51124 rb8001(8001) 배포본`이 `51123 robeing-gateway(8100)`를 통해 계획대로 전달되는지 확인. +- 제약: `수정금지` 조건으로 코드/설정 변경 없이 확인만 수행. + +## 확인한 사실 +- 게이트웨이 상태 + - `robeing-gateway` 컨테이너: `Up (healthy)` + - `GET /healthz`: `200 {"status":"ok"}` +- 게이트웨이 대상 설정 + - 컨테이너 환경변수: `ROBEING_DEFAULT_HOST=192.168.219.52`, `ROBEING_DEFAULT_PORT=8001`, `ROBEING_DEFAULT_ID=rb8001` +- Run ID 전파 구현 + - `app/main.py`의 `/api/chat`에서 `X-Run-Id` 생성/전달 및 응답 `run_id` 기본값 주입 확인 + - `app/routers/slack.py` + `app/services/slack_proxy.py`에서 `X-Run-Id` 헤더 생성/전달 확인 + +## 핵심 점검 결과 +- 아키텍처 적합성(게이트웨이 단일 진입) 관점에서 **부분 불일치** 확인. +- 근거: + - 게이트웨이 범용 프록시는 `GET /api/{path:path}`만 존재 (`robeing-gateway/app/main.py`) + - 계획 핵심 신규 API는 `POST` 중심 (`/api/self-improvement/*`, `/api/prompt-db/*`) + - 실제 호출 결과: + - `POST /api/self-improvement/runs` -> `405 Method Not Allowed (allow: GET)` + - `POST /api/prompt-db/templates` -> `405 Method Not Allowed (allow: GET)` + - `POST /api/self-improvement/policy-versions` -> `405 Method Not Allowed (allow: GET)` +- 대조 확인: + - 동일 경로를 rb8001(192.168.219.52:8001)로 직접 호출 시 `401 Unauthorized` 반환 + - 즉, rb8001 경로 자체는 존재하며 인증이 필요한 상태이고, 게이트웨이에서 먼저 `POST`가 차단되고 있음. + +## 부가 관찰 +- Slack 검증 스크립트 실행 시 등록 사용자 이벤트가 `403` 발생. +- 게이트웨이 로그에서 `No bot token found`, `No UUID found`가 함께 관찰됨. +- 이 항목은 신규 self-improvement/prompt-db 경로 이슈와 별개로, Slack 사용자 매핑/토큰 데이터 상태 점검이 필요함. + +## 24서버 전달사항 (rb8001 측 확인 결과) +- `rb8001` 현재 배포 커밋: `54f74d70fc7f2e72368a1ca081d0f52a8dfcba2b` (`Up (healthy)` 확인). +- 신규 경로 존재 확인: + - `POST /api/self-improvement/policy-versions` + - `POST /api/self-improvement/runs` + - `POST /api/prompt-db/templates`, `.../versions`, `.../activate/...`, `POST /api/prompt-db/events` +- DB 테이블 상태: + - `robeing_self_improvement_runs`, `robeing_policy_versions`, `prompt_templates`, `prompt_versions`, `prompt_events`, `prompt_metrics_daily` 모두 생성됨. + - API 직접 호출 시 `self_improvement_runs`/`prompt_events` 적재 정상 확인. +- 유의사항: + - 현재 `/api/message` 호출만으로는 `run_id` 기준 `self_improvement_runs`/`prompt_events` 자동 적재가 연결되지 않음. + - 즉, 현재 기준 자기개선 루프 적재는 API 수동 호출 경로는 동작, 메시지 E2E 자동 폐루프는 미연결 상태. + +## 교훈 +- `51123 gateway`가 단일 진입점인 구조에서는 신규 백엔드 API가 추가될 때 `HTTP method(특히 POST/PUT/DELETE)`까지 포함한 프록시 경로를 동시에 열어야 한다. +- `직접 upstream 성공`과 `gateway 경유 성공`은 별도 검증 항목이므로 배포 완료 판단 전에 둘 다 확인해야 한다. diff --git a/journey/troubleshooting/260303_51123_ufw_외부포트_차단_하드닝.md b/journey/troubleshooting/260303_51123_ufw_외부포트_차단_하드닝.md new file mode 100644 index 0000000..a00a034 --- /dev/null +++ b/journey/troubleshooting/260303_51123_ufw_외부포트_차단_하드닝.md @@ -0,0 +1,70 @@ +# 260303 51123 서버 UFW 외부 포트 차단 하드닝 + +## 발생 일시 +2026-03-03 10:43~10:53 KST + +## 배경 +외부 공개 포트 점검 중, 운영 원칙(외부는 80/443 + 관리 SSH만 공개) 대비 과다 노출이 확인됨. + +## 확인된 원인 +- UFW에서 아래 포트가 `Anywhere`/`Anywhere (v6)`로 허용되어 있었음. + - `5432/tcp` (PostgreSQL) + - `3000/tcp` (Gitea 직접 포트) + - `7474/tcp` (Neo4j HTTP) +- 이 상태는 도메인/nginx 경유가 아닌 직접 포트 접근 경로를 열어두는 구성임. + +## 조치 내용 +실서버(51123)에서 아래 명령으로 공개 허용 규칙 제거: + +```bash +sudo ufw --force delete allow 5432/tcp +sudo ufw --force delete allow 3000/tcp +sudo ufw --force delete allow 7474/tcp +``` + +## 검증 결과 +조치 직후 실시간 검증: + +- 도메인 응답 + - `https://ro-being.com` → `HTTP/2 200` + - `https://git.ro-being.com` → `HTTP/2 200` + - `https://auth.ro-being.com` → `HTTP/2 404` (기존 동작 동일) +- 내부 서비스 헬스 + - `http://127.0.0.1:9000/health` → `200` + - `http://127.0.0.1:8000/health` → `200` +- UFW 규칙 + - `5432/3000/7474`의 `Anywhere`, `Anywhere (v6)` 허용 규칙 삭제 확인 + +## 영향도 +- 사용자 도메인 경유 트래픽 영향 없음 +- `git.ro-being.com` 기반 Gitea 사용 영향 없음 +- 직접 포트 우회 접근 경로만 차단됨 + +## 현재 공개 정책(2026-03-03 기준) +- 외부 공개 유지: `80/tcp`, `443/tcp`, `51123/tcp(관리 SSH)` +- 내부/제한 네트워크 허용: `7687`, `7474(172.17.0.0/16)` + +## 후속 권장 +- Docker 퍼블리시 포트(`8000/8100/8200/9000/9200/9600`)의 외부 노출 축소(가능한 `127.0.0.1` 또는 내부 네트워크만 사용) +- PostgreSQL `listen_addresses`, `pg_hba.conf`를 내부 대역 기반으로 추가 제한 + +## 사후 정정 (2026-03-03 11:40 KST) +초기 차단 조치만으로는 충분하지 않았고, 실제 운영 의존 경로를 일부 누락한 상태였다. + +- 누락된 의존 경로: + - 51124 직접 경로: `192.168.219.52 -> 51123:5432` + - Docker 브리지 경로: `172.16.0.0/12 -> 51123:5432` (예: auth-server `host.docker.internal:5432`) +- 결과: + - `auth-server /auth/naverworks/passport/refresh` 타임아웃 + - `skill-email /messages*` 연쇄 500 + +복구 시 최종 반영한 규칙: + +```bash +sudo ufw allow from 192.168.219.52 to any port 5432 proto tcp +sudo ufw allow from 172.16.0.0/12 to any port 5432 proto tcp +``` + +최종 정책(정정): +- "5432는 무조건 전체 차단"이 아니라, **실제 의존 출발지 단위 최소 허용**이 원칙. +- 하드닝 변경 시 반드시 컨테이너 env 기반 의존성 스캔 + 변경 직후 연계 API 실호출을 완료해야 한다. diff --git a/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md b/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md new file mode 100644 index 0000000..a2f82aa --- /dev/null +++ b/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md @@ -0,0 +1,116 @@ +# 260304 51123 임시복구 서비스 연속성 조치내역 + +## 1. 목적 +- 51124 서버 장애 상황에서 51123 단독으로 robeing 핵심 서비스 연속성을 임시 복구한다. +- 2026-03-04 기준, 내일(2026-03-05) 오전 9시~10시 일정/이메일 경로 중단을 방지한다. + +## 2. 장애 징후 및 운영 영향 +- `/api/message` 응답이 3초 제한 내 타임아웃(`HTTP:000`, `curl (28)`)으로 실패. +- 게이트웨이 경유 일부 경로에서 422/500이 혼재되어 호출 신뢰도가 저하. +- PostgreSQL 연결 슬롯 고갈(Idle 세션 누적)로 신규 작업 지연. +- 51124 불가 상태로 기존 이중서버 가정(23 인프라 + 24 실행)이 깨짐. + +## 3. 확인된 근본 원인 +1. Docker 브리지 대역(`172.21.0.0/16`)에서 호스트 포트(8001, 9024, 8512) 접근이 방화벽에 막혀 내부 연계가 단절됨. +2. PostgreSQL Idle 세션 누적으로 커넥션 풀 여유가 줄어 응답 지연이 증폭됨. +3. rb8001 런타임에서 고비용 경로(의도/검색 그래프 포함)가 활성화된 상태로 느린 경로가 잦게 호출됨. +4. gateway 환경변수 일부가 운영 실IP 기준과 어긋나 헬스/검증 경로가 불안정했음. + +## 4. 실제 조치 내역(51123) +### 4.1 네트워크/방화벽 +- UFW allow 규칙 추가: + - `from 172.21.0.0/16 to any port 8001 proto tcp` + - `from 172.21.0.0/16 to any port 9024 proto tcp` + - `from 172.21.0.0/16 to any port 8512 proto tcp` + +### 4.2 데이터베이스 +- Idle 커넥션 92건 정리(`pg_terminate_backend`)로 슬롯 회복. +- 즉시 재접속 정상화 확인. + +### 4.3 rb8001 성능 안전모드(임시) +- `/home/admin/rb8001/.env` 오버라이드 적용: + - `INTENT_ENGINE=v1` + - `INTENT_USE_LANGGRAPH=false` + - `INTENT_USE_COT=false` + - `WEB_SEARCH_USE_GRAPH=false` +- 적용 방식: `docker compose down && docker compose up -d --build` + +### 4.4 gateway 운영값 정합화 +- `/home/admin/robeing-gateway/.env` 수정: + - `ROBEING_DEFAULT_HOST=192.168.219.45` + - `MONITOR_URL="http://192.168.219.45:9024"` +- 적용 방식: `docker compose down && docker compose up -d --build` + +## 5. 검증 결과(2026-03-04) +1. 컨테이너 상태 +- `robeing-gateway(8100)`, `rb8001(8001)`, `robeing_monitor(9024)`, `skill-calendar(8512)`, `skill-email(8501)` running 확인. + +2. 헬스/응답 +- gateway `/healthz` 200. +- gateway `/api/message` 정상 응답 복구(측정 약 0.5~1.7초 구간). + +3. 핵심 기능 +- 일정성 문구 포함 메시지 요청 시 응답 정상. +- `self-improvement`, `prompt-db`는 유효 스키마 요청에서 성공, 비유효 payload는 기대대로 422/500. + +4. 이메일 경로(내일 9~10시 핵심) +- `skill-email` `/health` 200. +- rb8001 컨테이너 -> skill-email 내부 호출 200. +- NaverWorks 메일 리스트 API(실 UUID `3550cef6-63e1-4ceb-8802-a25c9d1c6917`) 200, 목록 수신 확인. + +5. 스케줄 DB +- `scheduled_jobs` 활성 항목 확인: + - `naverworks_daily`: `0 9 * * mon-fri` + - `coldmail_daily`: `5 9 * * mon-fri` + - `daily_headlines`: `10 9 * * mon-fri` + - `companyx_news`: `0 10 * * mon-fri` + +## 6. 잔여 리스크 및 운영 주의 +- `skill-embedding(8515)` 미기동 상태는 지속. rb8001 로그에 임베딩 연결 에러가 간헐적으로 남을 수 있음. +- 현재 복구는 "핵심 연속성 확보" 기준의 임시 안정화이며, 51124 복구 후 원래 분리구조로 되돌리는 재배치가 필요. +- 스케줄 실행 직전/직후(2026-03-05 08:55~10:10) 구간 모니터링을 강화해야 함. + +## 7. 24 서버 인계 메모 +- 51124 복구 후 우선순위: + 1. rb8001/skill/chromadb 원복 배치 + 2. gateway 대상 upstream 재점검 + 3. 임시 성능 플래그(`INTENT_USE_LANGGRAPH=false` 등) 단계적 해제 여부 성능 측정 후 결정 +- 본 문서는 51123 임시복구 기준 운영 기록이며, 24 원복 시 별도 후속 문서로 분리 기록 권장. + +## 8. 추가 복구/배포 안전화 기록 (2026-03-04 03:00~03:30 KST) +### 8.1 스킬 복구 상태(51123) +- 실행 확인: + - `robeing-skill-news` (`8505`) healthy + - `skill-slack` (`8502`) healthy + - `skill-rag-file` (`8508`) healthy + - `skill-embedding` (`8515`) healthy +- 헬스 응답 확인: + - `GET http://192.168.219.45:8505/health` -> `{"status":"healthy"}` + - `GET http://192.168.219.45:8502/health` -> healthy 응답 + - `GET http://192.168.219.45:8508/healthz` -> healthy 응답 + - `GET http://192.168.219.45:8515/healthz` -> `{"status":"ok"}` + +### 8.2 근본 원인과 조치(embedding) +- 근본 원인: + - `skill-embedding` 재시작 루프 원인은 `/models/onnx/ko-sroberta-multitask/model.onnx` 파일 부재. + - 로그 근거: `FileNotFoundError: ONNX 모델 파일을 찾을 수 없습니다`. +- 조치: + - `jhgan/ko-sroberta-multitask`를 ONNX로 변환해 `model.onnx` 생성. + - 생성 경로: `/home/admin/robeing/onnx_models/ko-sroberta-multitask/model.onnx` (약 423MB). + - 이후 `skill-embedding` `docker compose down && up -d --build`로 정상화. + +### 8.3 배포 안전화(23/24 경로 일반화) 및 푸시 +- `skill-rag-file`: + - `DOCUMENT_MOUNT_ROOT`, `DOCUMENT_BASE_PATH` 기반으로 볼륨/경로를 서버별 `.env` 오버라이드 가능하게 일반화. + - 반영 커밋: `ab3ac78` (`main` 푸시 완료). +- `skill-embedding`: + - `ONNX_MODELS_HOST_PATH` 기반으로 모델 마운트 경로 일반화. + - 24 자동배포 기본값은 `/home/admin/ivada_project/onnx_models`로 고정. + - 23 임시복구는 `.env` 오버라이드로 유지. + - 반영 커밋: `5a0f357`, 추가 교정 `ede5896` (`main` 푸시 완료). + +### 8.4 Gitea workflow 점검 결과 +- 점검 대상: `rb8001`, `skill-news`, `skill-slack`, `skill-email`, `skill-calendar`, `skill-rag-file`, `skill-embedding`, `robeing-monitor`의 `.gitea/workflows/*.yml`. +- 결론: + - 이번 이슈 기준(서버 경로 하드코딩)으로는 workflow YAML 추가 수정 없이 `.env`/compose 일반화로 대응 가능. + - 별도 개선 후보: `skill-calendar` workflow의 `runs-on` 위치가 비표준 구조라 안정성 점검 필요(후속 과제 분리). diff --git a/journey/troubleshooting/260305_23임시배포_envdeploy_ssot_및_배포실패_근본원인_해결.md b/journey/troubleshooting/260305_23임시배포_envdeploy_ssot_및_배포실패_근본원인_해결.md new file mode 100644 index 0000000..de6fae7 --- /dev/null +++ b/journey/troubleshooting/260305_23임시배포_envdeploy_ssot_및_배포실패_근본원인_해결.md @@ -0,0 +1,42 @@ +# 260305 23임시배포 env.deploy SSOT 및 배포실패 근본원인 해결 + +**날짜**: 2026-03-05 +**작성자**: Codex +**관련 파일**: `robeing/skill-rag-file/app/core/config.py`, `robeing/skill-rag-file/.gitea/workflows/deploy.yml`, `robeing/skill-embedding/config.py`, `robeing/robeing-monitor/.gitea/workflows/deploy.yml` + +--- + +## 문제 상황 +- 51124 다운 상태에서 51123 임시운영 중, 일부 스킬 배포가 반복 실패했다. +- `skill-rag-file`, `skill-embedding`은 컨테이너 기동 직후 `ValidationError`로 헬스체크 실패가 발생했다. +- `robeing-monitor`는 배포 스크립트 단계에서 권한 오류로 중단됐다. + +## 확인된 근본 원인 +1. `skill-rag-file`/`skill-embedding` 설정 모델이 `.env`의 추가 키를 허용하지 않아 런타임 시작이 실패했다. +2. 워크플로우의 배포 경로가 서비스별 하드코딩 경로를 사용해 SSOT(`DEPLOY_PROJECT_DIR`)가 깨져 있었다. +3. `robeing-monitor` 배포 스크립트의 `chmod 777 logs`가 실제 권한 정책과 충돌해 즉시 실패했다. + +## 해결 방안 +1. 설정 파서 수정(원인 직접 수정) +- `skill-rag-file/app/core/config.py`: `SettingsConfigDict(..., extra="ignore")` 적용. +- `skill-embedding/config.py`: `SettingsConfigDict(..., extra="ignore")` 적용. + +2. 배포 경로 SSOT 정리 +- `skill-rag-file/.gitea/workflows/deploy.yml`: `cd /home/admin/...` 하드코딩 제거, `DEPLOY_PROJECT_DIR` 사용으로 통일. +- `robeing-monitor/.gitea/workflows/deploy.yml`: 하드코딩 경로 제거, `DEPLOY_PROJECT_DIR` 기반으로 통일. + +3. 권한 충돌 제거 +- `robeing-monitor/.gitea/workflows/deploy.yml`: 실패 원인인 `chmod 777 logs` 제거. + +## 검증 결과 +- `skill-embedding` 최신 커밋 `f89109c` 실행: Gitea Actions `task 2106` `Job succeeded`. +- `skill-rag-file` 최신 커밋 `ddc4693` 실행: Gitea Actions `task 2107` `Job succeeded`. +- `robeing-monitor` 최신 커밋 `c62794c` 실행: Gitea Actions `task 2108` `Job succeeded`. + +## 운영 결론 +- 51123 임시운영 기준 배포 실패 이슈는 해결 완료 상태다. +- 51124 복구 시 코드 수정 없이 각 레포 `.env.deploy`의 배포 대상 값만 24 서버 값으로 전환하면 된다. + +## 교훈 +- 배포 실패는 폴백 추가보다 실패 지점의 단일 원인(설정/권한/경로)을 직접 수정해야 재발이 줄어든다. +- 배포 경로는 서비스별 하드코딩이 아니라 `DEPLOY_PROJECT_DIR` 단일 기준으로 유지해야 운영 전환(23↔24)이 단순해진다. diff --git a/journey/troubleshooting/260305_51124_다운_상태_및_복구예정.md b/journey/troubleshooting/260305_51124_다운_상태_및_복구예정.md new file mode 100644 index 0000000..5bfaa74 --- /dev/null +++ b/journey/troubleshooting/260305_51124_다운_상태_및_복구예정.md @@ -0,0 +1,9 @@ +# 260305 51124 다운 상태 및 복구 예정 + +- 기준일: 2026-03-05 +- 대상 서버: 51124 (192.168.219.52) +- 현재 상태: 다운(미가동) +- 복구 계획일: 2026-03-06 +- 임시 운영 상태: 51123에서 robeing 임시 가동 중 (rb8001, skill 계열) +- 원래 실행 위치: 51124 (robeing/skill 실행 서버) +- 비고: 본 상태/일정은 사용자 운영 지시 기준으로 기록함 diff --git a/journey/troubleshooting/260306_51123_gitea_lfs_permission_denied_502_복구.md b/journey/troubleshooting/260306_51123_gitea_lfs_permission_denied_502_복구.md new file mode 100644 index 0000000..834b7ba --- /dev/null +++ b/journey/troubleshooting/260306_51123_gitea_lfs_permission_denied_502_복구.md @@ -0,0 +1,44 @@ +# 51123 Gitea LFS 권한 오류로 인한 git.ro-being.com 502 복구 + +tags: [gitea, lfs, nas, recovery] + +**날짜**: 2026-03-06 +**작성자**: admin +**관련 파일**: `/etc/gitea/app.ini`, `/etc/nginx/sites-enabled/default` + +--- + +## 문제 상황 +- 2026-03-06 19:04 KST 전후 `https://git.ro-being.com/` 접속 시 `HTTP/2 502` 발생. +- nginx는 `git.ro-being.com`을 `http://localhost:3000/`으로 프록시 중이었고, upstream인 gitea가 비정상 상태였음. + +## 원인 확인 +1. 서비스 상태 +- `systemctl status gitea`에서 `failed (Result: exit-code)` 확인. + +2. gitea 로그 +- `journalctl -u gitea`에서 아래 치명 오류 반복 확인: + - `storage.Init failed: mkdir /mnt/nas/gitea-lfs: permission denied` +- 19:04:28~19:04:31 KST 사이 재시작 반복 후 `Failed to start Gitea` 상태 진입. + +3. 설정 경로 +- `/etc/gitea/app.ini`에서 LFS 저장 경로가 `/mnt/nas/gitea-lfs`로 설정됨. + +## 복구 상태 확인 +- 2026-03-06 19:21:08 KST: `Started Gitea` 로그 확인. +- 현재 `gitea.service`는 `active (running)` 상태. +- 외부 검증: `curl -I https://git.ro-being.com/` 결과 `HTTP/2 200`. + +## 추가 관찰 사항 +- 현재 시점 확인 결과: + - `/mnt/nas`는 `findmnt /mnt/nas` 기준 `not-mounted` + - 디렉터리 권한은 `/mnt/nas`(root:root), `/mnt/nas/gitea-lfs`(git:git) 상태 +- 즉, gitea는 현재 경로 접근은 가능하지만 NAS 마운트 상태와 실제 저장 위치 일치 여부는 별도 운영 점검이 필요함. + +## 교훈 +- Gitea LFS가 NAS 경로를 사용하면, 서비스 기동 전 `마운트 상태 + 대상 디렉터리 소유권`이 동시에 만족되어야 함. +- `502`만 보고 nginx 문제로 단정하면 오판 가능성이 높고, 반드시 `nginx(upstream) + systemd(gitea) + journal`을 같은 시각대로 교차 확인해야 함. +- 스토리지 경로가 마운트 의존일 때는 마운트 해제/권한 변동 감시를 운영 체크리스트에 포함해야 함. + +## 후속 문서 +- 다음 단계: [260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증](./260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md) diff --git a/journey/troubleshooting/260307_51123_성수이전_네트워크변경_운영기록.md b/journey/troubleshooting/260307_51123_성수이전_네트워크변경_운영기록.md new file mode 100644 index 0000000..d4d4b32 --- /dev/null +++ b/journey/troubleshooting/260307_51123_성수이전_네트워크변경_운영기록.md @@ -0,0 +1,18 @@ +# 260307 51123 서버 성수 이전 네트워크 변경 운영기록 + +## 1. 배경 +- 51123 서버 운영 위치가 서울 양재에서 성수로 이전됨. +- 이전 과정에서 공인 IP, 공유기, 내부 사설 IP 대역이 변경됨. +- DNS 설정은 완료했고, 내부 사설 IP 정리 작업을 진행 중임. + +## 2. 현재 기준 주소(운영 사실) +- 51123 임시 운용 서버 내부 사설 IP: `192.168.0.100` +- NAS 내부 사설 IP: `192.168.0.101` + +## 3. 운영 반영 메모 +- 기존 `192.168.219.x` 기준 문서/환경변수/프록시/헬스체크 경로는 순차적으로 `192.168.0.x` 기준으로 정리 필요. +- gateway 및 연계 서비스의 upstream 대상 주소는 실제 바인딩/노출 포트와 함께 재검증 필요. +- NAS 마운트/백업 경로는 `192.168.0.101` 기준으로 재점검 필요. + +## 4. 기록 출처 +- 2026-03-07 사용자 전달 사실 기반 운영 기록. diff --git a/journey/troubleshooting/260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md b/journey/troubleshooting/260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md new file mode 100644 index 0000000..423d460 --- /dev/null +++ b/journey/troubleshooting/260307_Gitea_LFS_NAS_권한정렬_및_실업로드_검증.md @@ -0,0 +1,73 @@ +# 260307 Gitea LFS NAS 권한정렬 및 실업로드 검증 + +tags: [gitea, lfs, nas, cifs, ssot] + +**날짜**: 2026-03-07 +**작성자**: admin +**관련 파일**: `/etc/gitea/app.ini`, `/usr/local/bin/mount-nas-ssot.sh`, `/etc/systemd/system/mount-nas-ssot.service`, `/home/admin/infra-config/runtime.env`, `/home/admin/infra-config/secrets.env` + +--- + +## 문제 상황 +- Gitea는 기동 중이었고 `git.ro-being.com` 일반 Git push/pull도 정상 동작했다. +- 하지만 실제 `git lfs push` 검증에서는 `500 Internal Server Error`로 실패했다. +- 즉 "LFS 경로가 설정돼 있다"와 "실제 대용량 파일 업로드가 된다"가 분리된 상태였다. + +## 검증으로 확인한 사실 +1. 일반 Git 경로는 정상 +- `git push`, `git pull`은 정상 + +2. LFS 경로는 비정상 +- 실제 `git lfs` 업로드 테스트에서 반복적으로 `500` 발생 +- `journalctl -u gitea` 기준 실패 시각(2026-03-07 09:35 KST) 로그: + - `mkdir /mnt/nas/gitea-lfs/18: permission denied` + +3. 근본 원인 +- `gitea.service`는 `git:git (uid=131 gid=138)`로 실행 +- NAS CIFS 마운트는 `uid=1001,gid=1000,file_mode=0755,dir_mode=0755` 기준 +- 결과적으로 `/mnt/nas/gitea-lfs`는 `admin:xusers` 소유처럼 보였고, `git` 사용자는 쓰기 불가 + +## 실제 조치 +### 1. 마운트 권한 정렬 +- `/usr/local/bin/mount-nas-ssot.sh`의 CIFS 옵션을 아래 기준으로 조정 + - `uid=1001` + - `gid=1000` + - `forceuid,forcegid` + - `file_mode=0664` + - `dir_mode=0775` + +### 2. Gitea 실행 사용자 그룹 정렬 +- `git` 사용자를 `xusers` 그룹에 추가 +- 결과: `git` 사용자가 `/mnt/nas/gitea-lfs`에 그룹 쓰기 가능 + +### 3. 서비스 반영 +- NAS 재마운트 실행 +- `gitea.service` 재시작 +- `sudo -u git` 기준 직접 쓰기 테스트 성공 + +## 재검증 결과 +1. 권한 +- `id git` -> `groups=138(git),1000(xusers)` +- `/mnt/nas/gitea-lfs` -> `drwxrwxr-x` + +2. 실업로드 검증 +- `test-meta-skill` 저장소에 임시 브랜치 생성 후 1MB 바이너리 파일을 `git lfs`로 push +- 재클론 후 `git lfs pull` 수행 +- 원본과 재다운로드 파일 SHA256 일치 + +3. NAS 저장 확인 +- 실제 생성 경로: + - `/mnt/nas/gitea-lfs/4a/22/ae83cbb68dcdcddb9e053fdce9466e63463881c981597bb6c797ca4a0f7b` +- 검증 시점 기준 LFS 파일 수: + - before=0 + - after_push=1 + - after_pull=1 + +## 결론 +- 현재 Gitea LFS는 설정상 연결된 수준이 아니라, 실제로 NAS에 대용량 파일을 저장하는 상태까지 검증 완료됐다. +- 이번 조치로 `git lfs push -> Gitea -> /mnt/nas/gitea-lfs` 경로가 실동작함을 확인했다. +- 이후 동일 계열 문제 재발 시, `Gitea 상태`보다 먼저 `gitea 실행 사용자`와 `NAS 마운트 권한`을 함께 봐야 한다. + +## 전후 관계 문서 +- 이전: [260306_51123_gitea_lfs_permission_denied_502_복구](./260306_51123_gitea_lfs_permission_denied_502_복구.md) +- 관련: [260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구](./260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md) diff --git a/journey/troubleshooting/260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md b/journey/troubleshooting/260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md new file mode 100644 index 0000000..fd4f074 --- /dev/null +++ b/journey/troubleshooting/260307_NAS_192_168_0_101_SSOT_전환_및_CIFS_실마운트_복구.md @@ -0,0 +1,74 @@ +# 260307 NAS(192.168.0.101) SSOT 전환 및 CIFS 실마운트 복구 + +## 시간 +- 기준일: 2026-03-07 +- 작업 시각: 2026-03-07 오전 + +## 배경 +- 서버 이전 후 NAS 내부 사설 IP가 `192.168.219.51`에서 `192.168.0.101`로 변경되었다. +- 51123은 임시운영 상태에서 `/mnt/nas`를 다시 실NAS로 연결해야 했고, 동시에 SSOT 원칙에 맞게 NAS 설정을 정리할 필요가 있었다. +- 기존 `/mnt/nas`는 실제 마운트가 아니라 로컬 디렉터리처럼 남아 있었고, `weekly-backup.sh`가 기대하는 `/mnt/nas/backup/weekly`도 실NAS 기준으로는 정합성이 깨져 있었다. + +## 확인된 사실 +1. `192.168.0.101`은 실제 응답하는 NAS였다. +- `ping` 정상 응답 +- `22/80/443/139/445/5000/5001` 포트 오픈 확인 +- `5000/5001` 응답 기준 Synology DSM 장비 확인 + +2. NAS 내부에는 기존 백업 구조가 남아 있었다. +- `home` 공유 접근 가능 +- `backup/current/{robing,gitea,config}` 존재 +- `gitea-lfs` 디렉터리 존재 + +3. 서버 쪽 마운트 설정은 구식 값이 남아 있었다. +- `/etc/fstab`에 `//192.168.219.51/home /mnt/nas cifs username=admin,password=...` 형태의 평문 설정 존재 +- 이는 이전 IP 기준이며, SSOT 원칙에도 맞지 않았다. + +## 실제 조치 +### 1. NAS 접근 확인 +- `smbclient -L //192.168.0.101 -U admin%...` 로 `home`, `homes` 공유 확인 +- `smbclient //192.168.0.101/home ...` 로 `backup`, `gitea-lfs` 실제 존재 확인 + +### 2. SSOT 반영 +- `/home/admin/infra-config/runtime.env` + - `NAS_HOST=192.168.0.101` + - `NAS_SMB_PORT=445` + - `NAS_SHARE=home` + - `NAS_MOUNT_PATH=/mnt/nas` +- `/home/admin/infra-config/secrets.env` + - `NAS_USERNAME=admin` + - `NAS_PASSWORD=...` + +### 3. 마운트 방식 교체 +- `/etc/fstab`의 평문 CIFS 항목은 주석 처리 +- `/usr/local/bin/mount-nas-ssot.sh` 생성 + - `runtime.env`, `secrets.env`를 읽어 CIFS 마운트 수행 +- `/etc/systemd/system/mount-nas-ssot.service` 생성 및 enable + - 부팅 후 SSOT 기준으로 NAS 마운트 복구 가능하도록 구성 + +### 4. 권한 정합화 +- 초기 마운트는 `uid=1000` 기준이라 현재 사용자 `admin(uid=1001)`가 쓰기 불가 +- 마운트 옵션을 `uid=1001,gid=1000`으로 교정 +- 이후 `/mnt/nas/backup/weekly` 생성 및 쓰기 가능 확인 + +## 검증 결과 +1. 마운트 상태 +- `//192.168.0.101/home on /mnt/nas type cifs` 확인 +- `df -h /mnt/nas` 기준 5.3T 마운트 정상 + +2. 구조 확인 +- `/mnt/nas/backup/current` +- `/mnt/nas/backup/archives` +- `/mnt/nas/gitea-lfs` + +3. 쓰기 확인 +- `/mnt/nas/backup/weekly/latest.txt` 생성 및 기록 성공 + +## 결론 +- 51123의 `/mnt/nas`는 다시 실NAS(`192.168.0.101`)를 바라보도록 복구되었다. +- NAS 접속 정보는 `infra-config/runtime.env` + `secrets.env` 기준으로 SSOT화되었다. +- 기존 `nas-fallback` 임시 우회 상태에서 한 단계 진전했지만, fallback 데이터 동기화 여부는 별도 점검이 필요하다. + +## 전후 관계 문서 +- 이전: [260226_NAS_192_168_219_51_접속불가_임시백업복구](./260226_NAS_192_168_219_51_접속불가_임시백업복구.md) +- 관련: [260307_51123_성수이전_네트워크변경_운영기록](./260307_51123_성수이전_네트워크변경_운영기록.md) diff --git a/journey/troubleshooting/260307_gateway_SSOT_runtime_secrets_분리_적용_및_검증.md b/journey/troubleshooting/260307_gateway_SSOT_runtime_secrets_분리_적용_및_검증.md new file mode 100644 index 0000000..ebad0b2 --- /dev/null +++ b/journey/troubleshooting/260307_gateway_SSOT_runtime_secrets_분리_적용_및_검증.md @@ -0,0 +1,76 @@ +# 260307 gateway SSOT(runtime/secrets) 분리 적용 및 검증 + +## 1. 목적 +- 51123 임시 운용 환경에서 분산된 설정값을 1차 정리한다. +- 우선순위가 높은 `robeing-gateway`부터 `runtime.env`(비민감)와 `secrets.env`(민감)로 분리 적용한다. + +## 2. 변경 사항 +### 2.1 SSOT 파일 신설 +- `/home/admin/infra-config/runtime.env` 생성 + - 운영 비민감값(예: `HOST_51123`, `NAS_HOST`, `ROBEING_DEFAULT_HOST`, `MONITOR_URL`) 관리 +- `/home/admin/infra-config/secrets.env` 생성 + - 민감값(예: `DATABASE_URL`, `JWT_SECRET_KEY`) 관리 + +### 2.2 권한 적용 +- `runtime.env`: `640` +- `secrets.env`: `600` +- 디렉터리 `/home/admin/infra-config`: `750` + +### 2.3 게이트웨이 참조 경로 변경 +- 대상: `/home/admin/robeing-gateway/docker-compose.yml` +- `env_file` 순서: + 1. `/home/admin/infra-config/runtime.env` + 2. `/home/admin/infra-config/secrets.env` + 3. `.env` (임시 오버라이드 전용) + +### 2.4 기존 게이트웨이 `.env` 정리 +- 대상: `/home/admin/robeing-gateway/.env` +- 실값 제거 후, “로컬 오버라이드 전용” 안내만 유지 + +## 3. 검증 결과 +### 3.1 설정 파싱 검증 +- `docker compose -f /home/admin/robeing-gateway/docker-compose.yml config` 성공 + +### 3.2 재가동 검증 +- 실행: `docker compose down && docker compose up -d --build` +- 결과: `robeing-gateway` `Up (healthy)` 확인 + +### 3.3 기능 검증 +- `GET http://127.0.0.1:8100/healthz` -> `200` +- 도메인 경유 `/gateway/api/config` -> 미인증 요청 `401` (정상 인증 경계) +- `gateway -> 192.168.0.100:8001/health` -> `200` +- `gateway -> 192.168.0.100:9024/healthz` -> `200` + +## 4. 결론 +- 기존 무응답 핵심 원인이었던 연결 단절 상태는 해소됨. +- 현재 `/api/message` 응답 경계는 연결 실패가 아니라 인증(`401`) 단계로 정상 전환됨. +- SSOT 분리는 `robeing-gateway`에 1차 적용 완료, 나머지 서비스는 동일 패턴으로 순차 이전 필요. + +## 5. 후속 적용: robeing-monitor SSOT 분리 및 9024 복구 +### 5.1 변경 사항 +- 대상: `/home/admin/robeing/robeing-monitor` +- `docker-compose.yml`이 `/home/admin/infra-config/runtime.env`, `/home/admin/infra-config/secrets.env`를 우선 참조하도록 변경 +- 기존 `.env`는 로컬 오버라이드 전용 안내만 유지 +- `app/core/config.py` 기본 DB 호스트를 현재 운영 기준 `192.168.0.100`으로 교정 +- `infra-config`에 아래 값을 추가 + - `ROBEING_MONITOR_PORT` + - `ROBEING_MONITOR_LOG_LEVEL` + - `ROBEING_MONITOR_DATABASE_URL` + - `ROBEING_URLS` + - `SKILL_URLS` + +### 5.2 증상 +- 적용 전 `robeing_monitor` 컨테이너는 `unhealthy` +- `curl http://127.0.0.1:9024/healthz` 타임아웃 +- Docker healthcheck도 동일하게 `Health check exceeded timeout (10s)` 반복 + +### 5.3 검증 결과 +- `docker compose -f /home/admin/robeing/robeing-monitor/docker-compose.yml config` 성공 +- 실행: `docker compose down && docker compose up -d --build` +- 결과: `robeing_monitor` `Up (healthy)` 확인 +- `GET http://127.0.0.1:9024/healthz` -> `200` + +### 5.4 결론 +- `robeing-monitor`도 SSOT 기반으로 1차 이전 완료 +- 9024 응답 정지 상태는 해소됐고, 현재 헬스체크 정상 +- 51123 임시 운용 핵심 경로는 `gateway`, `rb8001`, `robeing-monitor`까지 정상 응답 기준으로 복구됨