프로젝트

일반

사용자정보

Actions

결함 #1

진행중

서버 운영 작업 로그 (Claude Code)

이 도현이(가) 약 22시간 전에 추가함. 40분 전에 수정됨.

상태:
신규
우선순위:
보통
담당자:
-
시작시간:
2026-07-27
완료기한:
진척도:

0%

추정시간:

설명

Claude Code와 함께 진행하는 leedohyun.com 서버 운영/인프라 작업 기록. 작업할 때마다 이 이슈에 노트가 追加됩니다.

Actions #1

이 도현이(가) 약 22시간 전에 변경

2026-07-27 CI/CD 자동화 + gateway 안정화

  • ci-gateway-deployer RBAC + 제한 kubeconfig 생성
  • GitHub self-hosted runner 설치 (systemd 서비스)
  • gateway 워크플로에 deploy job 추가 (SHA 태그 + rollout status)
  • spring-cloud-gateway 30일간 CrashLoopBackOff 원인 파악 및 해결 (actuator 의존성 누락)
  • router.leedohyun.com -> leedohyun.asuscomm.com:8443 프록시 라우트 추가
  • JwtAuthenticationFilter가 router.leedohyun.com까지 인증 요구하던 버그 수정
  • SetRequestHeader X-Forwarded-For 템플릿 치환 500 에러 수정

commit: 6635e92, 35b62cd, 3452e70, d159a5a

Actions #2

이 도현이(가) 약 22시간 전에 변경

2026-07-27 작업 마무리 요약

1. 서버 환경 문서화
  • ~/msa/CLAUDE.md 신규 작성 — 하드웨어/K3s 구성/배포 서비스/알려진 문제/소스-이미지-배포 파이프라인 전부 정리

2. 인프라 정리
  • ~/.git (실수로 홈 디렉토리에 생긴 빈 저장소) 삭제
  • ~/gateway (죽은 GitLab 원격을 물고 있던 유령 클론, GitHub와 히스토리 전혀 안 겹침 확인 후) 삭제
  • Traefik 중복 설치, PVC 3개 Terminating 상태(314일째) 등 기존 이슈 문서화

3. 이메일 기능 완전 정리 (실익 없음 판단)
  • Route 53: MX/DKIM 레코드 삭제, SPF -all / DMARC p=reject 로 전환 (스푸핑 방지, 메일 미사용)
  • 라우터 포트포워딩: SMTP, IMAP, POP3, 용도불명 81/9000, Keycloak 직접노출 8081, DB range(8001-8010) 전부 삭제 → HTTP/HTTPS/SSH 3개만 남김

4. CI/CD 자동화 구축
  • ci-gateway-deployer 전용 RBAC + 제한된 kubeconfig 생성 (gateway Deployment 외 접근 불가하도록 스코프 제한, 실제 권한 검증 완료)
  • GitHub self-hosted runner 설치 (systemd 서비스로 등록, gateway 저장소 전용, k3s-home 레이블)
  • gateway 워크플로에 deploy job 추가 — build에서 SHA 태그도 함께 push, deploy job이 kubectl set image + rollout status 실행
  • 파이프라인 실제 동작 검증 완료 (여러 차례 push → 자동 빌드/배포 확인, 실패 시 정상적으로 CI 실패 처리되는 것도 확인)

5. spring-cloud-gateway 30일 CrashLoopBackOff 해결
  • 원인: build.gradle에 spring-boot-starter-actuator 의존성이 없어서 liveness/readiness probe가 보는 /actuator/health가 404 -> 계속 재시작
  • actuator 의존성 추가로 완전히 해결, 2/2 Ready 정상화

6. router.leedohyun.com 프록시 라우트 추가
  • 목표: https://router.leedohyun.com/ 접속 시 게이트웨이가 홈 라우터 관리화면(leedohyun.asuscomm.com:8443)으로 프록시
  • 해결: JwtAuthenticationFilter 전역 인증 필터가 이 라우트까지 막던 문제 (PUBLIC_HOSTS에 추가)
  • 해결: SetRequestHeader=X-Forwarded-For 템플릿 치환이 헤더 없을 때 500 에러 내던 문제 (불필요한 필터 제거)
  • 미해결: 게이트웨이가 라우터 TLS 인증서 체인을 검증하지 못해 500 에러 (SunCertPathBuilderException). 다음 세션 작업 예정

7. 발견한 구조적 이슈 (TODO로 기록)
  • Traefik Ingress가 대부분 도메인(wordpress/tool/keycloak/minio/redmine/architecture)을 게이트웨이 없이 각 서비스로 직접 라우팅 중 -> 게이트웨이 앱의 해당 라우트 정의는 전부 죽은 코드
  • 사용자 계획: Spring Cloud Gateway를 모든 트래픽의 진짜 단일 진입점으로 전환 예정 (아직 미착수, ~/msa/CLAUDE.md TODO 섹션 및 auto-memory에 기록)

8. 작업 기록 체계
  • Redmine API 연동 완료 (본 이슈에 계속 기록)

commits: 6635e92, 35b62cd, 3452e70, d159a5a (github.com/lee-dohyun/gateway)

Actions #3

이 도현이(가) 약 15시간 전에 변경

router.leedohyun.com TLS 인증서 문제 해결

  • 원인: leedohyun.asuscomm.com:8443이 Let's Encrypt가 아니라 ASUS 자체 자가서명 인증서(RT-AX57-7D38 Root Certificate)를 서빙 -> JVM 기본 트러스트 매니저가 거부(SunCertPathBuilderException)
  • 조치: 해당 인증서를 openssl로 추출해 gateway 리소스에 포함(router-admin-ca.pem), spring.cloud.gateway.httpclient.ssl.trustedX509Certificates로 신뢰하도록 설정
  • 결과: https://router.leedohyun.com/ 정상 200 응답, 라우터 로그인 화면(Main_Login.asp)으로 정상 연결 확인
  • commit: 224035c

이걸로 router.leedohyun.com 프록시 작업 완전히 마무리됨.

Actions #4

이 도현이(가) 약 15시간 전에 변경

2026-07-27 세션 마무리 — 브라우저 인증서 경고 발견 및 원인 파악, 조치 진행 중

문제

원인
  • default 네임스페이스의 leedohyun-wildcard-tls 는 이름과 달리 진짜 와일드카드 인증서가 아니라, WordPress 도메인(leedohyun.com/www/blog/wordpress) 4개만 SAN에 포함된 전용 인증서였음
  • 게이트웨이 Ingress가 이 시크릿을 재사용했지만 gateway.leedohyun.com / router.leedohyun.com 은 SAN에 없어서 Traefik이 매칭 인증서를 못 찾고 자체 기본 인증서(TRAEFIK DEFAULT CERT)로 fallback
  • ~/msa/CLAUDE.md 에 이 함정 문서화 완료 (향후 새 도메인 추가 시 재발 방지)

조치 (진행 중)
  • spring-cloud-gateway-ingress 의 secretName 을 leedohyun-wildcard-tls -> gateway-router-tls (전용) 로 변경
  • cert-manager 가 letsencrypt-dns 이슈어로 gateway.leedohyun.com, router.leedohyun.com 전용 인증서 신규 발급 중 (DNS-01 챌린지, 세션 종료 시점 기준 아직 Ready=False, 발급 대기 중)

다음 세션에서 이어서 할 것
  1. kubectl get certificate gateway-router-tls -n default 로 Ready=True 확인
  2. 브라우저에서 https://router.leedohyun.com/ 재접속해서 인증서 경고 없이 정상 로그인 화면 뜨는지 최종 확인

commit: 224035c (이전 세션에서 push된 상태 유지, 이번 조치는 K8s Ingress 리소스만 변경, 소스 push 없음)

Actions #5

이 도현이(가) 약 15시간 전에 변경

gateway-router-tls 인증서 발급 완료 — router.leedohyun.com 최종 정상화

  • Let's Encrypt가 gateway.leedohyun.com, router.leedohyun.com 두 도메인 포함한 정식 인증서 발급 완료 (cert-manager DNS-01, letsencrypt-dns 이슈어)
  • curl 검증 시 -k(인증서 검증 무시) 옵션 없이도 정상 200 응답 확인 -> 브라우저에서도 인증서 경고 없이 정상 접속될 것
  • 이걸로 router.leedohyun.com 프록시 작업 (JWT 필터, 500 에러, TLS 신뢰, 인증서 발급) 전체 완전히 종료

오늘 세션 전체 작업 완료.

Actions #6

이 도현이(가) 약 4시간 전에 변경

router.leedohyun.com 로그인 루프 해결 (최종)

  • 증상: 인증서/헬스체크 문제 다 해결 후에도 로그인 시도 시 계속 Main_Login.asp로 튕김
  • 원인: ASUS 라우터 펌웨어가 로그인(login.cgi) 요청의 Host/Origin/Referer가 자기 자신이 아는 도메인(leedohyun.asuscomm.com)과 일치하는지 검사(CSRF/DNS 리바인딩 방지). 게이트웨이가 브라우저 원본 헤더(router.leedohyun.com)를 그대로 전달해서 위조 요청으로 판단, 에러 없이 조용히 로그인 페이지로 되돌림
  • 조치: router-admin 라우트에 Host/Origin/Referer를 백엔드 실제 값으로 강제하는 SetRequestHeader 필터 추가 (commit bd4e7cb, dc01e0c)
  • 사용자 확인: 로그인 정상 작동
  • ~/msa/CLAUDE.md에 일반화된 패턴으로 문서화 완료 ("외부 관리 UI를 게이트웨이로 프록시할 땐 Host/Origin/Referer를 백엔드 기준으로 강제할 것") - 향후 NAS 등 비슷한 프록시 작업 시 재발 방지

router.leedohyun.com 프록시 작업 이걸로 완전히 종료.

Actions #7

이 도현이(가) 약 4시간 전에 변경

게이트웨이 단일 진입점 전환 - 진행 상황

사전 준비 (완료)
  • JwtAuthenticationFilter allow-by-default로 재설계 (PROTECTED_HOSTS=customer.localhost만)
  • application.yml 라우트 URI 전부 FQDN으로 수정 (네임스페이스 짧은 이름 DNS 해석 안 되던 버그)
  • SetRequestHeader={request.headers.X} 템플릿 필터 전부 제거 (헤더 없으면 500 나던 버그, 7개 라우트 전부 해당)
  • wordpress/redmine 라우트의 multi Host predicate AND 결합 버그 수정 (OR로는 콤마 구분 필요)
  • commits: d37df64, f0d5441

도메인별 전환 (진행 중)
  • architecture.leedohyun.com: 전환 완료 + 부수적으로 230일간 멈춰있던 별개의 롤아웃 버그도 발견/해결 (build.gradle 아님, architecture-web Deployment가 architecture-web:latest 로컬 이미지를 못 받아와서 nginx로 계속 fallback 중이었음). 소스를 github.com/lee-dohyun/architecture-web (브랜치명 architecture)로 신규 이관, CI 구성, leedohyun1985/architecture-web:latest로 정식 배포 완료. 실제 Flask 렌더링 페이지 정상 확인
  • tool.leedohyun.com: 전환 완료. cross-namespace Ingress 제약으로 default 네임스페이스에 전용 Ingress+인증서 새로 발급하는 방식으로 처리 (tool 네임스페이스의 다른 서비스들도 동일 패턴 필요)
  • 남은 것: minio(static/console), redmine, wordpress, keycloak(마지막)

commits: bd4e7cb, dc01e0c, e4beac3

Actions #8

이 도현이(가) 약 4시간 전에 변경

게이트웨이 단일 진입점 전환 - 완료

모든 *.leedohyun.com 도메인의 Ingress backend가 spring-cloud-gateway-service로 통일됨. kubectl get ingress -A로 확인 완료.

도메인별 전환 결과
  • architecture.leedohyun.com - 완료 (+230일 묵은 배포 버그 발견/해결, Flask 정식 배포로 전환, github.com/lee-dohyun/architecture-web 신규 저장소)
  • tool.leedohyun.com - 완료
  • static.leedohyun.com, minio.leedohyun.com - 완료
  • alm.leedohyun.com, redmine.leedohyun.com - 완료
  • leedohyun.com/www/blog/wordpress.leedohyun.com - 완료
  • keycloak.leedohyun.com - 완료 (OIDC issuer URL 정상 확인, SSO 영향 없음 검증)

구조적으로 남긴 것
  • Ingress는 backend와 같은 네임스페이스여야 하는 K8s 제약 때문에 tool/keycloak/minio/redmine은 default 네임스페이스에 전용 Ingress+인증서로 재구성 (원래 네임스페이스 Ingress는 검증 후 삭제)
  • ~/msa/CLAUDE.md에 전체 과정, 발견한 버그, 재발 방지 패턴 전부 문서화

commits: d37df64, f0d5441, bd4e7cb, dc01e0c, e4beac3 (gateway), 신규 저장소 lee-dohyun/architecture-web

오늘 진행한 큰 작업(CI/CD 자동화 + 게이트웨이 단일 진입점 전환) 전부 완료.

Actions #9

이 도현이(가) 약 3시간 전에 변경

blog.leedohyun.com 무한 리다이렉트 해결 + PVC 데이터 손실 위험 사전 차단

1. blog.leedohyun.com 원인/해결
  • 진짜 원인: 게이트웨이가 클러스터 내부 라우팅 시 원본 Host 헤더를 보존하지 않고 대상 서비스 이름(wordpress-service)으로 덮어써서 전달 (X-Forwarded-Host는 정확했음)
  • Keycloak이 문제없었던 이유: 게이트웨이가 Host를 잘 보존해서가 아니라 Keycloak 자체가 X-Forwarded-Host를 자동으로 신뢰하기 때문. WordPress는 안 그래서 문제 발생
  • 해결: wp-config.php(WORDPRESS_CONFIG_EXTRA)에 X-Forwarded-Host -> Host 승격 스니펫 추가
  • 결과: leedohyun.com/www/blog/wordpress.leedohyun.com 4개 도메인 전부 정상 (blog가 canonical, 나머지는 blog로 301 후 200 - 의도된 동작)
  • ~/msa/CLAUDE.md에 일반화 패턴으로 문서화 (게이트웨이 뒤에 Host 기반 검증하는 새 서비스 붙일 때 참고)

2. PVC 데이터 손실 위험 발견 및 차단 (중요)
  • wordpress-pvc가 314일째 Terminating(예전 kubectl delete pvc가 finalizer에 걸려 못 지워짐)이라 재배포가 막혀있었음
  • 회수 정책이 Delete라서, 그대로 재배포 시도했으면 실제 블로그 데이터가 영구 삭제될 뻔함 -> 발견 즉시 Retain으로 변경 후 안전하게 복구 진행
  • 복구 절차: PV reclaimPolicy Retain 변경 -> 파드 scale 0 (PVC 삭제 완료, PV는 Released로 생존) -> claimRef 제거 -> volumeName 지정해서 새 PVC 생성(기존 데이터에 재바인딩) -> 파드 복구. 데이터 손실 없이 완료 확인
  • 이 사건을 계기로 클러스터의 PV 7개 전부(wordpress/mysql/redis/keycloak-postgresql/redmine-mysql/redmine-data/minio) reclaimPolicy를 Retain으로 통일 -> 앞으로 비슷한 사고 원천 차단
  • 남은 것: mysql-pvc, redis-pvc는 여전히 Terminating 상태(재배포 필요해지면 같은 절차로 복구 필요) - 위험은 없어졌지만 Terminating 자체는 안 풀림

Actions #10

이 도현이(가) 약 3시간 전에 변경

mysql-pvc, redis-pvc Terminating 문제도 완전 정리

wordpress-pvc와 동일한 절차로 처리:
  • mysql-pvc: 데이터 무결성 확인 완료 (wp_posts 발행글 50개, siteurl/home 정상)
  • redis-pvc: 정상 기동, PING -> PONG 확인

클러스터 전체 PVC 중 Terminating 상태인 것 이제 0개. 전부 Retain 정책 적용된 상태로 안전하게 정리 완료.

오늘 세션에서 발견/해결한 것 전체 요약:
  1. CI/CD 자동화 구축 (self-hosted runner, deploy job)
  2. spring-cloud-gateway 30일 CrashLoopBackOff 해결
  3. router.leedohyun.com 프록시 (JWT/500/TLS/로그인루프 4단계 버그 해결)
  4. 게이트웨이 단일 진입점 전환 (6개 도메인 + 다수 숨은 버그 발견/수정)
  5. architecture-web 230일 배포 버그 해결 + 신규 GitHub 저장소
  6. blog.leedohyun.com 무한 리다이렉트 해결 (Host/X-Forwarded-Host 문제)
  7. PVC Terminating 3개 전부 데이터 손실 없이 복구 + 클러스터 전체 PV Retain 정책 통일

오늘 작업 전체 완전히 마무리.

Actions #11

이 도현이(가) 약 2시간 전에 변경

auth.api용 PostgreSQL + Redis 인프라 구축 (customer 네임스페이스 신규)

  • github.com/lee-dohyun/auth.api 소스 조사 후 실제 기대값(DB_HOST/PORT/NAME/USER/PASSWORD)에 맞춰 PostgreSQL 15 구축 (DB: authdb, 계정: authuser)
  • Redis 7도 함께 구축 (auth.api는 아직 미사용, 향후 customer 라인 공유 용도로 선제 준비)
  • PVC 생성 즉시 PV Retain 정책 적용 (오늘 겪은 교훈 반영)
  • 외부 접속: SSH 터널 방식으로만 허용 (라우터 포트 추가 안 함, DB를 인터넷에 직접 노출하지 않는 방향 선택)
  • 매니페스트: ~/msa/customer/postgres.yaml, redis.yaml
  • 모두 접속 검증 완료 (psql conninfo, redis PING)

이번 작업 범위는 데이터 계층만, auth.api 앱 자체 배포는 별도 작업으로 남겨둘. auth.api를 실제 배포할 때 JWT 서명키 영속화 문제(레플리카 스케일 전 선해결 필요)도 CLAUDE.md에 메모해둘.

Actions #12

이 도현이(가) 약 한시간 전에 변경

진짜 와일드카드 인증서 통일 + architecture 저장소 정리 + favicon 추가

1. 와일드카드 인증서 통일
  • default 네임스페이스에 leedohyun-real-wildcard Certificate 신규 생성 (*.leedohyun.com + leedohyun.com, DNS-01)
  • 8개 Ingress 전부 이 시크릿(leedohyun-real-wildcard-tls) 하나로 통일, 예전 개별 인증서/시크릿 전부 삭제
  • 사고 발생 및 복구: Ingress에 남아있던 cert-manager.io/cluster-issuer 어노테이션 때문에 ingress-shim이 같은 시크릿 이름으로 좁은 인증서(architecture.leedohyun.com 하나짜리)를 자동 생성해서 와일드카드를 덮어씀 -> 어노테이션 전부 제거 + 시크릿 삭제 후 재발급으로 완전 복구, 전 도메인 재검증 완료
  • 자동 갱신은 cert-manager가 원래 담당하는 기본 기능이라 별도 설정 불필요함을 확인/안내

2. architecture-web 저장소 이름 변경
  • github.com/lee-dohyun/architecture-web -> architecture 로 저장소명 변경, 기본 브랜치도 architecture -> main 으로 변경, 워크플로 트리거도 맞춤
  • K8s 리소스명(Deployment/Service)과 Docker Hub 이미지명은 그대로 architecture-web 유지 (저장소명만 변경됨, 혼동 주의 문서화)

3. architecture.leedohyun.com favicon 추가
  • blog.leedohyun.com과 동일한 favicon(32x32, 192x192, apple-touch-icon) 적용, Flask static 폴더로 이관
  • 배포 및 실제 응답 확인 완료

~/msa/CLAUDE.md 전체 반영 완료.

Actions #13

이 도현이(가) 40분 전에 변경

[auth.api Keycloak 위임 전환 완료]

- Keycloak customer realm + auth-api-backend 클라이언트(Direct Access Grant + 서비스 계정) 구성
- auth.api: 자체 JWT 서명/BCrypt/DB 인증 로직 전부 제거, KeycloakClient로 로그인/회원가입을 Keycloak에 위임 (authdb는 인증 목적 미사용으로 전환)
- gateway JwtAuthenticationFilter: JWKS 조회 대상을 Keycloak으로 변경, issuer 검증 추가, X-User-Email/X-User-Name 헤더로 교체
- customer.front/home.front 최초 배포 (customer.leedohyun.com, home.leedohyun.com), 쿠키는 Domain=.leedohyun.com으로 서브도메인 공유
- 버그: 한글 이름이 HTTP 헤더(ISO-8859-1)를 못 통과해서 깨짐 > 게이트웨이에서 URL 인코딩, auth.api에서 디코딩하여 해결
e2e 검증 완료 (회원가입/로그인/me/쿠키 도메인 전부 확인), 테스트 계정 정리 완료
- CLAUDE.md의 customer 네임스페이스 섹션 최신화 완료

Actions

내보내기 Atom PDF