110 lines
4.3 KiB
Markdown
110 lines
4.3 KiB
Markdown
# Redmine #547 - 외부 VM HTTPS 운영 런북
|
||
|
||
## 운영 구조
|
||
|
||
- 공개 endpoint: `https://<소유 FQDN>` 또는 `https://<고정 public IPv4>`
|
||
- Caddy: VM의 80/443에서 TLS termination, HTTP redirect, HSTS, 인증서 자동 발급·갱신
|
||
- Spring Boot: `127.0.0.1:8082`에서만 수신
|
||
- 외부 `8082/tcp`: OCI NSG와 VM firewalld 모두 deny
|
||
|
||
FQDN을 쓰면 A 레코드는 VM public IP를 가리켜야 한다. DNS가 없는 고정 public IPv4는 Let’s Encrypt `shortlived` profile 기반 약 6일 인증서를 사용하며 Caddy 자동 갱신이 정상인지 반드시 모니터링한다. 임시 공개 DNS 서비스와 Caddy 로컬 CA 인증서는 운영 endpoint로 사용하지 않는다.
|
||
|
||
## 최초 준비
|
||
|
||
아래 작업은 시스템 패키지와 방화벽을 바꾸므로 개별 승인을 받은 뒤 수행한다.
|
||
|
||
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에 공식 Caddy 패키지를 설치한다.
|
||
|
||
```bash
|
||
sudo dnf install -y dnf-plugins-core
|
||
sudo dnf copr enable -y @caddy/caddy
|
||
sudo dnf install -y caddy
|
||
```
|
||
|
||
공식 패키지는 `caddy.service`와 `/etc/caddy/Caddyfile`을 제공한다. 설정 스크립트가 service enable/start를 처리한다.
|
||
|
||
## 적용
|
||
|
||
먼저 로컬 검증과 앱 배포를 수행한다.
|
||
|
||
```bash
|
||
mvn test
|
||
scripts/test-backoffice-https-config.sh
|
||
scripts/deploy-backoffice-vm.sh --host hermes
|
||
```
|
||
|
||
HTTPS 설정을 dry-run으로 확인한 다음 적용한다.
|
||
|
||
```bash
|
||
scripts/configure-backoffice-https-vm.sh \
|
||
--host hermes \
|
||
--public-host admin.example.com \
|
||
--tls-email ops@example.com \
|
||
--expected-address 130.162.134.59 \
|
||
--dry-run
|
||
|
||
scripts/configure-backoffice-https-vm.sh \
|
||
--host hermes \
|
||
--public-host admin.example.com \
|
||
--tls-email ops@example.com \
|
||
--expected-address 130.162.134.59
|
||
```
|
||
|
||
실제 endpoint, 이메일, 주소로 바꿔 실행한다. FQDN 대신 IP를 쓰는 현재 hermes 예시는 `--public-host 130.162.134.59 --expected-address 130.162.134.59`다. 스크립트는 DNS/IP 일치, Caddy/sudo, Caddyfile 문법, service 상태를 확인하고 기존 설정을 `~/apps/vpd-backoffice/caddy-backups`에 저장한다.
|
||
|
||
## 반복 검증
|
||
|
||
설정을 바꾸지 않고 외부 검증만 다시 수행할 수 있다.
|
||
|
||
```bash
|
||
scripts/configure-backoffice-https-vm.sh \
|
||
--host hermes \
|
||
--public-host admin.example.com \
|
||
--tls-email ops@example.com \
|
||
--expected-address 130.162.134.59 \
|
||
--verify-only
|
||
```
|
||
|
||
검증 항목:
|
||
|
||
- HTTP `/login`이 동일 host의 HTTPS로 전환됨
|
||
- HTTPS 인증서가 공개 신뢰됨
|
||
- HSTS 1년
|
||
- `JSESSIONID`의 Secure/HttpOnly/SameSite=Lax
|
||
- 외부 `:8082` 직접 연결 실패
|
||
|
||
## 인증서 갱신과 모니터링
|
||
|
||
Caddy는 공개 DNS 이름의 인증서를 자동 갱신하며, 공식 systemd service의 인증서 상태는 `/var/lib/caddy/.local/share/caddy`에 유지된다. 별도 cron이나 certbot hook을 추가하지 않는다.
|
||
|
||
```bash
|
||
ssh hermes 'systemctl is-active caddy && systemctl is-enabled caddy'
|
||
ssh hermes 'sudo journalctl -u caddy --since "24 hours ago" --no-pager'
|
||
ssh hermes 'sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile'
|
||
```
|
||
|
||
ACME 오류, 인증서 만료 경고, 반복 reload 실패를 알림 대상으로 삼는다. VM 백업에서 Caddy data directory와 앱의 Caddyfile backup을 함께 보존한다.
|
||
|
||
## 장애와 롤백
|
||
|
||
1. 앱이 살아 있는지 VM 내부에서 확인한다.
|
||
|
||
```bash
|
||
ssh hermes 'curl -sS -H "X-Forwarded-Proto: https" -H "X-Forwarded-Host: admin.example.com" -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8082/login'
|
||
```
|
||
|
||
2. Caddy 로그와 설정을 확인한다.
|
||
3. 설정 변경 직후 장애라면 가장 최근 backup을 복원한다.
|
||
|
||
```bash
|
||
ssh hermes 'ls -1t ~/apps/vpd-backoffice/caddy-backups/Caddyfile.* | head -n 3'
|
||
ssh hermes 'sudo install -o root -g root -m 644 ~/apps/vpd-backoffice/caddy-backups/Caddyfile.<timestamp> /etc/caddy/Caddyfile && sudo systemctl reload caddy'
|
||
```
|
||
|
||
4. 앱 jar 롤백이 필요하면 직전 승인된 artifact를 배포하고 앱과 Caddy를 모두 재검증한다.
|
||
|
||
장애 우회를 위해 `8082`를 다시 공개하지 않는다. 서비스 중단이나 방화벽/NSG 롤백은 개별 승인을 받는다.
|