docs: migrate infrastructure troubleshooting from robeing

This commit is contained in:
Claude 2026-03-09 18:36:33 +09:00
parent 715e134a64
commit ef666e6fc0
17 changed files with 974 additions and 0 deletions

View File

@ -19,6 +19,22 @@
- 실행 중 문제가 생기면 `worklog`가 아니라 `troubleshooting`으로 기록합니다. - 실행 중 문제가 생기면 `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) - [51123 구 IP 하드코딩과 런타임 SSOT 불일치 이슈](./troubleshooting/260309_51123_구IP하드코딩_런타임SSOT불일치_이슈.md)
- [24서버 우분투 터미널 불가, 네트워크 대역 오류, python3-apt 복구 기록](./troubleshooting/260309_24서버_우분투터미널불가_네트워크대역오류_python3apt복구.md) - [24서버 우분투 터미널 불가, 네트워크 대역 오류, python3-apt 복구 기록](./troubleshooting/260309_24서버_우분투터미널불가_네트워크대역오류_python3apt복구.md)
- [23서버 워크스페이스 인프라 구조정리 이슈](./troubleshooting/260307_23서버_워크스페이스_인프라_구조정리_이슈.md) - [23서버 워크스페이스 인프라 구조정리 이슈](./troubleshooting/260307_23서버_워크스페이스_인프라_구조정리_이슈.md)

View File

@ -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` 기준 유지.

View File

@ -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` 룰 정리 및 화이트리스트 검증

View File

@ -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)와 보안 후속조치를 같은 작업 단위로 처리해야 함

View File

@ -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)에 즉시 기록해 동일 유형 이슈 재발 시 판단 시간을 단축해야 함

View File

@ -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)

View File

@ -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:<port>` 참조를 `.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
```

View File

@ -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 경유 성공`은 별도 검증 항목이므로 배포 완료 판단 전에 둘 다 확인해야 한다.

View File

@ -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 실호출을 완료해야 한다.

View File

@ -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` 위치가 비표준 구조라 안정성 점검 필요(후속 과제 분리).

View File

@ -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)이 단순해진다.

View File

@ -0,0 +1,9 @@
# 260305 51124 다운 상태 및 복구 예정
- 기준일: 2026-03-05
- 대상 서버: 51124 (192.168.219.52)
- 현재 상태: 다운(미가동)
- 복구 계획일: 2026-03-06
- 임시 운영 상태: 51123에서 robeing 임시 가동 중 (rb8001, skill 계열)
- 원래 실행 위치: 51124 (robeing/skill 실행 서버)
- 비고: 본 상태/일정은 사용자 운영 지시 기준으로 기록함

View File

@ -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)

View File

@ -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 사용자 전달 사실 기반 운영 기록.

View File

@ -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)

View File

@ -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)

View File

@ -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`까지 정상 응답 기준으로 복구됨