diff --git a/Dockerfile-prod_bak b/Dockerfile-prod_bak new file mode 100644 index 00000000..3c330e8a --- /dev/null +++ b/Dockerfile-prod_bak @@ -0,0 +1,23 @@ +# Stage 1: Build stage (gradle build는 Jenkins에서 이미 수행) +FROM kamco-java-gdal:21 + +ARG UID=1000 +ARG GID=1000 + +RUN groupadd -g ${GID} kcomu \ + && useradd -u ${UID} -g ${GID} -m kcomu + +USER kcomu + +# 작업 디렉토리 설정 +WORKDIR /app + +# JAR 파일 복사 (Jenkins에서 빌드된 ROOT.jar) +COPY build/libs/ROOT.jar app.jar + +# 포트 노출 +EXPOSE 8080 + +# 애플리케이션 실행 +# dev 프로파일로 실행 +ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"] diff --git a/nginx/README.md b/nginx/README.md new file mode 100644 index 00000000..2b3a6966 --- /dev/null +++ b/nginx/README.md @@ -0,0 +1,122 @@ +# Nginx HTTPS Configuration for KAMCO Change Detection API + +## SSL Certificate Setup + +### Required Files +GlobalSign SSL 인증서 파일들을 서버의 `/etc/ssl/certs/globalsign/` 디렉토리에 배치해야 합니다: + +``` +/etc/ssl/certs/globalsign/ +├── certificate.crt # SSL 인증서 파일 +├── private.key # 개인 키 파일 +└── ca-bundle.crt # CA 번들 파일 (중간 인증서) +``` + +### Certificate Installation Steps + +1. **디렉토리 생성** +```bash +sudo mkdir -p /etc/ssl/certs/globalsign +sudo chmod 755 /etc/ssl/certs/globalsign +``` + +2. **인증서 파일 복사** +```bash +sudo cp your-certificate.crt /etc/ssl/certs/globalsign/certificate.crt +sudo cp your-private.key /etc/ssl/certs/globalsign/private.key +sudo cp ca-bundle.crt /etc/ssl/certs/globalsign/ca-bundle.crt +``` + +3. **파일 권한 설정** +```bash +sudo chmod 644 /etc/ssl/certs/globalsign/certificate.crt +sudo chmod 600 /etc/ssl/certs/globalsign/private.key +sudo chmod 644 /etc/ssl/certs/globalsign/ca-bundle.crt +``` + +## Configuration Overview + +### Service Architecture +``` +Internet (HTTPS:12013) + ↓ +nginx (443 in container) + ↓ +kamco-changedetection-api (8080 in container) +``` + +### Key Features +- **HTTPS/TLS**: TLSv1.2, TLSv1.3 지원 +- **Port**: 외부 12013 → 내부 443 (nginx) +- **Domain**: aicd-api.e-kamco.com:12013 +- **Reverse Proxy**: kamco-changedetection-api:8080으로 프록시 +- **Security Headers**: HSTS, X-Frame-Options, X-Content-Type-Options 등 +- **Health Check**: /health 엔드포인트 + +## Deployment + +### Start Services +```bash +docker-compose -f docker-compose-prod.yml up -d +``` + +### Check Logs +```bash +# Nginx logs +docker logs kamco-cd-nginx + +# API logs +docker logs kamco-changedetection-api +``` + +### Verify Configuration +```bash +# Test nginx configuration +docker exec kamco-cd-nginx nginx -t + +# Check SSL certificate +docker exec kamco-cd-nginx openssl s_client -connect localhost:443 -servername aicd-api.e-kamco.com +``` + +### Access Service +```bash +# HTTPS Access +curl -k https://aicd-api.e-kamco.com:12013/monitor/health + +# Health Check +curl -k https://aicd-api.e-kamco.com:12013/health +``` + +## Troubleshooting + +### Certificate Issues +인증서 파일이 제대로 마운트되었는지 확인: +```bash +docker exec kamco-cd-nginx ls -la /etc/ssl/certs/globalsign/ +``` + +### Nginx Configuration Test +```bash +docker exec kamco-cd-nginx nginx -t +``` + +### Connection Test +```bash +# Check if nginx is listening +docker exec kamco-cd-nginx netstat -tlnp | grep 443 + +# Check backend connection +docker exec kamco-cd-nginx wget --spider http://kamco-changedetection-api:8080/monitor/health +``` + +## Configuration Files + +- `nginx/nginx.conf`: Main nginx configuration +- `nginx/conf.d/default.conf`: Server block with SSL and proxy settings +- `docker-compose-prod.yml`: Docker compose with nginx service + +## Notes + +- 인증서 파일명이 다를 경우 `nginx/conf.d/default.conf`에서 경로를 수정하세요 +- 인증서 갱신 시 nginx 컨테이너를 재시작하세요: `docker restart kamco-cd-nginx` +- 포트 12013이 방화벽에서 허용되어 있는지 확인하세요 \ No newline at end of file diff --git a/nginx/conf.d/default.conf b/nginx/conf.d/default.conf new file mode 100644 index 00000000..b5819658 --- /dev/null +++ b/nginx/conf.d/default.conf @@ -0,0 +1,60 @@ +upstream kamco_api { + server kamco-cd-api:8080; +} + +server { + listen 443 ssl http2; + server_name aicd-api.e-kamco.com; + + # GlobalSign SSL Certificate + ssl_certificate /etc/ssl/certs/globalsign/certificate.crt; + ssl_certificate_key /etc/ssl/certs/globalsign/private.key; + + # SSL Configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Security Headers + 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; + + # Client Body Size + client_max_body_size 100M; + + # Proxy Settings + location / { + proxy_pass http://kamco_api; + 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 $host; + proxy_set_header X-Forwarded-Port $server_port; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # WebSocket Support (if needed) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Health Check Endpoint + location /health { + access_log off; + return 200 "OK"; + add_header Content-Type text/plain; + } + + # Access and Error Logs + access_log /var/log/nginx/kamco-api-access.log; + error_log /var/log/nginx/kamco-api-error.log; +} \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 00000000..a82807c5 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,33 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +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; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json; + + include /etc/nginx/conf.d/*.conf; +} \ No newline at end of file diff --git a/src/main/resources/application-prod.yml_bak b/src/main/resources/application-prod.yml_bak new file mode 100644 index 00000000..894a055b --- /dev/null +++ b/src/main/resources/application-prod.yml_bak @@ -0,0 +1,120 @@ +spring: + config: + activate: + on-profile: prod + + jpa: + show-sql: true + hibernate: + ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 + order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 + order_inserts: true + use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용) + format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성) + jdbc: + batch_size: 1000 # ✅ 추가 (JDBC batch) + + datasource: + url: jdbc:postgresql://kamco-cd-postgis:5432/kamco_cds + #url: jdbc:postgresql://localhost:15432/kamco_cds + username: kamco_cds + password: kamco_cds_Q!W@E#R$ + hikari: + minimum-idle: 10 + maximum-pool-size: 20 + connection-timeout: 60000 # 60초 연결 타임아웃 + idle-timeout: 300000 # 5분 유휴 타임아웃 + max-lifetime: 1800000 # 30분 최대 수명 + leak-detection-threshold: 60000 # 연결 누수 감지 + + transaction: + default-timeout: 300 # 5분 트랜잭션 타임아웃 + + data: + redis: + host: 127.0.0.1 + port: 16379 + password: kamco + + servlet: + multipart: + enabled: true + max-file-size: 4GB + max-request-size: 4GB + file-size-threshold: 10MB + +server: + tomcat: + max-swallow-size: 4GB + max-http-form-post-size: 4GB + +jwt: + secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b" + access-token-validity-in-ms: 86400000 # 1일 + refresh-token-validity-in-ms: 604800000 # 7일 + +token: + refresh-cookie-name: kamco # 개발용 쿠키 이름 + refresh-cookie-secure: true # 로컬 http 테스트면 false + +logging: + level: + root: INFO + org.springframework.web: INFO + org.springframework.security: INFO + + # 헬스체크 노이즈 핵심만 다운 + org.springframework.security.web.FilterChainProxy: INFO + org.springframework.security.web.authentication.AnonymousAuthenticationFilter: INFO + org.springframework.security.web.authentication.Http403ForbiddenEntryPoint: INFO + org.springframework.web.servlet.DispatcherServlet: INFO + + +mapsheet: + upload: + skipGdalValidation: true + shp: + baseurl: /app/detect/result #현재사용안함 + +file: + #sync-root-dir: D:/kamco-nfs/images/ + sync-root-dir: /kamco-nfs/images/ + sync-tmp-dir: ${file.sync-root-dir}/tmp # image upload temp dir + sync-file-extention: tfw,tif + sync-auto-exception-start-year: 2025 + sync-auto-exception-before-year-cnt: 3 + + #dataset-dir: D:/kamco-nfs/model_output/ #변경 model_output + dataset-dir: /kamco-nfs/model_output/export/ # 마운트경로 AI 추론결과 + dataset-tmp-dir: ${file.dataset-dir}tmp/ + + #model-dir: D:/kamco-nfs/ckpt/model/ + model-dir: /kamco-nfs/ckpt/model/ # 학습서버에서 트레이닝한 모델업로드경로 + model-tmp-dir: ${file.model-dir}tmp/ + model-file-extention: pth,json,py + + pt-path: /kamco-nfs/ckpt/model/v6-cls-checkpoints/ + pt-FileName: yolov8_6th-6m.pt + +inference: + url: http://127.0.0.1:8000/jobs + batch-url: http://127.0.0.1:8000/batches + geojson-dir: /kamco-nfs/requests/ # 학습서버에서 트레이닝한 모델업로드경로 + jar-path: /kamco-nfs/repo/jar/shp-exporter.jar # 추론실행을 위한 파일생성경로 + inference-server-name: server1,server2,server3,server4 + +gukyuin: + url: http://127.0.0.1:5301 + cdi: ${gukyuin.url}/api/kcd/cdi + +training-data: + geojson-dir: /kamco-nfs/dataset/request/ + +layer: + geoserver-url: https://kamco.geo-dev.gs.dabeeo.com + wms-path: geoserver/cd + wmts-path: geoserver/cd/gwc/service + workspace: cd