# Redmine #547 - 외부 VM HTTPS 운영 런북

## 운영 구조

- 공개 endpoint: `https://kb.cloud-handson.com`
- 공개 배포 VM: `opc@161.33.6.45`
- Nginx: VM의 80/443에서 TLS termination, HTTP redirect, HSTS
- Spring Boot: `127.0.0.1:8080`에서만 수신
- 외부 애플리케이션 포트 직접 접근: OCI NSG와 VM firewalld 모두 deny
- 인증서: Let’s Encrypt / Certbot Nginx plugin

FQDN의 A 레코드는 VM public IP `161.33.6.45`를 가리켜야 한다. 현재 운영 경로는 Nginx가 `127.0.0.1:8080`의 `vpd-backoffice.service`로 프록시하는 구조다. `hermes` 또는 `8082` 응답만 보고 운영 반영 완료로 판단하지 않는다.

## 최초 준비

아래 작업은 시스템 패키지와 방화벽을 바꾸므로 개별 승인을 받은 뒤 수행한다.

1. 소유 FQDN의 A 레코드를 VM public IP로 설정하거나 고정 public IPv4 사용을 확정한다.
2. OCI NSG와 VM firewalld에서 80/443 ingress를 허용한다.
3. 기존 8082 ingress를 OCI NSG와 firewalld에서 제거한다.
4. Oracle Linux/RHEL 계열 VM에 Nginx와 Certbot Nginx plugin을 설치한다.
5. `vpd-backoffice.service`는 `127.0.0.1:8080`에만 바인딩한다.

## 적용

먼저 로컬 검증과 앱 배포를 수행한다.

```bash
mvn test
```

운영 배포는 `161.33.6.45` 대상에 수행한다. SSH alias를 쓴다면 해당 alias가 반드시 `opc@161.33.6.45`를 가리키는지 먼저 확인한다.

```bash
ssh <운영-alias> 'hostname; hostname -I; systemctl status vpd-backoffice --no-pager'
```

배포 후에는 systemd 서비스를 재시작하고 공개 URL로 확인한다.

```bash
ssh <운영-alias> 'sudo systemctl restart vpd-backoffice'
curl -k -sS https://kb.cloud-handson.com/login
```

## 반복 검증

설정을 바꾸지 않고 외부 검증만 다시 수행할 수 있다.

검증 항목:

- HTTP `/login`이 동일 host의 HTTPS로 전환됨
- HTTPS 인증서가 공개 신뢰됨
- HSTS 1년
- `JSESSIONID`의 Secure/HttpOnly/SameSite=Lax
- 외부 애플리케이션 포트 직접 연결 실패
- `https://kb.cloud-handson.com/login`의 HTML이 현재 배포된 jar의 로그인 화면과 일치

## 인증서 갱신과 모니터링

Certbot timer가 Let’s Encrypt 인증서를 갱신한다. Nginx 설정과 인증서 갱신 상태를 함께 확인한다.

```bash
ssh <운영-alias> 'systemctl is-active nginx && systemctl is-enabled nginx'
ssh <운영-alias> 'systemctl is-active certbot-renew.timer && systemctl is-enabled certbot-renew.timer'
ssh <운영-alias> 'sudo nginx -t'
ssh <운영-alias> 'sudo journalctl -u nginx --since "24 hours ago" --no-pager'
```

ACME 오류, 인증서 만료 경고, 반복 reload 실패를 알림 대상으로 삼는다.

## 장애와 롤백

1. 앱이 살아 있는지 VM 내부에서 확인한다.

```bash
ssh <운영-alias> 'curl -sS -H "X-Forwarded-Proto: https" -H "X-Forwarded-Host: kb.cloud-handson.com" -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/login'
```

2. Nginx 로그와 설정을 확인한다.
3. 설정 변경 직후 장애라면 가장 최근 Nginx 설정 backup을 복원한다.

4. 앱 jar 롤백이 필요하면 직전 승인된 artifact를 배포하고 앱과 Nginx를 모두 재검증한다.

장애 우회를 위해 애플리케이션 포트를 직접 공개하지 않는다. 서비스 중단이나 방화벽/NSG 롤백은 개별 승인을 받는다.
