prod
This commit is contained in:
56
docker-compose-prod.yml
Normal file
56
docker-compose-prod.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: kamco-cd-nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
- nginx-logs:/var/log/nginx
|
||||
depends_on:
|
||||
kamco-changedetection-api:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- kamco-cds
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "--no-check-certificate", "https://localhost/monitor/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
kamco-changedetection-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: kamco-cd-training-api:${IMAGE_TAG:-latest}
|
||||
container_name: kamco-cd-training-api
|
||||
expose:
|
||||
- "8080"
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Seoul
|
||||
volumes:
|
||||
- ./app/model_output:/app/model-outputs
|
||||
- ./app/train_dataset:/app/train-dataset
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- kamco-cds
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/monitor/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
kamco-cds:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
nginx-logs:
|
||||
driver: local
|
||||
397
nginx/SSL_SETUP.md
Normal file
397
nginx/SSL_SETUP.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# SSL 사설 인증서 설정 가이드 (RedHat 9.6)
|
||||
|
||||
## 개요
|
||||
|
||||
이 문서는 RedHat 9.6 환경에서 `https://api.train-kamco.com` 및 `https://train-kamco.com` 도메인을 위한 100년 유효한 사설 SSL 인증서 설정 방법을 설명합니다.
|
||||
|
||||
## 디렉토리 구조
|
||||
|
||||
```
|
||||
nginx/
|
||||
├── nginx.conf # Nginx 설정 파일
|
||||
├── ssl/
|
||||
│ ├── openssl.cnf # OpenSSL 설정 파일 (SAN 포함)
|
||||
│ ├── train-kamco.com.crt # 사설 SSL 인증서 (멀티 도메인)
|
||||
│ └── train-kamco.com.key # 개인 키 (비공개)
|
||||
└── SSL_SETUP.md # 이 문서
|
||||
```
|
||||
|
||||
## 인증서 정보
|
||||
|
||||
- **도메인**: api.train-kamco.com, train-kamco.com (멀티 도메인)
|
||||
- **유효 기간**: 100년 (36500일)
|
||||
- **알고리즘**: RSA 4096-bit
|
||||
- **CN (Common Name)**: api.train-kamco.com
|
||||
- **SAN (Subject Alternative Names)**: api.train-kamco.com, train-kamco.com
|
||||
|
||||
## 사설 SSL 인증서 생성 (이미 생성됨)
|
||||
|
||||
인증서가 이미 생성되어 있습니다. 재생성이 필요한 경우 아래 단계를 따르세요.
|
||||
|
||||
### 1. OpenSSL 설정 파일 생성
|
||||
|
||||
```bash
|
||||
cd /path/to/kamco-train-api
|
||||
|
||||
cat > nginx/ssl/openssl.cnf << 'EOF'
|
||||
[req]
|
||||
default_bits = 4096
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
distinguished_name = dn
|
||||
req_extensions = v3_req
|
||||
|
||||
[dn]
|
||||
C=KR
|
||||
ST=Seoul
|
||||
L=Seoul
|
||||
O=KAMCO
|
||||
OU=Training
|
||||
CN=api.train-kamco.com
|
||||
|
||||
[v3_req]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = api.train-kamco.com
|
||||
DNS.2 = train-kamco.com
|
||||
EOF
|
||||
```
|
||||
|
||||
### 2. SSL 인증서 및 개인 키 생성
|
||||
|
||||
```bash
|
||||
# nginx/ssl 디렉토리 생성 (없는 경우)
|
||||
mkdir -p nginx/ssl
|
||||
chmod 700 nginx/ssl
|
||||
|
||||
# 인증서 및 개인 키 생성 (100년 유효)
|
||||
openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes \
|
||||
-keyout nginx/ssl/train-kamco.com.key \
|
||||
-out nginx/ssl/train-kamco.com.crt \
|
||||
-days 36500 \
|
||||
-config nginx/ssl/openssl.cnf \
|
||||
-extensions v3_req
|
||||
|
||||
# 파일 권한 설정
|
||||
chmod 600 nginx/ssl/train-kamco.com.key
|
||||
chmod 644 nginx/ssl/train-kamco.com.crt
|
||||
```
|
||||
|
||||
### 3. 인증서 검증
|
||||
|
||||
```bash
|
||||
# 인증서 정보 확인
|
||||
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout
|
||||
|
||||
# 유효 기간 확인
|
||||
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout | grep -A2 "Validity"
|
||||
|
||||
# SAN (멀티 도메인) 확인
|
||||
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout | grep -A1 "Subject Alternative Name"
|
||||
|
||||
# CN 확인
|
||||
openssl x509 -in nginx/ssl/train-kamco.com.crt -noout -subject
|
||||
|
||||
# 개인 키 확인
|
||||
openssl rsa -in nginx/ssl/train-kamco.com.key -check
|
||||
```
|
||||
|
||||
**예상 결과**:
|
||||
```
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:api.train-kamco.com, DNS:train-kamco.com
|
||||
|
||||
Validity
|
||||
Not Before: Mar 2 23:39:XX 2026 GMT
|
||||
Not After : Feb 6 23:39:XX 2126 GMT
|
||||
```
|
||||
|
||||
## /etc/hosts 설정 (RedHat 9.6)
|
||||
|
||||
### 1. hosts 파일에 도메인 추가
|
||||
|
||||
```bash
|
||||
# root 권한으로 실행
|
||||
echo "127.0.0.1 api.train-kamco.com train-kamco.com" | sudo tee -a /etc/hosts
|
||||
|
||||
# 확인
|
||||
cat /etc/hosts | grep train-kamco
|
||||
```
|
||||
|
||||
**예상 결과**:
|
||||
```
|
||||
127.0.0.1 api.train-kamco.com train-kamco.com
|
||||
```
|
||||
|
||||
### 2. 도메인 확인
|
||||
|
||||
```bash
|
||||
# ping 테스트
|
||||
ping -c 2 api.train-kamco.com
|
||||
ping -c 2 train-kamco.com
|
||||
```
|
||||
|
||||
## Docker Compose 배포
|
||||
|
||||
### 1. 기존 컨테이너 중지 (실행 중인 경우)
|
||||
|
||||
```bash
|
||||
cd /path/to/kamco-train-api
|
||||
docker-compose -f docker-compose-prod.yml down
|
||||
```
|
||||
|
||||
### 2. Production 환경 실행
|
||||
|
||||
```bash
|
||||
# IMAGE_TAG 환경 변수 설정 (선택사항)
|
||||
export IMAGE_TAG=latest
|
||||
|
||||
# Docker Compose 실행
|
||||
docker-compose -f docker-compose-prod.yml up -d
|
||||
|
||||
# 컨테이너 상태 확인
|
||||
docker-compose -f docker-compose-prod.yml ps
|
||||
```
|
||||
|
||||
### 3. 로그 확인
|
||||
|
||||
```bash
|
||||
# Nginx 로그
|
||||
docker logs kamco-cd-nginx
|
||||
|
||||
# API 로그
|
||||
docker logs kamco-cd-training-api
|
||||
|
||||
# 실시간 로그 확인
|
||||
docker-compose -f docker-compose-prod.yml logs -f
|
||||
```
|
||||
|
||||
## HTTPS 접속 테스트
|
||||
|
||||
### 1. HTTP → HTTPS 리다이렉트 테스트
|
||||
|
||||
```bash
|
||||
# api.train-kamco.com
|
||||
curl -I http://api.train-kamco.com
|
||||
|
||||
# train-kamco.com
|
||||
curl -I http://train-kamco.com
|
||||
|
||||
# 예상 결과: 301 Moved Permanently
|
||||
# Location: https://api.train-kamco.com/ 또는 https://train-kamco.com/
|
||||
```
|
||||
|
||||
### 2. HTTPS 헬스체크 (-k: 사설 인증서 경고 무시)
|
||||
|
||||
```bash
|
||||
# api.train-kamco.com
|
||||
curl -k https://api.train-kamco.com/monitor/health
|
||||
|
||||
# train-kamco.com
|
||||
curl -k https://train-kamco.com/monitor/health
|
||||
|
||||
# 예상 결과: {"status":"UP","components":{...}}
|
||||
```
|
||||
|
||||
### 3. SSL 인증서 확인
|
||||
|
||||
```bash
|
||||
# api.train-kamco.com
|
||||
openssl s_client -connect api.train-kamco.com:443 -showcerts
|
||||
|
||||
# train-kamco.com
|
||||
openssl s_client -connect train-kamco.com:443 -showcerts
|
||||
|
||||
# CN 및 SAN 확인
|
||||
```
|
||||
|
||||
### 4. 브라우저 테스트
|
||||
|
||||
브라우저에서 다음 URL에 접속:
|
||||
|
||||
- `https://api.train-kamco.com/monitor/health`
|
||||
- `https://train-kamco.com/monitor/health`
|
||||
|
||||
**주의**: 사설 인증서이므로 "안전하지 않음" 경고가 표시됩니다.
|
||||
- **Chrome/Edge**: "고급" → "계속 진행" 클릭
|
||||
- **Firefox**: "위험 감수 및 계속" 클릭
|
||||
|
||||
## 브라우저에서 사설 인증서 신뢰 설정 (선택사항)
|
||||
|
||||
사설 인증서를 브라우저에 등록하면 경고 없이 접속 가능합니다.
|
||||
|
||||
### Chrome/Edge (RedHat Desktop)
|
||||
|
||||
1. `chrome://settings/certificates` 접속
|
||||
2. **Authorities** 탭 선택
|
||||
3. **Import** 클릭
|
||||
4. `nginx/ssl/train-kamco.com.crt` 선택
|
||||
5. **Trust this certificate for identifying websites** 체크
|
||||
6. **OK** 클릭
|
||||
|
||||
### Firefox
|
||||
|
||||
1. `about:preferences#privacy` 접속
|
||||
2. **Certificates** → **View Certificates** 클릭
|
||||
3. **Authorities** 탭 선택
|
||||
4. **Import** 클릭
|
||||
5. `nginx/ssl/train-kamco.com.crt` 선택
|
||||
6. **Trust this CA to identify websites** 체크
|
||||
7. **OK** 클릭
|
||||
|
||||
## 방화벽 설정 (RedHat 9.6)
|
||||
|
||||
### 1. 방화벽 상태 확인
|
||||
|
||||
```bash
|
||||
sudo firewall-cmd --state
|
||||
```
|
||||
|
||||
### 2. HTTP (80) 및 HTTPS (443) 포트 개방
|
||||
|
||||
```bash
|
||||
# HTTP 포트 개방
|
||||
sudo firewall-cmd --permanent --add-port=80/tcp
|
||||
|
||||
# HTTPS 포트 개방
|
||||
sudo firewall-cmd --permanent --add-port=443/tcp
|
||||
|
||||
# 방화벽 재로드
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
# 확인
|
||||
sudo firewall-cmd --list-ports
|
||||
```
|
||||
|
||||
**예상 결과**:
|
||||
```
|
||||
80/tcp 443/tcp
|
||||
```
|
||||
|
||||
## 보안 체크리스트
|
||||
|
||||
- [x] `train-kamco.com.key` 파일 권한이 600으로 설정됨
|
||||
- [x] ssl 디렉토리가 버전 관리에서 제외됨 (.gitignore 확인)
|
||||
- [x] 두 도메인(api.train-kamco.com, train-kamco.com) 모두 SAN에 포함됨
|
||||
- [ ] 방화벽에서 80, 443 포트 개방 확인
|
||||
- [x] HSTS 헤더 활성화 확인
|
||||
- [x] TLS 1.2 이상만 허용 확인
|
||||
- [ ] /etc/hosts에 도메인 매핑 확인
|
||||
|
||||
## 트러블슈팅
|
||||
|
||||
### 인증서 관련 오류
|
||||
|
||||
**"certificate verify failed"**
|
||||
```bash
|
||||
# 해결: -k 플래그 사용 (사설 인증서 경고 무시)
|
||||
curl -k https://api.train-kamco.com/monitor/health
|
||||
```
|
||||
|
||||
**"NET::ERR_CERT_AUTHORITY_INVALID" (브라우저)**
|
||||
- 정상 동작: 사설 인증서이므로 브라우저 경고는 예상된 동작입니다
|
||||
- 해결: 브라우저에 인증서 등록 (위 "브라우저에서 사설 인증서 신뢰 설정" 참조)
|
||||
|
||||
### 연결 오류
|
||||
|
||||
**"Connection refused"**
|
||||
```bash
|
||||
# 컨테이너 상태 확인
|
||||
docker ps | grep kamco-cd
|
||||
|
||||
# 포트 바인딩 확인
|
||||
docker port kamco-cd-nginx
|
||||
|
||||
# 예상 결과:
|
||||
# 80/tcp -> 0.0.0.0:80
|
||||
# 443/tcp -> 0.0.0.0:443
|
||||
```
|
||||
|
||||
**"502 Bad Gateway"**
|
||||
```bash
|
||||
# API 컨테이너 상태 확인
|
||||
docker logs kamco-cd-training-api
|
||||
|
||||
# nginx → API 연결 확인
|
||||
docker exec kamco-cd-nginx wget -qO- http://kamco-changedetection-api:8080/monitor/health
|
||||
```
|
||||
|
||||
**"Name or service not known" (도메인 해석 실패)**
|
||||
```bash
|
||||
# /etc/hosts 확인
|
||||
cat /etc/hosts | grep train-kamco
|
||||
|
||||
# 없으면 추가
|
||||
echo "127.0.0.1 api.train-kamco.com train-kamco.com" | sudo tee -a /etc/hosts
|
||||
```
|
||||
|
||||
### 방화벽 관련 오류
|
||||
|
||||
**외부에서 접속 안 됨**
|
||||
```bash
|
||||
# 방화벽 확인
|
||||
sudo firewall-cmd --list-ports
|
||||
|
||||
# 포트 개방
|
||||
sudo firewall-cmd --permanent --add-port=80/tcp
|
||||
sudo firewall-cmd --permanent --add-port=443/tcp
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
## 인증서 만료 및 갱신
|
||||
|
||||
### 만료 확인
|
||||
|
||||
```bash
|
||||
# 인증서 만료일 확인
|
||||
openssl x509 -in nginx/ssl/train-kamco.com.crt -noout -enddate
|
||||
|
||||
# 예상 결과: notAfter=Feb 6 23:39:XX 2126 GMT (100년 후)
|
||||
```
|
||||
|
||||
### 갱신 방법 (필요시)
|
||||
|
||||
100년 유효한 인증서이므로 갱신이 필요하지 않지만, 재생성이 필요한 경우:
|
||||
|
||||
```bash
|
||||
# 기존 인증서 백업
|
||||
cp nginx/ssl/train-kamco.com.crt nginx/ssl/train-kamco.com.crt.bak
|
||||
cp nginx/ssl/train-kamco.com.key nginx/ssl/train-kamco.com.key.bak
|
||||
|
||||
# 위의 "사설 SSL 인증서 생성" 단계 재실행
|
||||
|
||||
# nginx 재시작
|
||||
docker-compose -f docker-compose-prod.yml restart nginx
|
||||
```
|
||||
|
||||
## 주의사항
|
||||
|
||||
1. **사설 인증서 경고**: 브라우저에서 "안전하지 않음" 경고가 표시됩니다. 프로덕션 환경에서는 **공인 인증서(Let's Encrypt, GlobalSign 등) 사용을 권장**합니다.
|
||||
|
||||
2. **포트 80/443**: Docker가 자동으로 처리하지만, 이미 사용 중인 프로세스가 있으면 충돌할 수 있습니다.
|
||||
```bash
|
||||
# 포트 사용 확인
|
||||
sudo lsof -i :80
|
||||
sudo lsof -i :443
|
||||
```
|
||||
|
||||
3. **대용량 파일 업로드**: `client_max_body_size`를 10GB로 설정했으므로, 서버 메모리 및 디스크 용량을 충분히 확보하세요.
|
||||
|
||||
4. **인증서 백업**: `train-kamco.com.key` 파일은 매우 중요합니다. 안전한 곳에 백업하세요.
|
||||
|
||||
5. **SELinux**: RedHat 9.6에서 SELinux가 활성화된 경우, Docker 볼륨 마운트 권한 문제가 발생할 수 있습니다.
|
||||
```bash
|
||||
# SELinux 상태 확인
|
||||
getenforce
|
||||
|
||||
# 필요시 permissive 모드로 변경
|
||||
sudo setenforce 0
|
||||
```
|
||||
|
||||
## 참고 자료
|
||||
|
||||
- [OpenSSL Documentation](https://www.openssl.org/docs/)
|
||||
- [Nginx SSL Configuration](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||
- [Let's Encrypt (공인 인증서)](https://letsencrypt.org/)
|
||||
93
nginx/nginx.conf
Normal file
93
nginx/nginx.conf
Normal file
@@ -0,0 +1,93 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# 로그 설정
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# 업로드 파일 크기 제한 (10GB)
|
||||
client_max_body_size 10G;
|
||||
|
||||
# Upstream 설정
|
||||
upstream api_backend {
|
||||
server kamco-changedetection-api:8080;
|
||||
}
|
||||
|
||||
# HTTP → HTTPS 리다이렉트 서버
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.train-kamco.com train-kamco.com;
|
||||
|
||||
# 모든 HTTP 요청을 HTTPS로 리다이렉트
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS 서버 설정
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name api.train-kamco.com train-kamco.com;
|
||||
|
||||
# SSL 인증서 설정 (사설 인증서 - 멀티 도메인)
|
||||
ssl_certificate /etc/nginx/ssl/train-kamco.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/train-kamco.com.key;
|
||||
|
||||
# SSL 프로토콜 및 암호화 설정
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# SSL 세션 캐시
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# HSTS (HTTP Strict Transport Security)
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# 보안 헤더
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# 프록시 설정
|
||||
location / {
|
||||
proxy_pass http://api_backend;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# 프록시 헤더 설정
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
|
||||
# 타임아웃 설정 (대용량 파일 업로드 지원)
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
# 버퍼 설정
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
proxy_busy_buffers_size 8k;
|
||||
}
|
||||
|
||||
# 헬스체크 엔드포인트
|
||||
location /monitor/health {
|
||||
proxy_pass http://api_backend/monitor/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user