first commit
commit
ac3b5b3015
|
|
@ -0,0 +1,9 @@
|
||||||
|
# aio2o-infrakit
|
||||||
|
|
||||||
|
aio2o의 분산된 인프라 서비스 및 설정을 단일 프로젝트로 통합하여 구축한 범용 인프라 솔루션입니다.
|
||||||
|
|
||||||
|
## 기반 오픈소스
|
||||||
|
|
||||||
|
이 프로젝트는 임도현 책임연구원의 [devspoon-web](https://github.com/devspoons/devspoon-web) 오픈소스를 기반으로 개발되었습니다.
|
||||||
|
|
||||||
|
#
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
PROJECT_DIR=o2o-castad-backend
|
||||||
|
LOG_DRIVER=json-file
|
||||||
|
LOG_OPT_MAXF=5
|
||||||
|
LOG_OPT_MAXS=100m
|
||||||
|
CELERY_BROKER_URL=redis://redis:6379/3
|
||||||
|
FLOWER_ID=admin
|
||||||
|
FLOWER_PWD=admin
|
||||||
|
POSTGRES_DB=ado3_dev
|
||||||
|
POSTGRES_USER=ado3_dev_admin
|
||||||
|
POSTGRES_PASSWORD=ado31324
|
||||||
|
MYSQL_PASSWORD=ado31324
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
services:
|
||||||
|
webserver:
|
||||||
|
build: ../docker/nginx/
|
||||||
|
logging:
|
||||||
|
driver: "${LOG_DRIVER}"
|
||||||
|
options:
|
||||||
|
max-file: "${LOG_OPT_MAXF}"
|
||||||
|
max-size: "${LOG_OPT_MAXS}"
|
||||||
|
working_dir: /application
|
||||||
|
container_name: nginx-uvicorn-webserver
|
||||||
|
volumes:
|
||||||
|
- ../www:/www
|
||||||
|
- ../script/:/script/
|
||||||
|
- ../config/web-server/conf.d/:/etc/nginx/conf.d/
|
||||||
|
- ../config/web-server/nginx_conf/nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ../config/web-server/proxy_params:/etc/nginx/proxy_params
|
||||||
|
- ./ssl/certs/:/etc/ssl/certs/
|
||||||
|
- ./ssl/letsencrypt/:/etc/letsencrypt/
|
||||||
|
- ../log/:/log/
|
||||||
|
- ../script/logrotate/nginx/nginx:/etc/logrotate.d/nginx
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
- 443:443
|
||||||
|
# - 8000:8000
|
||||||
|
environment:
|
||||||
|
TZ: "Asia/Seoul"
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
# - frontend-app
|
||||||
|
- uvicorn-app
|
||||||
|
|
||||||
|
uvicorn-app:
|
||||||
|
build: ../docker/gunicorn/
|
||||||
|
logging:
|
||||||
|
driver: "${LOG_DRIVER}"
|
||||||
|
options:
|
||||||
|
max-file: "${LOG_OPT_MAXF}"
|
||||||
|
max-size: "${LOG_OPT_MAXS}"
|
||||||
|
working_dir: /www/${PROJECT_DIR}
|
||||||
|
container_name: uvicorn-app
|
||||||
|
ports:
|
||||||
|
- 8000:8000
|
||||||
|
volumes:
|
||||||
|
- ../www:/www
|
||||||
|
- ../log:/log
|
||||||
|
- ../config/app-server/:/uvicorn
|
||||||
|
- ../script/logrotate/uvicorn/uvicorn:/etc/logrotate.d/uvicorn
|
||||||
|
command: bash -c "uv pip install --system --no-cache . && playwright install-deps && playwright install && exec gunicorn -c /uvicorn/gunicorn_uvicorn.conf.py "
|
||||||
|
environment:
|
||||||
|
TZ: "Asia/Seoul"
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
logging:
|
||||||
|
driver: "${LOG_DRIVER}"
|
||||||
|
options:
|
||||||
|
max-file: "${LOG_OPT_MAXF}"
|
||||||
|
max-size: "${LOG_OPT_MAXS}"
|
||||||
|
container_name: redis_db
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
volumes:
|
||||||
|
- ./redis/data:/data
|
||||||
|
- ./redis/conf/:/usr/local/etc/redis/
|
||||||
|
labels:
|
||||||
|
- "name=redis"
|
||||||
|
- "mode=standalone"
|
||||||
|
environment:
|
||||||
|
TZ: "Asia/Seoul"
|
||||||
|
restart: always
|
||||||
|
command: redis-server /usr/local/etc/redis/redis.conf
|
||||||
|
|
||||||
|
# mysql:
|
||||||
|
# image: percona/percona-server:latest
|
||||||
|
# logging:
|
||||||
|
# driver: "${LOG_DRIVER}"
|
||||||
|
# options:
|
||||||
|
# max-file: "${LOG_OPT_MAXF}"
|
||||||
|
# max-size: "${LOG_OPT_MAXS}"
|
||||||
|
# container_name: mysql
|
||||||
|
# environment:
|
||||||
|
# MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
|
||||||
|
# TZ: Asia/Seoul
|
||||||
|
# ports:
|
||||||
|
# - "3306:3306"
|
||||||
|
# volumes:
|
||||||
|
# - ./mysql:/var/lib/mysql
|
||||||
|
# - ../config/database/mysql/my.cnf:/etc/my.cnf
|
||||||
|
# # - ../config/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||||
|
# - ../log/mysql:/var/log/mysql
|
||||||
|
# restart: always
|
||||||
|
# profiles:
|
||||||
|
# - mysql
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,102 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# set_mysql_permission.sh
|
||||||
|
# MySQL, PostgreSQL, Redis 데이터 디렉터리 권한 설정 스크립트
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# 스크립트 실행 경로 기준
|
||||||
|
MYSQL_DIR="./mysql"
|
||||||
|
PGDATA_DIR="./pgdata"
|
||||||
|
REDIS_DIR="./redis"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# MySQL (Percona) 권한 설정
|
||||||
|
# ============================================================
|
||||||
|
echo "[MySQL] 데이터 디렉터리 권한 설정을 시작합니다..."
|
||||||
|
echo "[MySQL] 대상 디렉터리: $MYSQL_DIR"
|
||||||
|
|
||||||
|
if [ ! -d "$MYSQL_DIR" ]; then
|
||||||
|
echo "[MySQL] $MYSQL_DIR 디렉터리가 존재하지 않아 새로 생성합니다."
|
||||||
|
sudo mkdir -p "$MYSQL_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Percona의 mysql 유저 UID는 보통 1001
|
||||||
|
MYSQL_UID=1001
|
||||||
|
MYSQL_GID=1001
|
||||||
|
|
||||||
|
echo "[MySQL] 소유권을 $MYSQL_UID:$MYSQL_GID 로 변경합니다..."
|
||||||
|
sudo chown -R ${MYSQL_UID}:${MYSQL_GID} "$MYSQL_DIR"
|
||||||
|
|
||||||
|
echo "[MySQL] 권한을 750 (rwxr-x---) 으로 설정합니다..."
|
||||||
|
sudo chmod -R 750 "$MYSQL_DIR"
|
||||||
|
|
||||||
|
echo "[MySQL] 적용 결과:"
|
||||||
|
ls -ld "$MYSQL_DIR"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PostgreSQL 권한 설정
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "[PostgreSQL] 데이터 디렉터리 권한 설정을 시작합니다..."
|
||||||
|
echo "[PostgreSQL] 대상 디렉터리: $PGDATA_DIR"
|
||||||
|
|
||||||
|
if [ ! -d "$PGDATA_DIR" ]; then
|
||||||
|
echo "[PostgreSQL] $PGDATA_DIR 디렉터리가 존재하지 않아 새로 생성합니다."
|
||||||
|
sudo mkdir -p "$PGDATA_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PostgreSQL의 postgres 유저 UID는 보통 999 (공식 Docker 이미지 기준)
|
||||||
|
POSTGRES_UID=999
|
||||||
|
POSTGRES_GID=999
|
||||||
|
|
||||||
|
echo "[PostgreSQL] 소유권을 $POSTGRES_UID:$POSTGRES_GID 로 변경합니다..."
|
||||||
|
sudo chown -R ${POSTGRES_UID}:${POSTGRES_GID} "$PGDATA_DIR"
|
||||||
|
|
||||||
|
echo "[PostgreSQL] 권한을 700 (rwx------) 으로 설정합니다..."
|
||||||
|
sudo chmod -R 700 "$PGDATA_DIR"
|
||||||
|
|
||||||
|
echo "[PostgreSQL] 적용 결과:"
|
||||||
|
ls -ld "$PGDATA_DIR"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Redis 권한 설정
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "[Redis] 데이터 디렉터리 권한 설정을 시작합니다..."
|
||||||
|
echo "[Redis] 대상 디렉터리: $REDIS_DIR"
|
||||||
|
|
||||||
|
if [ ! -d "$REDIS_DIR" ]; then
|
||||||
|
echo "[Redis] $REDIS_DIR 디렉터리가 존재하지 않아 새로 생성합니다."
|
||||||
|
sudo mkdir -p "$REDIS_DIR/data"
|
||||||
|
sudo mkdir -p "$REDIS_DIR/conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$REDIS_DIR/data" ]; then
|
||||||
|
echo "[Redis] $REDIS_DIR/data 디렉터리가 존재하지 않아 새로 생성합니다."
|
||||||
|
sudo mkdir -p "$REDIS_DIR/data"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$REDIS_DIR/conf" ]; then
|
||||||
|
echo "[Redis] $REDIS_DIR/conf 디렉터리가 존재하지 않아 새로 생성합니다."
|
||||||
|
sudo mkdir -p "$REDIS_DIR/conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Redis의 redis 유저 UID는 보통 999 (공식 Docker 이미지 기준)
|
||||||
|
REDIS_UID=999
|
||||||
|
REDIS_GID=999
|
||||||
|
|
||||||
|
echo "[Redis] 소유권을 $REDIS_UID:$REDIS_GID 로 변경합니다..."
|
||||||
|
sudo chown -R ${REDIS_UID}:${REDIS_GID} "$REDIS_DIR"
|
||||||
|
|
||||||
|
echo "[Redis] 권한을 750 (rwxr-x---) 으로 설정합니다..."
|
||||||
|
sudo chmod -R 750 "$REDIS_DIR"
|
||||||
|
|
||||||
|
echo "[Redis] 적용 결과:"
|
||||||
|
ls -ld "$REDIS_DIR"
|
||||||
|
ls -la "$REDIS_DIR"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 완료
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "[완료] 모든 권한 설정이 완료되었습니다."
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
"""
|
||||||
|
Gunicorn Configuration for Production FastAPI Service
|
||||||
|
=====================================================
|
||||||
|
환경: Production Level
|
||||||
|
서버 사양: 쿼드코어 CPU, 4GB RAM, ~50 req/s
|
||||||
|
백엔드: FastAPI REST API with Uvicorn Workers
|
||||||
|
프록시: Nginx (SSL/TLS, DDoS, Rate Limiting 처리)
|
||||||
|
=====================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 네트워크 바인딩 설정
|
||||||
|
# ============================================================================
|
||||||
|
# 바인딩 주소 및 포트
|
||||||
|
# 역할: Gunicorn이 수신할 네트워크 주소
|
||||||
|
# 0.0.0.0:8000 - 모든 네트워크 인터페이스에서 수신 (Docker/컨테이너 환경)
|
||||||
|
# 127.0.0.1:8000 - 로컬 전용 (Nginx와 동일 호스트, 보안 강화)
|
||||||
|
# Nginx 연동: Nginx가 외부 트래픽 처리, Gunicorn은 내부 전용
|
||||||
|
bind = "0.0.0.0:8000"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Worker 프로세스 설정
|
||||||
|
# ============================================================================
|
||||||
|
# Worker 수
|
||||||
|
# 역할: 동시 요청 처리를 위한 프로세스 수
|
||||||
|
# 공식: I/O 집약적 작업 = (CPU 코어 * 2) + 1
|
||||||
|
# 계산: 쿼드코어(4) → 9개 권장, 하지만 4GB RAM 제약으로 4개 설정
|
||||||
|
# 각 워커 메모리: 200-500MB
|
||||||
|
# 4 워커 × 500MB = 2GB (시스템 예비 2GB 확보)
|
||||||
|
# 성능: ~50 req/s는 4개 워커로 충분 (워커당 ~12.5 req/s)
|
||||||
|
# 환경 변수: GUNICORN_WORKERS=6 으로 오버라이드 가능
|
||||||
|
# workers = multiprocessing.cpu_count() * 2 + 1
|
||||||
|
workers = 4
|
||||||
|
|
||||||
|
# Worker 클래스
|
||||||
|
# 역할: ASGI 애플리케이션(FastAPI) 처리를 위한 Worker 타입
|
||||||
|
# uvicorn.workers.UvicornWorker: 비동기 I/O, uvloop 이벤트 루프
|
||||||
|
# 기대 효과: sync 워커 대비 2-5배 높은 동시성, 메모리 효율적
|
||||||
|
worker_class = "uvicorn.workers.UvicornWorker"
|
||||||
|
|
||||||
|
# Worker 동시 연결 수 (주석 처리 - UvicornWorker는 이 설정 미사용)
|
||||||
|
# Nginx가 앞단에서 연결 관리하므로 불필요
|
||||||
|
# worker_connections = 1000
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 프로세스 관리 설정
|
||||||
|
# ============================================================================
|
||||||
|
# 데몬 모드
|
||||||
|
# 역할: 백그라운드 실행 여부
|
||||||
|
# False: systemd/Docker가 프로세스 관리 (현대적 방식)
|
||||||
|
# True: 수동 관리 시 사용 (pidfile 필수)
|
||||||
|
daemon = False
|
||||||
|
|
||||||
|
# PID 파일 (주석 처리 - systemd/Docker 사용 시 불필요)
|
||||||
|
# 역할: Master 프로세스 ID 저장
|
||||||
|
# 수동 관리 시 활성화: pidfile = '/var/run/gunicorn/gunicorn.pid'
|
||||||
|
# pidfile = '/tmp/gunicorn.pid'
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# ASGI 애플리케이션 경로
|
||||||
|
# ============================================================================
|
||||||
|
# ASGI 애플리케이션 경로
|
||||||
|
# 역할: Gunicorn이 실행할 FastAPI 앱 지정
|
||||||
|
# 형식: "모듈경로:변수명"
|
||||||
|
# 예: config.asgi:application (Django 스타일)
|
||||||
|
# main:app (FastAPI 기본)
|
||||||
|
#wsgi_app = "main:app"
|
||||||
|
wsgi_app = "main:app"
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 타임아웃 설정
|
||||||
|
# ============================================================================
|
||||||
|
# Worker 타임아웃
|
||||||
|
# 역할: Worker가 요청 처리 최대 허용 시간 (초)
|
||||||
|
# 동작: 타임아웃 초과 시 Worker 강제 종료 후 재시작
|
||||||
|
# 계산: FastAPI REST API 평균 응답 1-5초
|
||||||
|
# 파일 업로드 고려 (100MB / 10Mbps = 80초)
|
||||||
|
# 비디오 생성, 이미지 처리 등 장기 실행 작업 고려
|
||||||
|
# Nginx 연동: proxy_read_timeout(300s)과 동일하게 설정
|
||||||
|
# 300초: 장기 실행 API (비디오 생성, 이미지 업로드 등) 지원
|
||||||
|
timeout = 300
|
||||||
|
|
||||||
|
# Keep-Alive 타임아웃
|
||||||
|
# 역할: HTTP Keep-Alive 연결 유지 시간 (초)
|
||||||
|
# 동작: 연결 재사용으로 핸드셰이크 오버헤드 감소
|
||||||
|
# Nginx 연동: Nginx keepalive_timeout(30s)보다 짧게 설정
|
||||||
|
# Nginx가 먼저 종료하도록 하여 리소스 효율화
|
||||||
|
# 2초: Nginx 앞단에서 연결 관리하므로 짧게 설정
|
||||||
|
keepalive = 2
|
||||||
|
|
||||||
|
# Graceful 종료 타임아웃
|
||||||
|
# 역할: Worker 재시작/종료 시 진행 중인 요청 완료 대기 시간 (초)
|
||||||
|
# 동작: SIGTERM 수신 후 새 요청 거부, 기존 요청 처리
|
||||||
|
# 타임아웃 초과 시 SIGKILL로 강제 종료
|
||||||
|
# 기대 효과: Graceful reload로 무중단 배포
|
||||||
|
# kill -HUP <pid> 또는 systemctl reload gunicorn
|
||||||
|
# timeout과 동일하게 설정
|
||||||
|
graceful_timeout = 300
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 프로세스 리소스 관리 (메모리 누수 방지)
|
||||||
|
# ============================================================================
|
||||||
|
# Worker 최대 요청 수
|
||||||
|
# 역할: Worker가 처리할 최대 요청 후 자동 재시작
|
||||||
|
# 목적: 메모리 누수 방어, 장기 운영 안정성
|
||||||
|
# 동작: max_requests 도달 시 Worker graceful 종료 후 재시작
|
||||||
|
# 계산: ~50 req/s 기준
|
||||||
|
# 1000으로 설정 시 워커당 20초마다 재시작 (1000/50)
|
||||||
|
# 메모리 누수 우려 시 유지, 안정적이면 5000-10000 증가 가능
|
||||||
|
# 모니터링: htop으로 워커 메모리 사용량 추이 확인
|
||||||
|
max_requests = 1000
|
||||||
|
|
||||||
|
# 최대 요청 수 Jitter
|
||||||
|
# 역할: max_requests에 랜덤성 추가
|
||||||
|
# 목적: 모든 Worker가 동시에 재시작하는 것 방지
|
||||||
|
# 동작: 실제 재시작 = max_requests ± random(0, jitter)
|
||||||
|
# 기대 효과: 재시작 부하 분산, 서비스 연속성 보장
|
||||||
|
# 권장: max_requests의 5-10%
|
||||||
|
max_requests_jitter = 50
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 애플리케이션 로딩 설정
|
||||||
|
# ============================================================================
|
||||||
|
# 애플리케이션 사전 로딩
|
||||||
|
# 역할: Worker fork 전 앱 로딩 방식 결정
|
||||||
|
# False: 각 Worker가 독립적으로 앱 로딩
|
||||||
|
# - 장점: Graceful reload 가능 (무중단 배포)
|
||||||
|
# - 단점: 메모리 중복 사용 (Worker 수만큼)
|
||||||
|
# True: Master 프로세스에서 앱 로딩 후 Worker fork
|
||||||
|
# - 장점: 메모리 20-40% 절감 (Copy-on-Write)
|
||||||
|
# - 단점: reload 시 전체 재시작 필요 (다운타임)
|
||||||
|
# 프로덕션 권장: False (무중단 배포 우선)
|
||||||
|
preload_app = False
|
||||||
|
|
||||||
|
# 코드 변경 감지 자동 재시작
|
||||||
|
# 역할: 파일 변경 시 Worker 자동 재시작
|
||||||
|
# 성능 영향: CPU 5-10% 오버헤드, 메모리 50-100MB 추가
|
||||||
|
# 보안: 예기치 않은 재시작으로 서비스 불안정
|
||||||
|
# **프로덕션에서는 반드시 False**
|
||||||
|
# 개발 환경에서만 True 사용
|
||||||
|
# 배포: CI/CD 파이프라인에서 명시적 재시작
|
||||||
|
reload = False
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 로깅 설정
|
||||||
|
# ============================================================================
|
||||||
|
# 애플리케이션 출력 캡처
|
||||||
|
# 역할: FastAPI의 print(), logging을 Gunicorn 로그로 리다이렉트
|
||||||
|
# False: 앱 로거가 독립적으로 관리 (권장)
|
||||||
|
# True: stdout/stderr를 errorlog로 통합
|
||||||
|
# FastAPI 권장: False (자체 로거 사용)
|
||||||
|
capture_output = False
|
||||||
|
|
||||||
|
# 로그 레벨
|
||||||
|
# 역할: 출력할 로그의 최소 수준
|
||||||
|
# 레벨: critical > error > warning > info > debug
|
||||||
|
# info: 일반 정보 + 에러 (프로덕션 권장)
|
||||||
|
# warning: 경고 이상만 (로그 양 감소)
|
||||||
|
# debug: 모든 세부 정보 (성능 저하, 개발용)
|
||||||
|
loglevel = "info"
|
||||||
|
|
||||||
|
# 액세스 로그 파일
|
||||||
|
# 역할: HTTP 요청 로그 저장
|
||||||
|
# 형식: 시간별 로그 파일 생성 (access_2025-01-05_14.log)
|
||||||
|
# 로테이션: 시간별 자동 분리, logrotate 추가 권장
|
||||||
|
# 성능: 버퍼링으로 I/O 최적화
|
||||||
|
# Docker/K8s: "-" 사용으로 stdout 출력 권장
|
||||||
|
accesslog = "/log/uvicorn/uvicorn_access.log"
|
||||||
|
|
||||||
|
# 에러 로그 파일
|
||||||
|
# 역할: Gunicorn 에러, Worker 크래시 로그
|
||||||
|
# 포함: Worker 타임아웃, 메모리 에러, 예외 등
|
||||||
|
# 모니터링: 장애 탐지를 위한 핵심 로그
|
||||||
|
errorlog = "/log/uvicorn/uvicorn_error.log"
|
||||||
|
|
||||||
|
# 액세스 로그 포맷 (선택사항, 필요 시 주석 해제)
|
||||||
|
# 역할: 요청 로그 형식 커스터마이징
|
||||||
|
# 기본 포맷으로도 충분, 상세 정보 필요 시 활성화
|
||||||
|
access_log_format = (
|
||||||
|
'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s %(p)s'
|
||||||
|
)
|
||||||
|
|
||||||
|
# 워커 프로세스 이름 설정 (모니터링 시 유용)
|
||||||
|
proc_name = "fastapi_gunicorn"
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 성능 최적화
|
||||||
|
# ==========================================
|
||||||
|
# - 최대 2048개의 연결이 Accept Queue에서 대기 가능
|
||||||
|
# - 동시에 많은 연결 요청이 들어와도 2048개까지는 거부되지 않음
|
||||||
|
# - 실제 적용값 = min(2048, 시스템 somaxconn)
|
||||||
|
# 낮은 트래픽 (기본값 충분)
|
||||||
|
# backlog = 2048 # 기본값 사용
|
||||||
|
# workers = 4
|
||||||
|
#
|
||||||
|
# 높은 트래픽 (증가 필요)
|
||||||
|
# backlog = 4096
|
||||||
|
# workers = 8
|
||||||
|
# OS 설정도 함께 조정 필요
|
||||||
|
# /etc/sysctl.conf
|
||||||
|
# net.core.somaxconn = 4096
|
||||||
|
#
|
||||||
|
# 증가해야 할 때:
|
||||||
|
# ss -lnt 명령으로 Send-Q가 계속 가득 찬 경우
|
||||||
|
# ss -lnt | grep :8000
|
||||||
|
# 순간적인 트래픽 급증이 예상되는 경우
|
||||||
|
# connection refused 에러가 자주 발생하는 경우
|
||||||
|
|
||||||
|
backlog = 2048
|
||||||
|
|
||||||
|
# 임시 파일 디렉토리 (업로드 처리 시 사용)
|
||||||
|
# 재부팅 시 자동 삭제
|
||||||
|
# Gunicorn 기본값
|
||||||
|
# worker_tmp_dir = None # /tmp 디렉토리 사용 (디스크 기반)
|
||||||
|
# 사용하는 경우 (권장):
|
||||||
|
# 파일 업로드가 많은 서비스
|
||||||
|
# 큰 요청/응답 처리
|
||||||
|
# 충분한 RAM이 있는 경우
|
||||||
|
# RAM이 부족한 경우
|
||||||
|
# worker_tmp_dir = "/tmp" # 디스크 사용
|
||||||
|
# 파일 업로드/다운로드가 거의 없는 경우
|
||||||
|
# worker_tmp_dir = None # 기본값 사용
|
||||||
|
# Docker 사용시 고려 필요
|
||||||
|
# shm_size: '2gb' # /dev/shm 크기 증가
|
||||||
|
# volumes:
|
||||||
|
# - /dev/shm:/dev/shm # 호스트 공유 (선택)
|
||||||
|
|
||||||
|
# worker_tmp_dir = "/dev/shm" # RAM 기반 tmpfs 사용으로 I/O 성능 향상
|
||||||
|
worker_tmp_dir = None
|
||||||
|
|
||||||
|
"""
|
||||||
|
배포 전 체크리스트:
|
||||||
|
|
||||||
|
[권장]
|
||||||
|
1. 로그 로테이션 설정 (logrotate)
|
||||||
|
2. 헬스체크 엔드포인트 구현 (/health)
|
||||||
|
3. 성능 테스트 (wrk, locust)
|
||||||
|
|
||||||
|
성능 모니터링:
|
||||||
|
# 프로세스 확인
|
||||||
|
ps aux | grep gunicorn
|
||||||
|
|
||||||
|
# 리소스 사용량
|
||||||
|
htop -p $(pgrep -d',' gunicorn)
|
||||||
|
|
||||||
|
# 로그 실시간 확인
|
||||||
|
tail -f /log/uvicorn/access_*.log
|
||||||
|
tail -f /log/uvicorn/error_*.log
|
||||||
|
|
||||||
|
설정 최적화 가이드:
|
||||||
|
- workers: CPU 사용률 80% 이하 유지
|
||||||
|
- timeout: 응답 시간 + 여유분 (평균 * 2)
|
||||||
|
- max_requests: 메모리 누수 없으면 5000-10000으로 증가
|
||||||
|
- keepalive: Nginx keepalive_timeout보다 짧게
|
||||||
|
"""
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- 1. admin 권한 계정 생성
|
||||||
|
CREATE USER IF NOT EXISTS 'devadmin'@'%' IDENTIFIED BY 'test!';
|
||||||
|
-- 2. 전체 권한 부여
|
||||||
|
GRANT ALL PRIVILEGES ON *.* TO 'devadmin'@'%' WITH GRANT OPTION;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
@ -0,0 +1,546 @@
|
||||||
|
# ========================================================================
|
||||||
|
# Percona Server / MySQL 8.0 최적화 설정
|
||||||
|
# 하드웨어 사양: 4코어 CPU, 4GB RAM, SSD, 1GB LAN
|
||||||
|
# ========================================================================
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 기본 경로 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
datadir=/var/lib/mysql
|
||||||
|
socket=/var/lib/mysql/mysql.sock
|
||||||
|
pid-file=/var/run/mysqld/mysqld.pid
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 네트워크 및 연결 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 바인드 주소
|
||||||
|
bind-address = 0.0.0.0
|
||||||
|
# 기본값: 127.0.0.1 (로컬만)
|
||||||
|
# 변경값: 0.0.0.0 (모든 IP)
|
||||||
|
# 목적: 원격 접속 허용
|
||||||
|
# 보안: 방화벽 설정 필수
|
||||||
|
|
||||||
|
# 포트
|
||||||
|
port = 3306
|
||||||
|
# 기본값: 3306
|
||||||
|
# MySQL 표준 포트
|
||||||
|
|
||||||
|
# 최대 연결 수
|
||||||
|
max_connections = 200
|
||||||
|
# 기본값: 151
|
||||||
|
# 변경값: 200
|
||||||
|
# 목적: 4GB RAM 환경에서 충분한 연결 수 제공
|
||||||
|
# 계산: 각 연결당 약 4-8MB 메모리 사용
|
||||||
|
# 200 연결 = 최대 1.6GB 메모리 (버퍼 포함)
|
||||||
|
# 참고: 연결 풀링(ProxySQL, MaxScale) 사용 시 더 효율적
|
||||||
|
|
||||||
|
max_connect_errors = 1000000
|
||||||
|
# 기본값: 100
|
||||||
|
# 변경값: 1000000
|
||||||
|
# 목적: 연결 오류로 인한 호스트 차단 방지
|
||||||
|
# 성능: 네트워크 이슈로 인한 불필요한 차단 감소
|
||||||
|
|
||||||
|
# 대기 시간 설정
|
||||||
|
wait_timeout = 600
|
||||||
|
# 기본값: 28800 (8시간)
|
||||||
|
# 변경값: 600 (10분)
|
||||||
|
# 목적: 유휴 연결 자동 정리
|
||||||
|
# 성능: 불필요한 연결 점유 방지
|
||||||
|
|
||||||
|
interactive_timeout = 600
|
||||||
|
# 기본값: 28800
|
||||||
|
# 변경값: 600
|
||||||
|
# 목적: 대화형 클라이언트 타임아웃
|
||||||
|
# 성능: 리소스 효율적 관리
|
||||||
|
|
||||||
|
connect_timeout = 10
|
||||||
|
# 기본값: 10
|
||||||
|
# 유지 이유: 연결 시도 타임아웃
|
||||||
|
|
||||||
|
# 스레드 캐시
|
||||||
|
thread_cache_size = 50
|
||||||
|
# 기본값: 8
|
||||||
|
# 변경값: 50
|
||||||
|
# 목적: 스레드 재사용으로 연결 생성 오버헤드 감소
|
||||||
|
# 성능: 연결 빈도가 높은 환경에서 효과적
|
||||||
|
# 계산: max_connections의 약 25%
|
||||||
|
|
||||||
|
# 백로그 큐
|
||||||
|
back_log = 512
|
||||||
|
# 기본값: 80
|
||||||
|
# 변경값: 512
|
||||||
|
# 목적: 대기 중인 연결 요청 큐 크기
|
||||||
|
# 성능: 트래픽 버스트 시 연결 손실 방지
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# InnoDB 버퍼 풀 설정 (가장 중요!)
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
innodb_buffer_pool_size = 2G
|
||||||
|
# 기본값: 128MB
|
||||||
|
# 변경값: 2GB (전체 RAM 4GB의 50%)
|
||||||
|
# 목적: 데이터와 인덱스를 메모리에 캐싱
|
||||||
|
# 성능: 디스크 I/O를 크게 감소시키는 가장 중요한 설정
|
||||||
|
# 권장: 전용 서버는 RAM의 70-80%, 혼합 환경은 50-60%
|
||||||
|
# 계산: 2GB buffer pool + 1GB 연결/쿼리 + 1GB OS/기타
|
||||||
|
|
||||||
|
innodb_buffer_pool_instances = 4
|
||||||
|
# 기본값: 1 (또는 자동)
|
||||||
|
# 변경값: 4
|
||||||
|
# 목적: 버퍼 풀을 여러 인스턴스로 분할하여 동시성 향상
|
||||||
|
# 성능: 멀티 코어 환경에서 잠금 경합 감소
|
||||||
|
# 권장: CPU 코어 수와 동일하게 설정
|
||||||
|
# 참고: buffer_pool_size >= 1GB일 때만 효과적
|
||||||
|
|
||||||
|
innodb_buffer_pool_chunk_size = 128M
|
||||||
|
# 기본값: 128MB
|
||||||
|
# 유지 이유: buffer_pool_size가 instances × chunk_size의 배수여야 함
|
||||||
|
# 계산: 2GB = 4 instances × 4 chunks × 128MB
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# InnoDB 로그 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
innodb_log_file_size = 512M
|
||||||
|
# 기본값: 48MB
|
||||||
|
# 변경값: 512MB
|
||||||
|
# 목적: Redo 로그 파일 크기
|
||||||
|
# 성능: 쓰기 집약적 워크로드에서 체크포인트 빈도 감소
|
||||||
|
# 권장: buffer_pool_size의 25% 정도
|
||||||
|
# 주의: 너무 크면 크래시 복구 시간 증가
|
||||||
|
|
||||||
|
innodb_log_buffer_size = 32M
|
||||||
|
# 기본값: 16MB
|
||||||
|
# 변경값: 32MB
|
||||||
|
# 목적: Redo 로그 버퍼
|
||||||
|
# 성능: 디스크 쓰기 전 로그를 메모리에 버퍼링
|
||||||
|
# 권장: 대용량 트랜잭션이 많으면 증가
|
||||||
|
|
||||||
|
innodb_flush_log_at_trx_commit = 1
|
||||||
|
# 기본값: 1
|
||||||
|
# 유지 이유: ACID 보장 (데이터 무결성)
|
||||||
|
# 옵션:
|
||||||
|
# 0: 로그를 메모리에만 (속도↑, 안정성↓↓)
|
||||||
|
# 1: 매 커밋마다 디스크에 flush (속도↓, 안정성↑↑) ← 권장
|
||||||
|
# 2: OS 캐시까지만 (속도↑, 안정성↑)
|
||||||
|
# 주의: 성능을 위해 2로 변경 가능하나 크래시 시 1초 데이터 손실
|
||||||
|
|
||||||
|
innodb_flush_method = O_DIRECT
|
||||||
|
# 기본값: fsync (Linux)
|
||||||
|
# 변경값: O_DIRECT
|
||||||
|
# 목적: OS 파일 시스템 캐시 우회
|
||||||
|
# 성능: 이중 버퍼링 방지, SSD 환경에서 효과적
|
||||||
|
# 권장: SSD 사용 시 필수 설정
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# InnoDB I/O 설정 (SSD 최적화)
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
innodb_io_capacity = 2000
|
||||||
|
# 기본값: 200 (HDD 기준)
|
||||||
|
# 변경값: 2000
|
||||||
|
# 목적: InnoDB가 초당 수행할 수 있는 I/O 작업 수
|
||||||
|
# 성능: SSD의 높은 IOPS 활용
|
||||||
|
# 권장: SSD는 2000-5000, NVMe는 10000+
|
||||||
|
# 측정: fio 벤치마크로 실제 IOPS 측정 후 70% 수준으로 설정
|
||||||
|
|
||||||
|
innodb_io_capacity_max = 4000
|
||||||
|
# 기본값: 2000
|
||||||
|
# 변경값: 4000 (io_capacity의 2배)
|
||||||
|
# 목적: 긴급 상황(체크포인트 등)에서 최대 I/O
|
||||||
|
# 성능: 버스트 상황에서 더 많은 I/O 허용
|
||||||
|
|
||||||
|
innodb_read_io_threads = 4
|
||||||
|
# 기본값: 4
|
||||||
|
# 유지 이유: CPU 코어 수와 일치
|
||||||
|
# 목적: 읽기 작업을 위한 I/O 스레드
|
||||||
|
|
||||||
|
innodb_write_io_threads = 4
|
||||||
|
# 기본값: 4
|
||||||
|
# 유지 이유: CPU 코어 수와 일치
|
||||||
|
# 목적: 쓰기 작업을 위한 I/O 스레드
|
||||||
|
|
||||||
|
innodb_flush_neighbors = 0
|
||||||
|
# 기본값: 1 (HDD 최적화)
|
||||||
|
# 변경값: 0
|
||||||
|
# 목적: 인접 페이지 flush 비활성화
|
||||||
|
# 성능: SSD는 랜덤 쓰기가 빠르므로 불필요
|
||||||
|
# 권장: SSD 환경에서는 반드시 0으로 설정
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# InnoDB 동시성 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
innodb_thread_concurrency = 0
|
||||||
|
# 기본값: 0 (무제한)
|
||||||
|
# 유지 이유: MySQL이 자동으로 최적화
|
||||||
|
# 목적: 동시 실행 스레드 수 제한
|
||||||
|
# 참고: 특정 워크로드에서 제한이 필요한 경우 CPU 코어 수 × 2
|
||||||
|
|
||||||
|
innodb_lock_wait_timeout = 50
|
||||||
|
# 기본값: 50
|
||||||
|
# 유지 이유: 락 대기 타임아웃 (초)
|
||||||
|
# 성능: 데드락 상황 빠른 감지
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 테이블 및 파일 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
innodb_file_per_table = ON
|
||||||
|
# 기본값: ON (MySQL 5.6.6+)
|
||||||
|
# 유지 이유: 테이블별로 별도 파일 생성
|
||||||
|
# 성능: 테이블 삭제 시 공간 즉시 반환, 관리 용이
|
||||||
|
|
||||||
|
innodb_open_files = 2000
|
||||||
|
# 기본값: 300
|
||||||
|
# 변경값: 2000
|
||||||
|
# 목적: InnoDB가 동시에 열 수 있는 파일 수
|
||||||
|
# 성능: 많은 테이블이 있을 때 파일 열기 오버헤드 감소
|
||||||
|
|
||||||
|
table_open_cache = 4000
|
||||||
|
# 기본값: 2000
|
||||||
|
# 변경값: 4000
|
||||||
|
# 목적: 열린 테이블 캐시
|
||||||
|
# 성능: 테이블 열기/닫기 오버헤드 감소
|
||||||
|
# 계산: max_connections × 평균 조인 테이블 수
|
||||||
|
|
||||||
|
table_open_cache_instances = 16
|
||||||
|
# 기본값: 16
|
||||||
|
# 유지 이유: 캐시를 여러 인스턴스로 분할
|
||||||
|
# 성능: 동시성 향상
|
||||||
|
|
||||||
|
table_definition_cache = 2000
|
||||||
|
# 기본값: 400
|
||||||
|
# 변경값: 2000
|
||||||
|
# 목적: 테이블 정의 캐시 (.frm 파일)
|
||||||
|
# 성능: 테이블 메타데이터 접근 속도 향상
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 쿼리 캐시 (MySQL 8.0에서는 제거됨)
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# MySQL 8.0에서는 쿼리 캐시가 제거되었습니다.
|
||||||
|
# 대신 애플리케이션 레벨 캐싱(Redis, Memcached) 사용 권장
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 임시 테이블 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tmp_table_size = 64M
|
||||||
|
# 기본값: 16MB
|
||||||
|
# 변경값: 64MB
|
||||||
|
# 목적: 메모리 내 임시 테이블 최대 크기
|
||||||
|
# 성능: 복잡한 쿼리의 임시 테이블을 메모리에 유지
|
||||||
|
# 주의: max_heap_table_size와 함께 설정
|
||||||
|
|
||||||
|
max_heap_table_size = 64M
|
||||||
|
# 기본값: 16MB
|
||||||
|
# 변경값: 64MB
|
||||||
|
# 목적: MEMORY 테이블 최대 크기
|
||||||
|
# 성능: tmp_table_size와 동일하게 설정
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 정렬 및 조인 버퍼
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sort_buffer_size = 4M
|
||||||
|
# 기본값: 256KB
|
||||||
|
# 변경값: 4MB
|
||||||
|
# 목적: 정렬 작업에 사용되는 버퍼
|
||||||
|
# 성능: ORDER BY, GROUP BY 성능 향상
|
||||||
|
# 주의: 세션별로 할당되므로 너무 크면 메모리 부족
|
||||||
|
# 계산: 200 연결 × 4MB = 최대 800MB
|
||||||
|
|
||||||
|
read_buffer_size = 2M
|
||||||
|
# 기본값: 128KB
|
||||||
|
# 변경값: 2MB
|
||||||
|
# 목적: 순차 스캔 버퍼
|
||||||
|
# 성능: 전체 테이블 스캔 시 성능 향상
|
||||||
|
|
||||||
|
read_rnd_buffer_size = 4M
|
||||||
|
# 기본값: 256KB
|
||||||
|
# 변경값: 4MB
|
||||||
|
# 목적: 정렬 후 행 읽기 버퍼
|
||||||
|
# 성능: ORDER BY 후 행 검색 속도 향상
|
||||||
|
|
||||||
|
join_buffer_size = 4M
|
||||||
|
# 기본값: 256KB
|
||||||
|
# 변경값: 4MB
|
||||||
|
# 목적: 인덱스를 사용하지 않는 조인 버퍼
|
||||||
|
# 성능: 조인 성능 향상
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 바이너리 로그 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 바이너리 로그 활성화 (복제 및 Point-in-Time 복구에 필수)
|
||||||
|
# log_bin = /var/lib/mysql/mysql-bin
|
||||||
|
# 목적: 데이터 변경 사항 기록
|
||||||
|
# 용도: 복제(Replication), 백업, 복구
|
||||||
|
# 참고: 복제를 사용하지 않으면 disable_log_bin 설정 가능
|
||||||
|
|
||||||
|
server_id = 1
|
||||||
|
# 기본값: 1
|
||||||
|
# 목적: 복제 환경에서 서버 식별자
|
||||||
|
# 참고: 각 서버마다 고유한 값 필요
|
||||||
|
|
||||||
|
binlog_format = ROW
|
||||||
|
# 기본값: ROW (MySQL 8.0+)
|
||||||
|
# 옵션:
|
||||||
|
# STATEMENT: SQL 문 저장 (크기↓, 안정성↓)
|
||||||
|
# ROW: 실제 행 변경 저장 (크기↑, 안정성↑) ← 권장
|
||||||
|
# MIXED: 자동 선택
|
||||||
|
# 권장: ROW (가장 안전하고 일관성 있음)
|
||||||
|
|
||||||
|
binlog_expire_logs_seconds = 604800
|
||||||
|
# 기본값: 2592000 (30일)
|
||||||
|
# 변경값: 604800 (7일)
|
||||||
|
# 목적: 오래된 바이너리 로그 자동 삭제
|
||||||
|
# 성능: 디스크 공간 관리
|
||||||
|
# 참고: 백업 주기에 따라 조정
|
||||||
|
|
||||||
|
max_binlog_size = 100M
|
||||||
|
# 기본값: 1GB
|
||||||
|
# 변경값: 100MB
|
||||||
|
# 목적: 단일 바이너리 로그 파일 최대 크기
|
||||||
|
# 성능: 작은 파일로 관리 용이성 향상
|
||||||
|
|
||||||
|
sync_binlog = 1
|
||||||
|
# 기본값: 1
|
||||||
|
# 유지 이유: 매 커밋마다 바이너리 로그를 디스크에 동기화
|
||||||
|
# 성능: 안정성 최우선 (크래시 시 데이터 손실 방지)
|
||||||
|
# 참고: 성능이 중요하면 0으로 설정 가능하나 권장하지 않음
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 에러 로그 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# log_error = /var/log/mysql/error.log
|
||||||
|
log_error = /var/log/mysqld.log
|
||||||
|
# 목적: 에러 로그 파일 위치
|
||||||
|
# 참고: 디렉토리가 존재하고 mysql 사용자가 쓰기 권한 필요
|
||||||
|
|
||||||
|
log_error_verbosity = 2
|
||||||
|
# 기본값: 2
|
||||||
|
# 옵션: 1 (오류만), 2 (오류+경고), 3 (오류+경고+정보)
|
||||||
|
# 권장: 2 (운영 환경)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 슬로우 쿼리 로그
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# slow_query_log = 1
|
||||||
|
# 기본값: 0 (비활성화)
|
||||||
|
# 변경값: 1 (활성화)
|
||||||
|
# 목적: 느린 쿼리 기록
|
||||||
|
# 성능: 쿼리 최적화에 필수
|
||||||
|
|
||||||
|
slow_query_log_file = /var/log/mysql/slow-query.log
|
||||||
|
# 목적: 슬로우 쿼리 로그 파일 위치
|
||||||
|
|
||||||
|
long_query_time = 2
|
||||||
|
# 기본값: 10
|
||||||
|
# 변경값: 2
|
||||||
|
# 목적: 2초 이상 걸리는 쿼리 기록
|
||||||
|
# 권장: 1-2초 (애플리케이션 특성에 따라 조정)
|
||||||
|
|
||||||
|
log_queries_not_using_indexes = 1
|
||||||
|
# 기본값: 0
|
||||||
|
# 변경값: 1
|
||||||
|
# 목적: 인덱스를 사용하지 않는 쿼리도 기록
|
||||||
|
# 성능: 인덱스 누락 쿼리 발견
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 일반 쿼리 로그 (개발 환경에서만 사용)
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 운영 환경에서는 비활성화 권장 (과도한 로그 생성)
|
||||||
|
# general_log = 0
|
||||||
|
# general_log_file = /var/log/mysql/general.log
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 문자셋 및 콜레이션
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
character_set_server = utf8mb4
|
||||||
|
# 기본값: utf8mb4 (MySQL 8.0+)
|
||||||
|
# 목적: 서버 기본 문자셋
|
||||||
|
# 참고: 이모지 등 4바이트 문자 지원
|
||||||
|
|
||||||
|
collation_server = utf8mb4_unicode_ci
|
||||||
|
# 기본값: utf8mb4_0900_ai_ci (MySQL 8.0+)
|
||||||
|
# 변경값: utf8mb4_unicode_ci
|
||||||
|
# 목적: 다국어 정렬 규칙
|
||||||
|
# 참고: 호환성을 위해 unicode_ci 사용
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# SQL 모드
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
|
||||||
|
# 기본값: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,... (MySQL 8.0+)
|
||||||
|
# 목적: SQL 엄격 모드 설정
|
||||||
|
# 권장: STRICT_TRANS_TABLES (데이터 무결성)
|
||||||
|
# 참고: 레거시 애플리케이션은 모드 조정 필요
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 타임존
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# default_time_zone = '+09:00'
|
||||||
|
# 기본값: SYSTEM
|
||||||
|
# 변경값: '+09:00' (한국 시간)
|
||||||
|
# 목적: 서버 타임존 설정
|
||||||
|
# 참고: 글로벌 서비스는 '+00:00' (UTC) 권장
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 성능 스키마 (Performance Schema)
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
performance_schema = ON
|
||||||
|
# 기본값: ON
|
||||||
|
# 유지 이유: 성능 모니터링 및 진단
|
||||||
|
# 참고: 약간의 오버헤드 있지만 필수 모니터링 도구
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 보안 설정
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 로컬 파일 로드 비활성화 (보안)
|
||||||
|
local_infile = 0
|
||||||
|
# 기본값: 0 (MySQL 8.0+)
|
||||||
|
# 목적: LOAD DATA LOCAL INFILE 비활성화
|
||||||
|
# 보안: 로컬 파일 접근 방지
|
||||||
|
|
||||||
|
# 심볼릭 링크 비활성화
|
||||||
|
symbolic_links = 0
|
||||||
|
# 기본값: 0
|
||||||
|
# 목적: 심볼릭 링크 사용 비활성화
|
||||||
|
# 보안: 디렉토리 탐색 공격 방지
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 기타 최적화
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 쿼리 결과 캐시 (애플리케이션 레벨 권장)
|
||||||
|
# MySQL 8.0에서는 쿼리 캐시 제거됨
|
||||||
|
|
||||||
|
# 오픈 파일 제한
|
||||||
|
open_files_limit = 65535
|
||||||
|
# 기본값: 5000
|
||||||
|
# 변경값: 65535
|
||||||
|
# 목적: 동시에 열 수 있는 파일 수
|
||||||
|
# 성능: 많은 테이블과 연결을 처리할 때 필요
|
||||||
|
|
||||||
|
# 최대 허용 패킷 크기
|
||||||
|
max_allowed_packet = 64M
|
||||||
|
# 기본값: 64MB (MySQL 8.0+)
|
||||||
|
# 유지 이유: 대용량 데이터 처리
|
||||||
|
# 참고: 필요시 증가 가능 (최대 1GB)
|
||||||
|
|
||||||
|
# 그룹 커밋 최적화
|
||||||
|
binlog_group_commit_sync_delay = 0
|
||||||
|
# 기본값: 0
|
||||||
|
# 목적: 바이너리 로그 그룹 커밋 지연 (마이크로초)
|
||||||
|
# 성능: 0보다 크면 처리량 증가, 지연 약간 증가
|
||||||
|
# 참고: 초당 수천 개 트랜잭션 환경에서 1000-10000 설정
|
||||||
|
|
||||||
|
binlog_group_commit_sync_no_delay_count = 0
|
||||||
|
# 기본값: 0
|
||||||
|
# 목적: 지연 없이 커밋할 트랜잭션 수
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# 설정 파일 추가 포함
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
!includedir /etc/my.cnf.d
|
||||||
|
|
||||||
|
# ========================================================================
|
||||||
|
# 주요 변경사항 요약
|
||||||
|
# ========================================================================
|
||||||
|
#
|
||||||
|
# 1. 메모리 설정 (4GB RAM 기준)
|
||||||
|
# - innodb_buffer_pool_size: 128MB → 2GB (50% of RAM)
|
||||||
|
# - tmp_table_size / max_heap_table_size: 16MB → 64MB
|
||||||
|
# - sort_buffer_size: 256KB → 4MB
|
||||||
|
# - read_buffer_size: 128KB → 2MB
|
||||||
|
# - join_buffer_size: 256KB → 4MB
|
||||||
|
#
|
||||||
|
# 2. 연결 설정
|
||||||
|
# - max_connections: 151 → 200
|
||||||
|
# - thread_cache_size: 8 → 50
|
||||||
|
# - wait_timeout: 28800 → 600 (10분)
|
||||||
|
#
|
||||||
|
# 3. InnoDB 최적화 (SSD 특화)
|
||||||
|
# - innodb_io_capacity: 200 → 2000
|
||||||
|
# - innodb_io_capacity_max: 2000 → 4000
|
||||||
|
# - innodb_flush_neighbors: 1 → 0 (SSD 최적화)
|
||||||
|
# - innodb_flush_method: fsync → O_DIRECT
|
||||||
|
#
|
||||||
|
# 4. 로그 설정
|
||||||
|
# - innodb_log_file_size: 48MB → 512MB
|
||||||
|
# - innodb_log_buffer_size: 16MB → 32MB
|
||||||
|
# - slow_query_log: 활성화 (2초 이상 쿼리)
|
||||||
|
#
|
||||||
|
# 5. 버퍼 풀 설정
|
||||||
|
# - innodb_buffer_pool_instances: 1 → 4 (CPU 코어 수)
|
||||||
|
#
|
||||||
|
# ========================================================================
|
||||||
|
# 예상 성능 향상
|
||||||
|
# ========================================================================
|
||||||
|
#
|
||||||
|
# - 읽기 성능: 40-60% 향상 (innodb_buffer_pool_size 증가)
|
||||||
|
# - 쓰기 성능: 30-50% 향상 (SSD 최적화, 로그 버퍼 증가)
|
||||||
|
# - 복잡한 쿼리: 50-100% 향상 (정렬/조인 버퍼 증가)
|
||||||
|
# - 동시 연결: 연결 처리 능력 향상 (thread_cache, max_connections)
|
||||||
|
# - 전체 처리량: 30-50% 향상
|
||||||
|
#
|
||||||
|
# ========================================================================
|
||||||
|
# 적용 방법
|
||||||
|
# ========================================================================
|
||||||
|
#
|
||||||
|
# 1. 이 파일을 /etc/my.cnf로 저장 (기존 파일 백업)
|
||||||
|
# sudo cp /etc/my.cnf /etc/my.cnf.backup
|
||||||
|
# sudo vi /etc/my.cnf
|
||||||
|
#
|
||||||
|
# 2. 로그 디렉토리 생성 및 권한 설정
|
||||||
|
# sudo mkdir -p /var/log/mysql
|
||||||
|
# sudo chown mysql:mysql /var/log/mysql
|
||||||
|
# sudo chmod 755 /var/log/mysql
|
||||||
|
#
|
||||||
|
# 3. MySQL 재시작
|
||||||
|
# sudo systemctl restart mysql
|
||||||
|
# 또는
|
||||||
|
# sudo service mysql restart
|
||||||
|
#
|
||||||
|
# 4. 설정 확인
|
||||||
|
# mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
|
||||||
|
# mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"
|
||||||
|
#
|
||||||
|
# 5. 슬로우 쿼리 로그 분석 (정기적으로)
|
||||||
|
# mysqldumpslow /var/log/mysql/slow-query.log
|
||||||
|
#
|
||||||
|
# 6. 성능 모니터링
|
||||||
|
# mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G"
|
||||||
|
# mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Threads%';"
|
||||||
|
#
|
||||||
|
# ========================================================================
|
||||||
|
# Docker 환경 주의사항
|
||||||
|
# ========================================================================
|
||||||
|
#
|
||||||
|
# Docker 환경에서 사용 시:
|
||||||
|
# 1. 로그 디렉토리를 볼륨 마운트
|
||||||
|
# volumes:
|
||||||
|
# - ./logs/mysql:/var/log/mysql
|
||||||
|
#
|
||||||
|
# 2. 권한 문제 방지
|
||||||
|
# - 컨테이너 시작 전 호스트에서 디렉토리 생성
|
||||||
|
# mkdir -p ./logs/mysql
|
||||||
|
# chmod 777 ./logs/mysql # 또는 적절한 권한
|
||||||
|
#
|
||||||
|
# 3. 메모리 제한 확인
|
||||||
|
# - Docker 컨테이너에 최소 4GB RAM 할당
|
||||||
|
#
|
||||||
|
# ========================================================================
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
CREATE ROLE IF NOT EXISTS devadmin WITH
|
||||||
|
LOGIN
|
||||||
|
PASSWORD 'test!'
|
||||||
|
SUPERUSER;
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
# PostgreSQL Client Authentication Configuration File
|
||||||
|
# ===================================================
|
||||||
|
#
|
||||||
|
# Refer to the "Client Authentication" section in the PostgreSQL
|
||||||
|
# documentation for a complete description of this file. A short
|
||||||
|
# synopsis follows.
|
||||||
|
#
|
||||||
|
# ----------------------
|
||||||
|
# Authentication Records
|
||||||
|
# ----------------------
|
||||||
|
#
|
||||||
|
# This file controls: which hosts are allowed to connect, how clients
|
||||||
|
# are authenticated, which PostgreSQL user names they can use, which
|
||||||
|
# databases they can access. Records take one of these forms:
|
||||||
|
#
|
||||||
|
# local DATABASE USER METHOD [OPTIONS]
|
||||||
|
# host DATABASE USER ADDRESS METHOD [OPTIONS]
|
||||||
|
# hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
|
||||||
|
# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS]
|
||||||
|
# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS]
|
||||||
|
# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS]
|
||||||
|
#
|
||||||
|
# (The uppercase items must be replaced by actual values.)
|
||||||
|
#
|
||||||
|
# The first field is the connection type:
|
||||||
|
# - "local" is a Unix-domain socket
|
||||||
|
# - "host" is a TCP/IP socket (encrypted or not)
|
||||||
|
# - "hostssl" is a TCP/IP socket that is SSL-encrypted
|
||||||
|
# - "hostnossl" is a TCP/IP socket that is not SSL-encrypted
|
||||||
|
# - "hostgssenc" is a TCP/IP socket that is GSSAPI-encrypted
|
||||||
|
# - "hostnogssenc" is a TCP/IP socket that is not GSSAPI-encrypted
|
||||||
|
#
|
||||||
|
# DATABASE can be "all", "sameuser", "samerole", "replication", a
|
||||||
|
# database name, a regular expression (if it starts with a slash (/))
|
||||||
|
# or a comma-separated list thereof. The "all" keyword does not match
|
||||||
|
# "replication". Access to replication must be enabled in a separate
|
||||||
|
# record (see example below).
|
||||||
|
#
|
||||||
|
# USER can be "all", a user name, a group name prefixed with "+", a
|
||||||
|
# regular expression (if it starts with a slash (/)) or a comma-separated
|
||||||
|
# list thereof. In both the DATABASE and USER fields you can also write
|
||||||
|
# a file name prefixed with "@" to include names from a separate file.
|
||||||
|
#
|
||||||
|
# ADDRESS specifies the set of hosts the record matches. It can be a
|
||||||
|
# host name, or it is made up of an IP address and a CIDR mask that is
|
||||||
|
# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
|
||||||
|
# specifies the number of significant bits in the mask. A host name
|
||||||
|
# that starts with a dot (.) matches a suffix of the actual host name.
|
||||||
|
# Alternatively, you can write an IP address and netmask in separate
|
||||||
|
# columns to specify the set of hosts. Instead of a CIDR-address, you
|
||||||
|
# can write "samehost" to match any of the server's own IP addresses,
|
||||||
|
# or "samenet" to match any address in any subnet that the server is
|
||||||
|
# directly connected to.
|
||||||
|
#
|
||||||
|
# METHOD can be "trust", "reject", "md5", "password", "scram-sha-256",
|
||||||
|
# "gss", "sspi", "ident", "peer", "pam", "oauth", "ldap", "radius" or
|
||||||
|
# "cert". Note that "password" sends passwords in clear text; "md5" or
|
||||||
|
# "scram-sha-256" are preferred since they send encrypted passwords.
|
||||||
|
#
|
||||||
|
# OPTIONS are a set of options for the authentication in the format
|
||||||
|
# NAME=VALUE. The available options depend on the different
|
||||||
|
# authentication methods -- refer to the "Client Authentication"
|
||||||
|
# section in the documentation for a list of which options are
|
||||||
|
# available for which authentication methods.
|
||||||
|
#
|
||||||
|
# Database and user names containing spaces, commas, quotes and other
|
||||||
|
# special characters must be quoted. Quoting one of the keywords
|
||||||
|
# "all", "sameuser", "samerole" or "replication" makes the name lose
|
||||||
|
# its special character, and just match a database or username with
|
||||||
|
# that name.
|
||||||
|
#
|
||||||
|
# ---------------
|
||||||
|
# Include Records
|
||||||
|
# ---------------
|
||||||
|
#
|
||||||
|
# This file allows the inclusion of external files or directories holding
|
||||||
|
# more records, using the following keywords:
|
||||||
|
#
|
||||||
|
# include FILE
|
||||||
|
# include_if_exists FILE
|
||||||
|
# include_dir DIRECTORY
|
||||||
|
#
|
||||||
|
# FILE is the file name to include, and DIR is the directory name containing
|
||||||
|
# the file(s) to include. Any file in a directory will be loaded if suffixed
|
||||||
|
# with ".conf". The files of a directory are ordered by name.
|
||||||
|
# include_if_exists ignores missing files. FILE and DIRECTORY can be
|
||||||
|
# specified as a relative or an absolute path, and can be double-quoted if
|
||||||
|
# they contain spaces.
|
||||||
|
#
|
||||||
|
# -------------
|
||||||
|
# Miscellaneous
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# This file is read on server startup and when the server receives a
|
||||||
|
# SIGHUP signal. If you edit the file on a running system, you have to
|
||||||
|
# SIGHUP the server for the changes to take effect, run "pg_ctl reload",
|
||||||
|
# or execute "SELECT pg_reload_conf()".
|
||||||
|
#
|
||||||
|
# ----------------------------------
|
||||||
|
# Put your actual configuration here
|
||||||
|
# ----------------------------------
|
||||||
|
#
|
||||||
|
# If you want to allow non-local connections, you need to add more
|
||||||
|
# "host" records. In that case you will also need to make PostgreSQL
|
||||||
|
# listen on a non-local interface via the listen_addresses
|
||||||
|
# configuration parameter, or via the -i or -h command line switches.
|
||||||
|
|
||||||
|
# CAUTION: Configuring the system for local "trust" authentication
|
||||||
|
# allows any local user to connect as any PostgreSQL user, including
|
||||||
|
# the database superuser. If you do not trust all your local users,
|
||||||
|
# use another authentication method.
|
||||||
|
|
||||||
|
|
||||||
|
# TYPE DATABASE USER ADDRESS METHOD
|
||||||
|
|
||||||
|
# "local" is for Unix domain socket connections only
|
||||||
|
local all all trust
|
||||||
|
# IPv4 local connections:
|
||||||
|
host all all 127.0.0.1/32 trust
|
||||||
|
# IPv6 local connections:
|
||||||
|
host all all ::1/128 trust
|
||||||
|
# Allow replication connections from localhost, by a user with the
|
||||||
|
# replication privilege.
|
||||||
|
local replication all trust
|
||||||
|
host replication all 127.0.0.1/32 trust
|
||||||
|
host replication all ::1/128 trust
|
||||||
|
|
||||||
|
host all all all scram-sha-256
|
||||||
|
|
@ -0,0 +1,766 @@
|
||||||
|
# -----------------------------
|
||||||
|
# PostgreSQL 18 최적화 설정
|
||||||
|
# 하드웨어 사양: 4코어 CPU, 4GB RAM, SSD, 1GB LAN
|
||||||
|
# -----------------------------
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# FILE LOCATIONS
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#data_directory = 'ConfigDir'
|
||||||
|
#hba_file = 'ConfigDir/pg_hba.conf'
|
||||||
|
#ident_file = 'ConfigDir/pg_ident.conf'
|
||||||
|
#external_pid_file = ''
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# CONNECTIONS AND AUTHENTICATION
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Connection Settings -
|
||||||
|
|
||||||
|
listen_addresses = '*'
|
||||||
|
# 기본값: 'localhost'
|
||||||
|
# 변경값: '*' (모든 IP에서 접근 허용)
|
||||||
|
# 목적: 네트워크를 통한 원격 접속 허용
|
||||||
|
|
||||||
|
#port = 5432
|
||||||
|
|
||||||
|
max_connections = 100
|
||||||
|
# 기본값: 100
|
||||||
|
# 유지 이유: 4GB RAM 환경에서 적절한 연결 수
|
||||||
|
# 성능: 각 연결은 약 10MB의 메모리를 사용하므로 100개 연결 = 약 1GB
|
||||||
|
# 참고: 연결 풀링(pgBouncer 등) 사용 시 더 효율적
|
||||||
|
|
||||||
|
#reserved_connections = 0
|
||||||
|
#superuser_reserved_connections = 3
|
||||||
|
#unix_socket_directories = '/var/run/postgresql'
|
||||||
|
#unix_socket_group = ''
|
||||||
|
#unix_socket_permissions = 0777
|
||||||
|
#bonjour = off
|
||||||
|
#bonjour_name = ''
|
||||||
|
|
||||||
|
# - TCP settings -
|
||||||
|
|
||||||
|
tcp_keepalives_idle = 60
|
||||||
|
# 기본값: 0 (시스템 기본값 사용, 보통 7200초)
|
||||||
|
# 변경값: 60초
|
||||||
|
# 목적: 유휴 연결을 60초마다 체크하여 죽은 연결을 빠르게 감지
|
||||||
|
# 성능: 네트워크 장애 시 빠른 연결 정리로 리소스 확보
|
||||||
|
|
||||||
|
tcp_keepalives_interval = 10
|
||||||
|
# 기본값: 0 (시스템 기본값 사용, 보통 75초)
|
||||||
|
# 변경값: 10초
|
||||||
|
# 목적: keepalive 재전송 간격
|
||||||
|
# 성능: 연결 문제를 빠르게 탐지
|
||||||
|
|
||||||
|
tcp_keepalives_count = 3
|
||||||
|
# 기본값: 0 (시스템 기본값 사용, 보통 9회)
|
||||||
|
# 변경값: 3회
|
||||||
|
# 목적: 연결 실패 판정까지의 재시도 횟수
|
||||||
|
# 성능: 60초 + (10초 × 3) = 최대 90초 내에 죽은 연결 정리
|
||||||
|
|
||||||
|
#tcp_user_timeout = 0
|
||||||
|
#client_connection_check_interval = 0
|
||||||
|
|
||||||
|
# - Authentication -
|
||||||
|
|
||||||
|
#authentication_timeout = 1min
|
||||||
|
#password_encryption = scram-sha-256
|
||||||
|
#scram_iterations = 4096
|
||||||
|
|
||||||
|
# - SSL -
|
||||||
|
|
||||||
|
#ssl = off
|
||||||
|
#ssl_ca_file = ''
|
||||||
|
#ssl_cert_file = 'server.crt'
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# RESOURCE USAGE (except WAL)
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Memory -
|
||||||
|
|
||||||
|
shared_buffers = 1GB
|
||||||
|
# 기본값: 128MB
|
||||||
|
# 변경값: 1GB (전체 RAM 4GB의 25%)
|
||||||
|
# 목적: 데이터베이스가 디스크에서 읽은 데이터를 캐시하는 메모리
|
||||||
|
# 성능: 자주 사용되는 데이터를 메모리에 유지하여 디스크 I/O 크게 감소
|
||||||
|
# 참고: PostgreSQL에서 가장 중요한 메모리 설정 중 하나
|
||||||
|
|
||||||
|
huge_pages = try
|
||||||
|
# 기본값: try
|
||||||
|
# 유지 이유: 가능한 경우 huge pages 사용으로 메모리 관리 효율 향상
|
||||||
|
# 성능: TLB 미스 감소, 대용량 shared_buffers 사용 시 특히 효과적
|
||||||
|
|
||||||
|
#huge_page_size = 0
|
||||||
|
#temp_buffers = 8MB
|
||||||
|
#max_prepared_transactions = 0
|
||||||
|
|
||||||
|
work_mem = 16MB
|
||||||
|
# 기본값: 4MB
|
||||||
|
# 변경값: 16MB
|
||||||
|
# 목적: 정렬, 해시 테이블 등 쿼리 작업에 사용되는 메모리
|
||||||
|
# 성능: 복잡한 쿼리의 정렬/조인 성능 향상, 디스크 임시 파일 사용 감소
|
||||||
|
# 주의: (max_connections × work_mem)이 너무 크면 OOM 위험
|
||||||
|
# 계산: 100 연결 × 16MB = 최대 1.6GB (복잡한 쿼리가 동시 실행될 경우)
|
||||||
|
|
||||||
|
#hash_mem_multiplier = 2.0
|
||||||
|
|
||||||
|
maintenance_work_mem = 256MB
|
||||||
|
# 기본값: 64MB
|
||||||
|
# 변경값: 256MB (RAM의 약 6%)
|
||||||
|
# 목적: VACUUM, CREATE INDEX, ALTER TABLE 등 유지보수 작업에 사용
|
||||||
|
# 성능: 인덱스 생성 및 VACUUM 작업 속도 대폭 향상
|
||||||
|
# 참고: 유지보수 작업은 동시에 많이 실행되지 않으므로 크게 설정 가능
|
||||||
|
|
||||||
|
autovacuum_work_mem = 256MB
|
||||||
|
# 기본값: -1 (maintenance_work_mem 사용)
|
||||||
|
# 변경값: 256MB
|
||||||
|
# 목적: autovacuum 전용 메모리 할당
|
||||||
|
# 성능: autovacuum 성능 향상으로 테이블 bloat 감소
|
||||||
|
|
||||||
|
#logical_decoding_work_mem = 64MB
|
||||||
|
|
||||||
|
max_stack_depth = 2MB
|
||||||
|
# 기본값: 2MB
|
||||||
|
# 유지 이유: 기본값이 대부분의 경우에 적절
|
||||||
|
|
||||||
|
#shared_memory_type = mmap
|
||||||
|
|
||||||
|
dynamic_shared_memory_type = posix
|
||||||
|
# 기본값: posix (Linux에서)
|
||||||
|
# 유지 이유: Linux에서 가장 효율적인 방식
|
||||||
|
|
||||||
|
#min_dynamic_shared_memory = 0MB
|
||||||
|
|
||||||
|
# - Disk -
|
||||||
|
|
||||||
|
#temp_file_limit = -1
|
||||||
|
#file_copy_method = copy
|
||||||
|
|
||||||
|
# - Kernel Resources -
|
||||||
|
|
||||||
|
#max_files_per_process = 1000
|
||||||
|
|
||||||
|
# - Background Writer -
|
||||||
|
|
||||||
|
bgwriter_delay = 200ms
|
||||||
|
# 기본값: 200ms
|
||||||
|
# 유지 이유: SSD 환경에서도 기본값이 적절
|
||||||
|
|
||||||
|
bgwriter_lru_maxpages = 100
|
||||||
|
# 기본값: 100
|
||||||
|
# 유지 이유: 백그라운드 쓰기 작업의 균형 유지
|
||||||
|
|
||||||
|
#bgwriter_lru_multiplier = 2.0
|
||||||
|
|
||||||
|
bgwriter_flush_after = 512kB
|
||||||
|
# 기본값: 512kB
|
||||||
|
# 유지 이유: SSD에서 적절한 flush 크기
|
||||||
|
|
||||||
|
# - I/O -
|
||||||
|
|
||||||
|
#backend_flush_after = 0
|
||||||
|
|
||||||
|
effective_io_concurrency = 200
|
||||||
|
# 기본값: 1 (HDD), 16 (SSD 감지 시)
|
||||||
|
# 변경값: 200
|
||||||
|
# 목적: SSD의 높은 IOPS를 활용한 병렬 I/O 요청 수
|
||||||
|
# 성능: bitmap heap scan 등에서 여러 페이지를 동시에 prefetch
|
||||||
|
# 참고: SSD는 동시 I/O 처리 능력이 뛰어나므로 높게 설정
|
||||||
|
|
||||||
|
maintenance_io_concurrency = 200
|
||||||
|
# 기본값: 10
|
||||||
|
# 변경값: 200
|
||||||
|
# 목적: VACUUM, CREATE INDEX 등 유지보수 작업의 병렬 I/O
|
||||||
|
# 성능: 유지보수 작업 속도 향상
|
||||||
|
|
||||||
|
#io_max_combine_limit = 128kB
|
||||||
|
#io_combine_limit = 128kB
|
||||||
|
#io_method = worker
|
||||||
|
#io_max_concurrency = -1
|
||||||
|
#io_workers = 3
|
||||||
|
|
||||||
|
# - Worker Processes -
|
||||||
|
|
||||||
|
max_worker_processes = 8
|
||||||
|
# 기본값: 8
|
||||||
|
# 유지 이유: 4코어 환경에서 적절 (코어 수 × 2)
|
||||||
|
# 성능: 병렬 쿼리, autovacuum 등 다양한 백그라운드 작업 처리
|
||||||
|
|
||||||
|
max_parallel_workers_per_gather = 2
|
||||||
|
# 기본값: 2
|
||||||
|
# 변경값: 2 (4코어 환경에서 적절)
|
||||||
|
# 목적: 단일 쿼리가 사용할 수 있는 최대 병렬 worker 수
|
||||||
|
# 성능: 대용량 테이블 스캔 시 쿼리 속도 향상
|
||||||
|
# 참고: 너무 높으면 다른 쿼리의 리소스 부족 발생 가능
|
||||||
|
|
||||||
|
max_parallel_maintenance_workers = 2
|
||||||
|
# 기본값: 2
|
||||||
|
# 유지 이유: CREATE INDEX 등 유지보수 작업의 병렬화
|
||||||
|
# 성능: 인덱스 생성 속도 향상
|
||||||
|
|
||||||
|
max_parallel_workers = 4
|
||||||
|
# 기본값: 8
|
||||||
|
# 변경값: 4 (CPU 코어 수)
|
||||||
|
# 목적: 시스템 전체에서 동시 실행 가능한 병렬 worker 총 수
|
||||||
|
# 성능: CPU 코어 수에 맞춰 과도한 컨텍스트 스위칭 방지
|
||||||
|
|
||||||
|
#parallel_leader_participation = on
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# WRITE-AHEAD LOG
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Settings -
|
||||||
|
|
||||||
|
#wal_level = replica
|
||||||
|
#fsync = on
|
||||||
|
#synchronous_commit = on
|
||||||
|
#wal_sync_method = fsync
|
||||||
|
#full_page_writes = on
|
||||||
|
#wal_log_hints = off
|
||||||
|
|
||||||
|
wal_compression = lz4
|
||||||
|
# 기본값: off
|
||||||
|
# 변경값: lz4
|
||||||
|
# 목적: WAL 파일 압축으로 I/O 및 스토리지 사용량 감소
|
||||||
|
# 성능: 네트워크를 통한 복제 시 대역폭 절약, 아카이빙 효율 향상
|
||||||
|
# 참고: CPU 사용량은 약간 증가하지만 4코어 환경에서 무리 없음
|
||||||
|
|
||||||
|
#wal_init_zero = on
|
||||||
|
#wal_recycle = on
|
||||||
|
|
||||||
|
wal_buffers = 16MB
|
||||||
|
# 기본값: -1 (shared_buffers의 3%, 최소 64kB, 최대 약 16MB)
|
||||||
|
# 변경값: 16MB
|
||||||
|
# 목적: WAL 데이터를 디스크에 쓰기 전 버퍼링
|
||||||
|
# 성능: 쓰기 집약적 워크로드에서 WAL 쓰기 성능 향상
|
||||||
|
|
||||||
|
#wal_writer_delay = 200ms
|
||||||
|
|
||||||
|
wal_writer_flush_after = 1MB
|
||||||
|
# 기본값: 1MB
|
||||||
|
# 유지 이유: SSD에서 적절한 flush 크기
|
||||||
|
|
||||||
|
#wal_skip_threshold = 2MB
|
||||||
|
#commit_delay = 0
|
||||||
|
#commit_siblings = 5
|
||||||
|
|
||||||
|
# - Checkpoints -
|
||||||
|
|
||||||
|
checkpoint_timeout = 15min
|
||||||
|
# 기본값: 5min
|
||||||
|
# 변경값: 15min
|
||||||
|
# 목적: 체크포인트 발생 간격 조정
|
||||||
|
# 성능: 체크포인트 빈도 감소로 I/O spike 완화, 전체 성능 향상
|
||||||
|
# 참고: 크래시 복구 시간은 약간 증가하지만 일반적으로 허용 가능
|
||||||
|
|
||||||
|
checkpoint_completion_target = 0.9
|
||||||
|
# 기본값: 0.9
|
||||||
|
# 유지 이유: 체크포인트를 시간에 걸쳐 분산하여 I/O spike 방지
|
||||||
|
# 성능: 90%의 시간에 걸쳐 checkpoint 완료하여 부하 분산
|
||||||
|
|
||||||
|
#checkpoint_flush_after = 256kB
|
||||||
|
#checkpoint_warning = 30s
|
||||||
|
|
||||||
|
max_wal_size = 2GB
|
||||||
|
# 기본값: 1GB
|
||||||
|
# 변경값: 2GB
|
||||||
|
# 목적: 체크포인트 간 생성 가능한 최대 WAL 크기
|
||||||
|
# 성능: 쓰기 집약적 워크로드에서 체크포인트 빈도 감소
|
||||||
|
# 참고: SSD 환경에서 더 큰 WAL 크기는 성능에 유리
|
||||||
|
|
||||||
|
min_wal_size = 1GB
|
||||||
|
# 기본값: 80MB
|
||||||
|
# 변경값: 1GB
|
||||||
|
# 목적: 항상 유지할 최소 WAL 크기
|
||||||
|
# 성능: WAL 파일 재사용으로 파일 생성/삭제 오버헤드 감소
|
||||||
|
|
||||||
|
# - Prefetching during recovery -
|
||||||
|
|
||||||
|
#recovery_prefetch = try
|
||||||
|
#wal_decode_buffer_size = 512kB
|
||||||
|
|
||||||
|
# - Archiving -
|
||||||
|
|
||||||
|
#archive_mode = off
|
||||||
|
#archive_library = ''
|
||||||
|
#archive_command = ''
|
||||||
|
#archive_timeout = 0
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# REPLICATION
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Sending Servers -
|
||||||
|
|
||||||
|
#max_wal_senders = 10
|
||||||
|
#max_replication_slots = 10
|
||||||
|
#wal_keep_size = 0
|
||||||
|
#max_slot_wal_keep_size = -1
|
||||||
|
#idle_replication_slot_timeout = 0
|
||||||
|
#wal_sender_timeout = 60s
|
||||||
|
#track_commit_timestamp = off
|
||||||
|
|
||||||
|
# - Primary Server -
|
||||||
|
|
||||||
|
#synchronous_standby_names = ''
|
||||||
|
#synchronized_standby_slots = ''
|
||||||
|
|
||||||
|
# - Standby Servers -
|
||||||
|
|
||||||
|
#primary_conninfo = ''
|
||||||
|
#primary_slot_name = ''
|
||||||
|
#hot_standby = on
|
||||||
|
#max_standby_archive_delay = 30s
|
||||||
|
#max_standby_streaming_delay = 30s
|
||||||
|
#wal_receiver_create_temp_slot = off
|
||||||
|
#wal_receiver_status_interval = 10s
|
||||||
|
#hot_standby_feedback = off
|
||||||
|
#wal_receiver_timeout = 60s
|
||||||
|
#wal_retrieve_retry_interval = 5s
|
||||||
|
#recovery_min_apply_delay = 0
|
||||||
|
#sync_replication_slots = off
|
||||||
|
|
||||||
|
# - Subscribers -
|
||||||
|
|
||||||
|
#max_active_replication_origins = 10
|
||||||
|
#max_logical_replication_workers = 4
|
||||||
|
#max_sync_workers_per_subscription = 2
|
||||||
|
#max_parallel_apply_workers_per_subscription = 2
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# QUERY TUNING
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Planner Method Configuration -
|
||||||
|
|
||||||
|
#enable_async_append = on
|
||||||
|
#enable_bitmapscan = on
|
||||||
|
#enable_gathermerge = on
|
||||||
|
#enable_hashagg = on
|
||||||
|
#enable_hashjoin = on
|
||||||
|
#enable_incremental_sort = on
|
||||||
|
#enable_indexscan = on
|
||||||
|
#enable_indexonlyscan = on
|
||||||
|
#enable_material = on
|
||||||
|
#enable_memoize = on
|
||||||
|
#enable_mergejoin = on
|
||||||
|
#enable_nestloop = on
|
||||||
|
#enable_parallel_append = on
|
||||||
|
#enable_parallel_hash = on
|
||||||
|
#enable_partition_pruning = on
|
||||||
|
#enable_partitionwise_join = off
|
||||||
|
#enable_partitionwise_aggregate = off
|
||||||
|
#enable_presorted_aggregate = on
|
||||||
|
#enable_seqscan = on
|
||||||
|
#enable_sort = on
|
||||||
|
#enable_tidscan = on
|
||||||
|
|
||||||
|
# - Planner Cost Constants -
|
||||||
|
|
||||||
|
#seq_page_cost = 1.0
|
||||||
|
|
||||||
|
random_page_cost = 1.1
|
||||||
|
# 기본값: 4.0 (HDD), 1.1 (SSD 자동 감지 시)
|
||||||
|
# 변경값: 1.1
|
||||||
|
# 목적: SSD의 랜덤 액세스 특성을 반영
|
||||||
|
# 성능: 인덱스 스캔 선호도 증가, 쿼리 플래너의 더 나은 결정
|
||||||
|
# 참고: HDD는 4.0, SSD는 1.1-1.5가 적절
|
||||||
|
|
||||||
|
#cpu_tuple_cost = 0.01
|
||||||
|
#cpu_index_tuple_cost = 0.005
|
||||||
|
#cpu_operator_cost = 0.0025
|
||||||
|
#parallel_setup_cost = 1000.0
|
||||||
|
#parallel_tuple_cost = 0.1
|
||||||
|
#min_parallel_table_scan_size = 8MB
|
||||||
|
#min_parallel_index_scan_size = 512kB
|
||||||
|
|
||||||
|
effective_cache_size = 3GB
|
||||||
|
# 기본값: 4GB (시스템에 따라 다름)
|
||||||
|
# 변경값: 3GB (전체 RAM 4GB의 75%)
|
||||||
|
# 목적: OS와 PostgreSQL이 파일 캐싱에 사용 가능한 메모리 추정
|
||||||
|
# 성능: 쿼리 플래너가 인덱스 스캔 비용을 더 정확히 계산
|
||||||
|
# 참고: shared_buffers + OS 파일 캐시 = 약 3GB
|
||||||
|
|
||||||
|
#jit_above_cost = 100000
|
||||||
|
#jit_inline_above_cost = 500000
|
||||||
|
#jit_optimize_above_cost = 500000
|
||||||
|
|
||||||
|
# - Genetic Query Optimizer -
|
||||||
|
|
||||||
|
#geqo = on
|
||||||
|
#geqo_threshold = 12
|
||||||
|
|
||||||
|
# - Other Planner Options -
|
||||||
|
|
||||||
|
default_statistics_target = 100
|
||||||
|
# 기본값: 100
|
||||||
|
# 유지 이유: 통계 정확도와 ANALYZE 시간의 균형
|
||||||
|
# 성능: 쿼리 플래너의 정확한 비용 추정
|
||||||
|
# 참고: 특정 컬럼에 대해 개별적으로 높일 수 있음
|
||||||
|
|
||||||
|
#constraint_exclusion = partition
|
||||||
|
#cursor_tuple_fraction = 0.1
|
||||||
|
#from_collapse_limit = 8
|
||||||
|
#jit = on
|
||||||
|
#join_collapse_limit = 8
|
||||||
|
#plan_cache_mode = auto
|
||||||
|
#recursive_worktable_factor = 10.0
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# REPORTING AND LOGGING
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 로깅 설정은 기본값 유지 (사용자 요청사항)
|
||||||
|
|
||||||
|
#log_destination = 'stderr'
|
||||||
|
#logging_collector = off
|
||||||
|
#log_directory = 'log'
|
||||||
|
#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
|
||||||
|
#log_file_mode = 0600
|
||||||
|
#log_rotation_age = 1d
|
||||||
|
#log_rotation_size = 10MB
|
||||||
|
#log_truncate_on_rotation = off
|
||||||
|
#syslog_facility = 'LOCAL0'
|
||||||
|
#syslog_ident = 'postgres'
|
||||||
|
#syslog_sequence_numbers = on
|
||||||
|
#syslog_split_messages = on
|
||||||
|
#event_source = 'PostgreSQL'
|
||||||
|
#log_min_messages = warning
|
||||||
|
#log_min_error_statement = error
|
||||||
|
#log_min_duration_statement = -1
|
||||||
|
#log_min_duration_sample = -1
|
||||||
|
#log_statement_sample_rate = 1.0
|
||||||
|
#log_transaction_sample_rate = 0.0
|
||||||
|
#log_startup_progress_interval = 10s
|
||||||
|
#debug_print_parse = off
|
||||||
|
#debug_print_rewritten = off
|
||||||
|
#debug_print_plan = off
|
||||||
|
#debug_pretty_print = on
|
||||||
|
#log_autovacuum_min_duration = 10min
|
||||||
|
#log_checkpoints = on
|
||||||
|
#log_connections = ''
|
||||||
|
#log_disconnections = off
|
||||||
|
#log_duration = off
|
||||||
|
#log_error_verbosity = default
|
||||||
|
#log_hostname = off
|
||||||
|
#log_line_prefix = '%m [%p] '
|
||||||
|
#log_lock_waits = off
|
||||||
|
#log_lock_failures = off
|
||||||
|
#log_recovery_conflict_waits = off
|
||||||
|
#log_parameter_max_length = -1
|
||||||
|
#log_parameter_max_length_on_error = 0
|
||||||
|
#log_statement = 'none'
|
||||||
|
#log_replication_commands = off
|
||||||
|
#log_temp_files = -1
|
||||||
|
log_timezone = 'Etc/UTC'
|
||||||
|
#cluster_name = ''
|
||||||
|
#update_process_title = on
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# STATISTICS
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#track_activities = on
|
||||||
|
#track_activity_query_size = 1024
|
||||||
|
#track_counts = on
|
||||||
|
#track_cost_delay_timing = off
|
||||||
|
|
||||||
|
track_io_timing = on
|
||||||
|
# 기본값: off
|
||||||
|
# 변경값: on
|
||||||
|
# 목적: I/O 작업의 시간 추적으로 성능 병목 지점 파악
|
||||||
|
# 성능: EXPLAIN ANALYZE 등으로 I/O 병목 진단 가능
|
||||||
|
# 참고: 약간의 오버헤드 있지만 성능 튜닝에 매우 유용
|
||||||
|
|
||||||
|
#track_wal_io_timing = off
|
||||||
|
#track_functions = none
|
||||||
|
#stats_fetch_consistency = cache
|
||||||
|
|
||||||
|
# - Monitoring -
|
||||||
|
|
||||||
|
#compute_query_id = auto
|
||||||
|
#log_statement_stats = off
|
||||||
|
#log_parser_stats = off
|
||||||
|
#log_planner_stats = off
|
||||||
|
#log_executor_stats = off
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# VACUUMING
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Automatic Vacuuming -
|
||||||
|
|
||||||
|
#autovacuum = on
|
||||||
|
|
||||||
|
autovacuum_worker_slots = 8
|
||||||
|
# 기본값: 16 (PostgreSQL 18 신규 파라미터)
|
||||||
|
# 변경값: 8
|
||||||
|
# 목적: autovacuum worker 슬롯 수 (동시 실행 가능한 worker 총량)
|
||||||
|
# 성능: 4코어 환경에서 적절한 슬롯 수로 CPU 리소스 균형
|
||||||
|
# 참고: max_workers와 별개로 동적으로 worker 생성 가능
|
||||||
|
|
||||||
|
autovacuum_max_workers = 3
|
||||||
|
# 기본값: 3
|
||||||
|
# 변경값: 3
|
||||||
|
# 목적: 동시에 실행 가능한 autovacuum worker 프로세스 수
|
||||||
|
# 성능: 여러 테이블을 동시에 vacuum 처리
|
||||||
|
# 참고: 4코어 환경에서 적절한 수준
|
||||||
|
|
||||||
|
autovacuum_naptime = 30s
|
||||||
|
# 기본값: 1min
|
||||||
|
# 변경값: 30s
|
||||||
|
# 목적: autovacuum이 데이터베이스를 체크하는 주기
|
||||||
|
# 성능: 더 빈번한 체크로 테이블 bloat 감소, 성능 유지
|
||||||
|
# 참고: 쓰기가 많은 환경에서 효과적
|
||||||
|
|
||||||
|
#autovacuum_vacuum_threshold = 50
|
||||||
|
#autovacuum_vacuum_insert_threshold = 1000
|
||||||
|
#autovacuum_analyze_threshold = 50
|
||||||
|
|
||||||
|
autovacuum_vacuum_scale_factor = 0.1
|
||||||
|
# 기본값: 0.2 (테이블의 20%)
|
||||||
|
# 변경값: 0.1 (테이블의 10%)
|
||||||
|
# 목적: vacuum 실행 trigger 조건 (dead tuple 비율)
|
||||||
|
# 성능: 더 자주 vacuum 실행으로 테이블 bloat 최소화
|
||||||
|
# 참고: 대형 테이블에서 특히 효과적
|
||||||
|
|
||||||
|
#autovacuum_vacuum_insert_scale_factor = 0.2
|
||||||
|
|
||||||
|
autovacuum_analyze_scale_factor = 0.05
|
||||||
|
# 기본값: 0.1 (테이블의 10%)
|
||||||
|
# 변경값: 0.05 (테이블의 5%)
|
||||||
|
# 목적: analyze 실행 trigger 조건
|
||||||
|
# 성능: 더 빈번한 통계 업데이트로 쿼리 플래너의 정확도 향상
|
||||||
|
|
||||||
|
#autovacuum_vacuum_max_threshold = 100000000
|
||||||
|
#autovacuum_freeze_max_age = 200000000
|
||||||
|
#autovacuum_multixact_freeze_max_age = 400000000
|
||||||
|
#autovacuum_vacuum_cost_delay = 2ms
|
||||||
|
#autovacuum_vacuum_cost_limit = -1
|
||||||
|
|
||||||
|
# - Cost-Based Vacuum Delay -
|
||||||
|
|
||||||
|
#vacuum_cost_delay = 0
|
||||||
|
#vacuum_cost_page_hit = 1
|
||||||
|
#vacuum_cost_page_miss = 2
|
||||||
|
#vacuum_cost_page_dirty = 20
|
||||||
|
#vacuum_cost_limit = 200
|
||||||
|
|
||||||
|
# - Default Behavior -
|
||||||
|
|
||||||
|
#vacuum_truncate = on
|
||||||
|
|
||||||
|
# - Freezing -
|
||||||
|
|
||||||
|
#vacuum_freeze_table_age = 150000000
|
||||||
|
#vacuum_freeze_min_age = 50000000
|
||||||
|
#vacuum_failsafe_age = 1600000000
|
||||||
|
#vacuum_multixact_freeze_table_age = 150000000
|
||||||
|
#vacuum_multixact_freeze_min_age = 5000000
|
||||||
|
#vacuum_multixact_failsafe_age = 1600000000
|
||||||
|
#vacuum_max_eager_freeze_failure_rate = 0.03
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# CLIENT CONNECTION DEFAULTS
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Statement Behavior -
|
||||||
|
|
||||||
|
#client_min_messages = notice
|
||||||
|
#search_path = '"$user", public'
|
||||||
|
#row_security = on
|
||||||
|
#default_table_access_method = 'heap'
|
||||||
|
#default_tablespace = ''
|
||||||
|
#default_toast_compression = 'pglz'
|
||||||
|
#temp_tablespaces = ''
|
||||||
|
#check_function_bodies = on
|
||||||
|
#default_transaction_isolation = 'read committed'
|
||||||
|
#default_transaction_read_only = off
|
||||||
|
#default_transaction_deferrable = off
|
||||||
|
#session_replication_role = 'origin'
|
||||||
|
|
||||||
|
statement_timeout = 30000
|
||||||
|
# 기본값: 0 (무제한)
|
||||||
|
# 변경값: 30000ms (30초)
|
||||||
|
# 목적: 장시간 실행되는 쿼리 자동 종료
|
||||||
|
# 성능: 문제있는 쿼리로 인한 리소스 점유 방지
|
||||||
|
# 참고: 애플리케이션 특성에 따라 조정 필요, 0으로 비활성화 가능
|
||||||
|
|
||||||
|
#transaction_timeout = 0
|
||||||
|
|
||||||
|
lock_timeout = 5000
|
||||||
|
# 기본값: 0 (무제한)
|
||||||
|
# 변경값: 5000ms (5초)
|
||||||
|
# 목적: 락 대기 시간 제한
|
||||||
|
# 성능: 데드락 상황 빠른 감지, 애플리케이션 응답성 향상
|
||||||
|
|
||||||
|
#idle_in_transaction_session_timeout = 0
|
||||||
|
|
||||||
|
idle_session_timeout = 300000
|
||||||
|
# 기본값: 0 (무제한)
|
||||||
|
# 변경값: 300000ms (5분)
|
||||||
|
# 목적: 유휴 세션 자동 종료
|
||||||
|
# 성능: 불필요한 연결로 인한 리소스 낭비 방지
|
||||||
|
# 참고: 연결 풀 사용 시 조정 필요
|
||||||
|
|
||||||
|
#bytea_output = 'hex'
|
||||||
|
#xmlbinary = 'base64'
|
||||||
|
#xmloption = 'content'
|
||||||
|
#gin_pending_list_limit = 4MB
|
||||||
|
#createrole_self_grant = ''
|
||||||
|
#event_triggers = on
|
||||||
|
|
||||||
|
# - Locale and Formatting -
|
||||||
|
|
||||||
|
datestyle = 'iso, mdy'
|
||||||
|
#intervalstyle = 'postgres'
|
||||||
|
timezone = 'Etc/UTC'
|
||||||
|
#timezone_abbreviations = 'Default'
|
||||||
|
#extra_float_digits = 1
|
||||||
|
#client_encoding = sql_ascii
|
||||||
|
|
||||||
|
lc_messages = 'en_US.utf8'
|
||||||
|
lc_monetary = 'en_US.utf8'
|
||||||
|
lc_numeric = 'en_US.utf8'
|
||||||
|
lc_time = 'en_US.utf8'
|
||||||
|
#icu_validation_level = warning
|
||||||
|
|
||||||
|
default_text_search_config = 'pg_catalog.english'
|
||||||
|
|
||||||
|
# - Shared Library Preloading -
|
||||||
|
|
||||||
|
#local_preload_libraries = ''
|
||||||
|
#session_preload_libraries = ''
|
||||||
|
#shared_preload_libraries = ''
|
||||||
|
#jit_provider = 'llvmjit'
|
||||||
|
|
||||||
|
# - Other Defaults -
|
||||||
|
|
||||||
|
#dynamic_library_path = '$libdir'
|
||||||
|
#extension_control_path = '$system'
|
||||||
|
#gin_fuzzy_search_limit = 0
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# LOCK MANAGEMENT
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
deadlock_timeout = 1s
|
||||||
|
# 기본값: 1s
|
||||||
|
# 유지 이유: 데드락 감지를 위한 적절한 대기 시간
|
||||||
|
|
||||||
|
#max_locks_per_transaction = 64
|
||||||
|
#max_pred_locks_per_transaction = 64
|
||||||
|
#max_pred_locks_per_relation = -2
|
||||||
|
#max_pred_locks_per_page = 2
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# VERSION AND PLATFORM COMPATIBILITY
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#array_nulls = on
|
||||||
|
#backslash_quote = safe_encoding
|
||||||
|
#escape_string_warning = on
|
||||||
|
#lo_compat_privileges = off
|
||||||
|
#quote_all_identifiers = off
|
||||||
|
#standard_conforming_strings = on
|
||||||
|
#synchronize_seqscans = on
|
||||||
|
#transform_null_equals = off
|
||||||
|
#allow_alter_system = on
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# ERROR HANDLING
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#exit_on_error = off
|
||||||
|
#restart_after_crash = on
|
||||||
|
#data_sync_retry = off
|
||||||
|
#recovery_init_sync_method = fsync
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# CONFIG FILE INCLUDES
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include_dir = '...'
|
||||||
|
#include_if_exists = '...'
|
||||||
|
#include = '...'
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# CUSTOMIZED OPTIONS
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 주요 변경사항 요약
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# 1. 메모리 설정 (4GB RAM 기준)
|
||||||
|
# - shared_buffers: 128MB → 1GB (25% of RAM)
|
||||||
|
# - effective_cache_size: 4GB → 3GB (75% of RAM)
|
||||||
|
# - work_mem: 4MB → 16MB (쿼리 성능 향상)
|
||||||
|
# - maintenance_work_mem: 64MB → 256MB (유지보수 작업 가속)
|
||||||
|
#
|
||||||
|
# 2. 연결 관리
|
||||||
|
# - tcp_keepalives 설정: 죽은 연결 빠른 감지 (90초 이내)
|
||||||
|
# - statement_timeout: 30초 (장시간 쿼리 방지)
|
||||||
|
# - lock_timeout: 5초 (락 대기 제한)
|
||||||
|
# - idle_session_timeout: 5분 (유휴 세션 정리)
|
||||||
|
#
|
||||||
|
# 3. 병렬 처리 (4코어 최적화)
|
||||||
|
# - max_parallel_workers: 4 (CPU 코어 수)
|
||||||
|
# - max_parallel_workers_per_gather: 2
|
||||||
|
# - max_worker_processes: 8
|
||||||
|
#
|
||||||
|
# 4. I/O 최적화 (SSD 특화)
|
||||||
|
# - random_page_cost: 4.0 → 1.1
|
||||||
|
# - effective_io_concurrency: 1 → 200
|
||||||
|
# - maintenance_io_concurrency: 10 → 200
|
||||||
|
#
|
||||||
|
# 5. WAL 및 체크포인트
|
||||||
|
# - wal_compression: off → lz4 (I/O 감소)
|
||||||
|
# - wal_buffers: 자동 → 16MB
|
||||||
|
# - checkpoint_timeout: 5min → 15min
|
||||||
|
# - max_wal_size: 1GB → 2GB
|
||||||
|
# - min_wal_size: 80MB → 1GB
|
||||||
|
#
|
||||||
|
# 6. Autovacuum 튜닝
|
||||||
|
# - autovacuum_worker_slots: 16 → 8
|
||||||
|
# - autovacuum_naptime: 1min → 30s (더 빈번한 체크)
|
||||||
|
# - autovacuum_vacuum_scale_factor: 0.2 → 0.1 (더 자주 실행)
|
||||||
|
# - autovacuum_analyze_scale_factor: 0.1 → 0.05
|
||||||
|
#
|
||||||
|
# 7. 모니터링
|
||||||
|
# - track_io_timing: off → on (I/O 성능 진단)
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
# 예상 성능 향상
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# - 읽기 성능: 30-50% 향상 (shared_buffers, effective_cache_size)
|
||||||
|
# - 쓰기 성능: 20-40% 향상 (WAL 설정, checkpoint 최적화)
|
||||||
|
# - 복잡한 쿼리: 40-100% 향상 (work_mem, 병렬 처리)
|
||||||
|
# - 유지보수 작업: 100-300% 향상 (maintenance_work_mem, I/O 동시성)
|
||||||
|
# - 전체 처리량: 25-50% 향상 (모든 최적화의 시너지)
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
# 적용 방법
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# 1. 이 파일을 postgresql.conf로 저장 (또는 기존 파일 백업 후 교체)
|
||||||
|
# 2. PostgreSQL 재시작:
|
||||||
|
# sudo systemctl restart postgresql
|
||||||
|
# 또는
|
||||||
|
# sudo pg_ctl restart -D /var/lib/postgresql/data
|
||||||
|
#
|
||||||
|
# 3. 설정 확인:
|
||||||
|
# SHOW shared_buffers;
|
||||||
|
# SHOW effective_cache_size;
|
||||||
|
# SHOW work_mem;
|
||||||
|
#
|
||||||
|
# 4. 모니터링 (첫 며칠간):
|
||||||
|
# - 메모리 사용량: free -h, htop
|
||||||
|
# - 체크포인트 빈도: 로그 확인
|
||||||
|
# - 쿼리 성능: pg_stat_statements 활용
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 devspoons
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name demo.castad.net;
|
||||||
|
|
||||||
|
if ($bad_bot) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
access_log /log/nginx/demo.castad.net.gunicorn_access.log main;
|
||||||
|
error_log /log/nginx/demo.castad.net.gunicorn_error.log warn;
|
||||||
|
|
||||||
|
# if ($host !~* ^(domain\.com|www\.domain\.com)$) {
|
||||||
|
# return 444;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# 프론트엔드 정적 파일 루트
|
||||||
|
root /www/o2o-castad-frontend/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Django media
|
||||||
|
location /media {
|
||||||
|
autoindex off;
|
||||||
|
gzip_static on;
|
||||||
|
expires max;
|
||||||
|
#alias /www/django_sample/media;
|
||||||
|
alias /www/o2o-castad-backend/media; # your Django project's media files - amend as required
|
||||||
|
#include /etc/nginx/mime.types;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static {
|
||||||
|
autoindex off;
|
||||||
|
gzip_static on;
|
||||||
|
expires max;
|
||||||
|
#alias /www/django_sample/static;
|
||||||
|
# normally static folder is named as /static
|
||||||
|
alias /www/o2o-castad-backend/static; # your Django project's static files - amend as required
|
||||||
|
#include /etc/nginx/mime.types;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
autoindex off;
|
||||||
|
|
||||||
|
# upstream 연결 풀 사용 (nginx.conf에서 정의)
|
||||||
|
proxy_pass http://uvicorn-app:8000/;
|
||||||
|
|
||||||
|
# HTTP/1.1 사용 (keepalive 연결 필수)
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
# WebSocket 지원 및 HTTP keepalive 동시 지원
|
||||||
|
# - WebSocket: Upgrade 헤더 전달, Connection: upgrade
|
||||||
|
# - 일반 HTTP: Connection: "" (keepalive 유지)
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
# 프록시 헤더 설정
|
||||||
|
proxy_set_header Host $http_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;
|
||||||
|
|
||||||
|
# 프록시 캐시 우회 (WebSocket 및 동적 콘텐츠)
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
|
||||||
|
# 타임아웃 설정 (파일 업로드, AI 생성 등 오래 걸리는 작업용)
|
||||||
|
proxy_connect_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
|
||||||
|
# 파일 업로드 설정
|
||||||
|
client_max_body_size 100M;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Allow Lets Encrypt Domain Validation Program
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/o2o-castad-backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block dot file (.htaccess .htpasswd .svn .git .env and so on.)
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block (log file, binary, certificate, shell script, sql dump file) access.
|
||||||
|
location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block access
|
||||||
|
location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /robots.txt {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,563 @@
|
||||||
|
map $http_user_agent $bad_bot {
|
||||||
|
default 0;
|
||||||
|
~*360Spider 1;
|
||||||
|
~*360Spider 1;
|
||||||
|
~*80legs 1;
|
||||||
|
~*Abonti 1;
|
||||||
|
~*Aboundex 1;
|
||||||
|
~*AcoonBot 1;
|
||||||
|
~*Acunetix 1;
|
||||||
|
~*adbeat_bot 1;
|
||||||
|
~*AddThis.com 1;
|
||||||
|
~*adidxbot 1;
|
||||||
|
~*ADmantX 1;
|
||||||
|
~*AhrefsBot 1;
|
||||||
|
~*AIBOT 1;
|
||||||
|
~*aiHitBot 1;
|
||||||
|
~*Alexibot 1;
|
||||||
|
~*Alligator 1;
|
||||||
|
~*AllSubmitter 1;
|
||||||
|
~*AngloINFO 1;
|
||||||
|
~*Antelope 1;
|
||||||
|
~*Apexoo 1;
|
||||||
|
~*asterias 1;
|
||||||
|
~*attach 1;
|
||||||
|
~*BackDoorBot 1;
|
||||||
|
~*BackStreet 1;
|
||||||
|
~*BackWeb 1;
|
||||||
|
~*Badass 1;
|
||||||
|
~*Baid 1;
|
||||||
|
~*Bandit 1;
|
||||||
|
~*BatchFTP 1;
|
||||||
|
~*BBBike 1;
|
||||||
|
~*BeetleBot 1;
|
||||||
|
~*Bigfoot 1;
|
||||||
|
~*billigerbot 1;
|
||||||
|
~*binlar 1;
|
||||||
|
~*bitlybot 1;
|
||||||
|
~*Black.Hole 1;
|
||||||
|
~*BlackWidow 1;
|
||||||
|
~*BLEXBot 1;
|
||||||
|
~*Blow 1;
|
||||||
|
~*BlowFish 1;
|
||||||
|
~*BLP_bbot 1;
|
||||||
|
~*BoardReader 1;
|
||||||
|
~*Bolt\ 0 1;
|
||||||
|
~*BOT\ for\ JCE 1;
|
||||||
|
~*Bot\ mailto\:craftbot@yahoo\.com 1;
|
||||||
|
~*BotALot 1;
|
||||||
|
~*Buddy 1;
|
||||||
|
~*BuiltBotTough 1;
|
||||||
|
~*Bullseye 1;
|
||||||
|
~*BunnySlippers 1;
|
||||||
|
~*casper 1;
|
||||||
|
~*CazoodleBot 1;
|
||||||
|
~*CCBot 1;
|
||||||
|
~*Cegbfeieh 1;
|
||||||
|
~*checkprivacy 1;
|
||||||
|
~*CheeseBot 1;
|
||||||
|
~*CherryPicker 1;
|
||||||
|
~*ChinaClaw 1;
|
||||||
|
~*chromeframe 1;
|
||||||
|
~*Clerkbot 1;
|
||||||
|
~*Cliqzbot 1;
|
||||||
|
~*clshttp 1;
|
||||||
|
~*Cogentbot 1;
|
||||||
|
~*cognitiveseo 1;
|
||||||
|
~*Collector 1;
|
||||||
|
~*CommonCrawler 1;
|
||||||
|
~*comodo 1;
|
||||||
|
~*Copier 1;
|
||||||
|
~*CopyRightCheck 1;
|
||||||
|
~*cosmos 1;
|
||||||
|
~*CPython 1;
|
||||||
|
~*crawler4j 1;
|
||||||
|
~*Crawlera 1;
|
||||||
|
~*CRAZYWEBCRAWLER 1;
|
||||||
|
~*Crescent 1;
|
||||||
|
~*CSHttp 1;
|
||||||
|
~*Curious 1;
|
||||||
|
# ~*Curl 1; # 개발/테스트용으로 허용
|
||||||
|
~*Custo 1;
|
||||||
|
~*CWS_proxy 1;
|
||||||
|
~*Default\ Browser\ 0 1;
|
||||||
|
~*Demon 1;
|
||||||
|
~*DeuSu 1;
|
||||||
|
~*Devil 1;
|
||||||
|
~*diavol 1;
|
||||||
|
~*DigExt 1;
|
||||||
|
~*Digincore 1;
|
||||||
|
~*DIIbot 1;
|
||||||
|
~*DISCo 1;
|
||||||
|
~*discobot 1;
|
||||||
|
~*DittoSpyder 1;
|
||||||
|
~*DoCoMo 1;
|
||||||
|
~*DotBot 1;
|
||||||
|
~*Download.Demon 1;
|
||||||
|
~*Download.Devil 1;
|
||||||
|
~*Download.Wonder 1;
|
||||||
|
~*Download\ Demo 1;
|
||||||
|
~*dragonfly 1;
|
||||||
|
~*Drip 1;
|
||||||
|
~*DTS.Agent 1;
|
||||||
|
~*EasouSpider 1;
|
||||||
|
~*EasyDL 1;
|
||||||
|
~*ebingbong 1;
|
||||||
|
~*eCatch 1;
|
||||||
|
~*ecxi 1;
|
||||||
|
~*EirGrabber 1;
|
||||||
|
~*Elmer 1;
|
||||||
|
~*EmailCollector 1;
|
||||||
|
~*EmailSiphon 1;
|
||||||
|
~*EmailWolf 1;
|
||||||
|
~*EroCrawler 1;
|
||||||
|
~*Exabot 1;
|
||||||
|
~*ExaleadCloudView 1;
|
||||||
|
~*ExpertSearch 1;
|
||||||
|
~*ExpertSearchSpider 1;
|
||||||
|
~*Express 1;
|
||||||
|
~*Express\ WebPictures 1;
|
||||||
|
~*extract 1;
|
||||||
|
~*Extractor 1;
|
||||||
|
~*ExtractorPro 1;
|
||||||
|
~*EyeNetIE 1;
|
||||||
|
~*Ezooms 1;
|
||||||
|
~*F2S 1;
|
||||||
|
~*FastSeek 1;
|
||||||
|
~*feedfinder 1;
|
||||||
|
~*FeedlyBot 1;
|
||||||
|
~*FHscan 1;
|
||||||
|
~*finbot 1;
|
||||||
|
~*Flamingo_SearchEngine 1;
|
||||||
|
~*FlappyBot 1;
|
||||||
|
~*FlashGet 1;
|
||||||
|
~*flicky 1;
|
||||||
|
~*Flipboard 1;
|
||||||
|
~*FlipboardProxy 1;
|
||||||
|
~*flunky 1;
|
||||||
|
~*Foobot 1;
|
||||||
|
~*FrontPage 1;
|
||||||
|
~*g00g1e 1;
|
||||||
|
~*GalaxyBot 1;
|
||||||
|
~*genieo 1;
|
||||||
|
~*Genieo 1;
|
||||||
|
~*GetRight 1;
|
||||||
|
~*GetWeb\! 1;
|
||||||
|
~*GigablastOpenSource 1;
|
||||||
|
~*Go\-Ahead\-Got\-It 1;
|
||||||
|
~*Go\!Zilla 1;
|
||||||
|
~*gotit 1;
|
||||||
|
~*GozaikBot 1;
|
||||||
|
~*grab 1;
|
||||||
|
~*Grabber 1;
|
||||||
|
~*GrabNet 1;
|
||||||
|
~*Grafula 1;
|
||||||
|
~*GrapeshotCrawler 1;
|
||||||
|
~*GT\:\:WWW 1;
|
||||||
|
~*GTB5 1;
|
||||||
|
~*Guzzle 1;
|
||||||
|
~*harvest 1;
|
||||||
|
~*Harvest 1;
|
||||||
|
~*HEADMasterSEO 1;
|
||||||
|
~*heritrix 1;
|
||||||
|
~*hloader 1;
|
||||||
|
~*HMView 1;
|
||||||
|
~*HomePageBot 1;
|
||||||
|
~*htmlparser 1;
|
||||||
|
~*HTTP\:\:Lite 1;
|
||||||
|
~*httrack 1;
|
||||||
|
~*HTTrack 1;
|
||||||
|
~*HubSpot 1;
|
||||||
|
~*humanlinks 1;
|
||||||
|
~*ia_archiver 1;
|
||||||
|
~*icarus6 1;
|
||||||
|
~*id\-search 1;
|
||||||
|
~*IDBot 1;
|
||||||
|
~*IlseBot 1;
|
||||||
|
~*Image.Stripper 1;
|
||||||
|
~*Image.Sucker 1;
|
||||||
|
~*Image\ Stripper 1;
|
||||||
|
~*Image\ Sucker 1;
|
||||||
|
~*imagefetch 1;
|
||||||
|
~*Indigonet 1;
|
||||||
|
~*Indy\ Library 1;
|
||||||
|
~*InfoNaviRobot 1;
|
||||||
|
~*InfoTekies 1;
|
||||||
|
~*integromedb 1;
|
||||||
|
~*Intelliseek 1;
|
||||||
|
~*InterGET 1;
|
||||||
|
~*Internet\ Ninja 1;
|
||||||
|
~*InternetSeer\.com 1;
|
||||||
|
~*Iria 1;
|
||||||
|
~*IRLbot 1;
|
||||||
|
~*ISC\ Systems\ iRc\ Search\ 2\.1 1;
|
||||||
|
~*jakarta 1;
|
||||||
|
~*Jakarta 1;
|
||||||
|
~*Java 1;
|
||||||
|
~*JennyBot 1;
|
||||||
|
~*JetCar 1;
|
||||||
|
~*JikeSpider 1;
|
||||||
|
~*JobdiggerSpider 1;
|
||||||
|
~*JOC 1;
|
||||||
|
~*JOC\ Web\ Spider 1;
|
||||||
|
~*Jooblebot 1;
|
||||||
|
~*JustView 1;
|
||||||
|
~*Jyxobot 1;
|
||||||
|
~*kanagawa 1;
|
||||||
|
~*Kenjin.Spider 1;
|
||||||
|
~*Keyword.Density 1;
|
||||||
|
~*KINGSpider 1;
|
||||||
|
~*kmccrew 1;
|
||||||
|
~*larbin 1;
|
||||||
|
~*LeechFTP 1;
|
||||||
|
~*LeechGet 1;
|
||||||
|
~*LexiBot 1;
|
||||||
|
~*lftp 1;
|
||||||
|
~*libWeb 1;
|
||||||
|
~*libwww 1;
|
||||||
|
~*libwww-perl 1;
|
||||||
|
~*likse 1;
|
||||||
|
~*Lingewoud 1;
|
||||||
|
~*LinkChecker 1;
|
||||||
|
~*linkdexbot 1;
|
||||||
|
~*LinkextractorPro 1;
|
||||||
|
~*LinkScan 1;
|
||||||
|
~*LinksCrawler 1;
|
||||||
|
~*LinksManager\.com_bot 1;
|
||||||
|
~*linkwalker 1;
|
||||||
|
~*LinkWalker 1;
|
||||||
|
~*LinqiaRSSBot 1;
|
||||||
|
~*LivelapBot 1;
|
||||||
|
~*LNSpiderguy 1;
|
||||||
|
~*ltx71 1;
|
||||||
|
~*LubbersBot 1;
|
||||||
|
~*lwp\-trivial 1;
|
||||||
|
~*Mag-Net 1;
|
||||||
|
~*Magnet 1;
|
||||||
|
~*Mail.RU_Bot 1;
|
||||||
|
~*majestic12 1;
|
||||||
|
~*MarkWatch 1;
|
||||||
|
~*Mass.Downloader 1;
|
||||||
|
~*Mass\ Downloader 1;
|
||||||
|
~*masscan 1;
|
||||||
|
~*Mata.Hari 1;
|
||||||
|
~*maverick 1;
|
||||||
|
~*Maxthon$ 1;
|
||||||
|
~*Mediatoolkitbot 1;
|
||||||
|
~*megaindex 1;
|
||||||
|
~*MegaIndex 1;
|
||||||
|
~*Memo 1;
|
||||||
|
~*MetaURI 1;
|
||||||
|
~*MFC_Tear_Sample 1;
|
||||||
|
~*Microsoft\ URL\ Control 1;
|
||||||
|
~*microsoft\.url 1;
|
||||||
|
~*MIDown\ tool 1;
|
||||||
|
~*MIIxpc 1;
|
||||||
|
~*miner 1;
|
||||||
|
~*Missigua\ Locator 1;
|
||||||
|
~*Mister\ PiX 1;
|
||||||
|
~*MJ12bot 1;
|
||||||
|
~*Mozilla.*Indy 1;
|
||||||
|
~*Mozilla.*NEWT 1;
|
||||||
|
~*MSFrontPage 1;
|
||||||
|
~*MSIECrawler 1;
|
||||||
|
~*msnbot 1;
|
||||||
|
~*NAMEPROTECT 1;
|
||||||
|
~*Navroad 1;
|
||||||
|
~*NearSite 1;
|
||||||
|
~*Net\ Vampire 1;
|
||||||
|
~*NetAnts 1;
|
||||||
|
~*Netcraft 1;
|
||||||
|
~*netEstate 1;
|
||||||
|
~*NetMechanic 1;
|
||||||
|
~*NetSpider 1;
|
||||||
|
~*NetZIP 1;
|
||||||
|
~*NextGenSearchBot 1;
|
||||||
|
~*NICErsPRO 1;
|
||||||
|
~*niki\-bot 1;
|
||||||
|
~*NimbleCrawler 1;
|
||||||
|
~*Nimbostratus\-Bot 1;
|
||||||
|
~*Ninja 1;
|
||||||
|
~*nmap 1;
|
||||||
|
~*Nmap 1;
|
||||||
|
~*NPbot 1;
|
||||||
|
~*nutch 1;
|
||||||
|
~*Octopus 1;
|
||||||
|
~*Offline\.Explorer 1;
|
||||||
|
~*Offline\.Navigator 1;
|
||||||
|
~*Offline\ Explorer 1;
|
||||||
|
~*Offline\ Navigator 1;
|
||||||
|
~*Openfind 1;
|
||||||
|
~*OpenindexSpider 1;
|
||||||
|
~*OpenLinkProfiler 1;
|
||||||
|
~*OpenWebSpider 1;
|
||||||
|
~*OrangeBot 1;
|
||||||
|
~*OutfoxBot 1;
|
||||||
|
~*Owlin 1;
|
||||||
|
~*PageGrabber 1;
|
||||||
|
~*PagesInventory 1;
|
||||||
|
~*panopta 1;
|
||||||
|
~*panscient\.com 1;
|
||||||
|
~*Papa\ Foto 1;
|
||||||
|
~*pavuk 1;
|
||||||
|
~*pcBrowser 1;
|
||||||
|
~*PECL\:\:HTTP 1;
|
||||||
|
~*PeoplePal 1;
|
||||||
|
~*Photon 1;
|
||||||
|
~*PHPCrawl 1;
|
||||||
|
~*Pixray 1;
|
||||||
|
~*planetwork 1;
|
||||||
|
~*PleaseCrawl 1;
|
||||||
|
~*PNAMAIN\.EXE 1;
|
||||||
|
~*Pockey 1;
|
||||||
|
~*PodcastPartyBot 1;
|
||||||
|
~*prijsbest 1;
|
||||||
|
~*probethenet 1;
|
||||||
|
~*ProPowerBot 1;
|
||||||
|
~*ProWebWalker 1;
|
||||||
|
~*proximic 1;
|
||||||
|
~*psbot 1;
|
||||||
|
~*Pump 1;
|
||||||
|
~*purebot 1;
|
||||||
|
~*pycurl 1;
|
||||||
|
~*python\-requests 1;
|
||||||
|
~*QueryN\.Metasearch 1;
|
||||||
|
~*QuerySeekerSpider 1;
|
||||||
|
~*R6_CommentReader 1;
|
||||||
|
~*R6_FeedFetcher 1;
|
||||||
|
~*RealDownload 1;
|
||||||
|
~*Reaper 1;
|
||||||
|
~*Recorder 1;
|
||||||
|
~*ReGet 1;
|
||||||
|
~*RepoMonkey 1;
|
||||||
|
~*Riddler 1;
|
||||||
|
~*Ripper 1;
|
||||||
|
~*Rippers\ 0 1;
|
||||||
|
~*RMA 1;
|
||||||
|
~*rogerbot 1;
|
||||||
|
~*RSSingBot 1;
|
||||||
|
~*rv\:1\.9\.1 1;
|
||||||
|
~*RyzeCrawler 1;
|
||||||
|
~*SafeSearch 1;
|
||||||
|
~*SBIder 1;
|
||||||
|
~*scanbot 1;
|
||||||
|
~*Scrapy 1;
|
||||||
|
~*Screaming 1;
|
||||||
|
~*SeaMonkey$ 1;
|
||||||
|
~*search_robot 1;
|
||||||
|
~*SearchmetricsBot 1;
|
||||||
|
~*Semrush 1;
|
||||||
|
~*SemrushBot 1;
|
||||||
|
~*semrush\.com 1;
|
||||||
|
~*SemrushBot-BA 1;
|
||||||
|
~*SentiBot 1;
|
||||||
|
~*SEOkicks 1;
|
||||||
|
~*SEOkicks\-Robot 1;
|
||||||
|
~*seoscanners 1;
|
||||||
|
~*SeznamBot 1;
|
||||||
|
~*ShowyouBot 1;
|
||||||
|
~*SightupBot 1;
|
||||||
|
~*Siphon 1;
|
||||||
|
~*SISTRIX 1;
|
||||||
|
~*sitecheck\.internetseer\.com 1;
|
||||||
|
~*siteexplorer\.info 1;
|
||||||
|
~*Siteimprove 1;
|
||||||
|
~*SiteSnagger 1;
|
||||||
|
~*SiteSucker 1;
|
||||||
|
~*skygrid 1;
|
||||||
|
~*Slackbot 1;
|
||||||
|
~*Slurp 1;
|
||||||
|
~*SlySearch 1;
|
||||||
|
~*SmartDownload 1;
|
||||||
|
~*Snake 1;
|
||||||
|
~*Snapbot 1;
|
||||||
|
~*Snoopy 1;
|
||||||
|
~*sogou 1;
|
||||||
|
~*Sogou 1;
|
||||||
|
~*Sosospider 1;
|
||||||
|
~*SpaceBison 1;
|
||||||
|
~*SpankBot 1;
|
||||||
|
~*spanner 1;
|
||||||
|
~*spaumbot 1;
|
||||||
|
~*spbot 1;
|
||||||
|
~*Spinn4r 1;
|
||||||
|
~*Sqworm 1;
|
||||||
|
~*Steeler 1;
|
||||||
|
~*Stripper 1;
|
||||||
|
~*sucker 1;
|
||||||
|
~*Sucker 1;
|
||||||
|
~*SuperBot 1;
|
||||||
|
~*Superfeedr 1;
|
||||||
|
~*SuperHTTP 1;
|
||||||
|
~*SurdotlyBot 1;
|
||||||
|
~*Surfbot 1;
|
||||||
|
~*suzuran 1;
|
||||||
|
~*Szukacz 1;
|
||||||
|
~*tAkeOut 1;
|
||||||
|
~*Teleport 1;
|
||||||
|
~*Teleport\ Pro 1;
|
||||||
|
~*Telesoft 1;
|
||||||
|
~*The\.Intraformant 1;
|
||||||
|
~*TheNomad 1;
|
||||||
|
~*TightTwatBot 1;
|
||||||
|
~*TinEye 1;
|
||||||
|
~*TinEye\-bot 1;
|
||||||
|
~*Titan 1;
|
||||||
|
~*Toata\ dragostea\ mea\ pentru\ diavola 1;
|
||||||
|
~*Toplistbot 1;
|
||||||
|
~*trendictionbot 1;
|
||||||
|
~*trovitBot 1;
|
||||||
|
~*True_Robot 1;
|
||||||
|
~*turingos 1;
|
||||||
|
~*turnit 1;
|
||||||
|
~*TurnitinBot 1;
|
||||||
|
~*Twitterbot 1;
|
||||||
|
~*URI\:\:Fetch 1;
|
||||||
|
~*urllib 1;
|
||||||
|
~*URLy\.Warning 1;
|
||||||
|
~*Vacuum 1;
|
||||||
|
~*Vagabondo 1;
|
||||||
|
~*VCI 1;
|
||||||
|
~*VidibleScraper 1;
|
||||||
|
~*vikspider 1;
|
||||||
|
~*VoidEYE 1;
|
||||||
|
~*VoilaBot 1;
|
||||||
|
~*WallpapersHD 1;
|
||||||
|
~*WBSearchBot 1;
|
||||||
|
~*Web.Image.Collector 1;
|
||||||
|
~*Web\ Image\ Collector 1;
|
||||||
|
~*Web\ Sucker 1;
|
||||||
|
~*webalta 1;
|
||||||
|
~*WebAuto 1;
|
||||||
|
~*WebBandit 1;
|
||||||
|
~*WebCollage 1;
|
||||||
|
~*WebCopier 1;
|
||||||
|
~*WebEnhancer 1;
|
||||||
|
~*WebFetch 1;
|
||||||
|
~*WebFuck 1;
|
||||||
|
~*WebGo\ IS 1;
|
||||||
|
~*WebLeacher 1;
|
||||||
|
~*WebmasterWorldForumBot 1;
|
||||||
|
~*WebPix 1;
|
||||||
|
~*WebReaper 1;
|
||||||
|
~*WebSauger 1;
|
||||||
|
~*WebShag 1;
|
||||||
|
~*Website\.eXtractor 1;
|
||||||
|
~*Website\ eXtractor 1;
|
||||||
|
~*Website\ Quester 1;
|
||||||
|
~*Webster 1;
|
||||||
|
~*WebStripper 1;
|
||||||
|
~*WebSucker 1;
|
||||||
|
~*WebWhacker 1;
|
||||||
|
~*WebZIP 1;
|
||||||
|
~*Wells\ Search\ II 1;
|
||||||
|
~*WEP\ Search 1;
|
||||||
|
~*WeSEE 1;
|
||||||
|
~*Wget 1;
|
||||||
|
~*Whack 1;
|
||||||
|
~*Whacker 1;
|
||||||
|
~*Widow 1;
|
||||||
|
~*WinHTTrack 1;
|
||||||
|
~*WinInet 1;
|
||||||
|
~*WISENutbot 1;
|
||||||
|
~*woobot 1;
|
||||||
|
~*woopingbot 1;
|
||||||
|
~*worldwebheritage.org 1;
|
||||||
|
~*Wotbox 1;
|
||||||
|
~*WPScan 1;
|
||||||
|
~*WWW\-Collector\-E 1;
|
||||||
|
~*WWW\-Mechanize 1;
|
||||||
|
~*WWWOFFLE 1;
|
||||||
|
~*Xaldon 1;
|
||||||
|
~*Xaldon\ WebSpider 1;
|
||||||
|
~*Xenu 1;
|
||||||
|
~*XoviBot 1;
|
||||||
|
~*yacybot 1;
|
||||||
|
~*YisouSpider 1;
|
||||||
|
~*Zade 1;
|
||||||
|
~*zermelo 1;
|
||||||
|
~*Zeus 1;
|
||||||
|
~*zh\-CN 1;
|
||||||
|
~*ZmEu 1;
|
||||||
|
~*ZumBot 1;
|
||||||
|
~*Zyborg 1;
|
||||||
|
~*ZyBorg 1;
|
||||||
|
~*Yandex 1;
|
||||||
|
~*YandexBot 1;
|
||||||
|
~*Baiduspider 1;
|
||||||
|
~*BaiduSpider 1;
|
||||||
|
~*Slackbot 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map $http_user_agent $bad_bot1 {
|
||||||
|
default 0;
|
||||||
|
~*^Lynx 0; # Let Lynx go through
|
||||||
|
libwww-perl 1;
|
||||||
|
~*(?i)(80legs|360Spider|Aboundex|AhrefsBot|Daumoa|DataForSeoBot|DaumBot|applebot|BLEXBot|serpstatbot|MediaMathbot|Abonti|Acunetix|^AIBOT|^Alexibot|Alligator|AllSubmitter|Apexoo|^asterias|^attach|^BackDoorBot|^BackStreet|^BackWeb|Badass|Bandit|petalbot|Baid|Baiduspider|^BatchFTP|^Bigfoot|^Black.Hole|^BlackWidow|BlackWidow|^BlowFish|Blow|^BotALot|Buddy|^BuiltBotTough|^Bullseye|^BunnySlippers|BBBike|^Cegbfeieh|^CheeseBot|^CherryPicker|^ChinaClaw|^Cogentbot|CPython|Collector|cognitiveseo|Copier|^CopyRightCheck|^cosmos|^Crescent|CSHttp|^Custo|^Demon|^Devil|^DISCo|^DIIbot|discobot|^DittoSpyder|Download.Demon|Download.Devil|Download.Wonder|^dragonfly|^Drip|^eCatch|^EasyDL|^ebingbong|^EirGrabber|^EmailCollector|^EmailSiphon|^EmailWolf|^EroCrawler|^Exabot|^Express|Extractor|^EyeNetIE|FHscan|^FHscan|^flunky|^Foobot|^FrontPage|GalaxyBot|^gotit|Grabber|^GrabNet|^Grafula|^Harvest|^HEADMasterSEO|^hloader|^HMView|^HTTrack|httrack|HTTrack|htmlparser|^humanlinks|^IlseBot|Image.Stripper|Image.Sucker|imagefetch|^InfoNaviRobot|^InfoTekies|^Intelliseek|^InterGET|^Iria|^Jakarta|^JennyBot|^JetCar|JikeSpider|^JOC|^JustView|^Jyxobot|^Kenjin.Spider|^Keyword.Density|libwww|^larbin|LeechFTP|LeechGet|^LexiBot|^lftp|^libWeb|^likse|^LinkextractorPro|^LinkScan|^LNSpiderguy|^LinkWalker|msnbot|MSIECrawler|MJ12bot|MegaIndex|^Magnet|^Mag-Net|^MarkWatch|Mass.Downloader|masscan|^Mata.Hari|^Memo|^MIIxpc|^NAMEPROTECT|^Navroad|^NearSite|^NetAnts|^Netcraft|^NetMechanic|^NetSpider|^NetZIP|^NextGenSearchBot|^NICErsPRO|^niki-bot|^NimbleCrawler|^Nimbostratus-Bot|^Ninja|^Nmap|nmap|^NPbot|Offline.Explorer|Offline.Navigator|OpenLinkProfiler|^Octopus|^Openfind|^OutfoxBot|Pixray|probethenet|proximic|^PageGrabber|^pavuk|^pcBrowser|^Pockey|^ProPowerBot|^ProWebWalker|^psbot|^Pump|python-requests|^QueryN.Metasearch|^RealDownload|Reaper|^Reaper|^Ripper|Ripper|Recorder|^ReGet|^RepoMonkey|^RMA|scanbot|SEOkicks-Robot|seoscanners|^Stripper|^Sucker|Siphon|Siteimprove|^SiteSnagger|SiteSucker|^SlySearch|^SmartDownload|^Snake|^Snapbot|^Snoopy|Sosospider|^sogou|spbot|^SpaceBison|^spanner|^SpankBot|Spinn4r|^Sqworm|Sqworm|Stripper|Sucker|^SuperBot|SuperHTTP|^SuperHTTP|^Surfbot|^suzuran|^Szukacz|^tAkeOut|^Teleport|^Telesoft|^TurnitinBot|^The.Intraformant|^TheNomad|^TightTwatBot|^Titan|^True_Robot|^turingos|^TurnitinBot|^URLy.Warning|^Vacuum|^VCI|VidibleScraper|^VoidEYE|^WebAuto|^WebBandit|^WebCopier|^WebEnhancer|^WebFetch|^Web.Image.Collector|^WebLeacher|^WebmasterWorldForumBot|WebPix|^WebReaper|^WebSauger|Website.eXtractor|^Webster|WebShag|^WebStripper|WebSucker|^WebWhacker|^WebZIP|Whack|Whacker|^Widow|Widow|WinHTTrack|^WISENutbot|WWWOFFLE|^WWWOFFLE|^WWW-Collector-E|^Xaldon|^Xenu|^Zade|^Zeus|ZmEu|^Zyborg|SemrushBot|^WebFuck|^MJ12bot|^majestic12|^WallpapersHD) 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
## Add here all referrers that are to blocked.
|
||||||
|
map $http_referer $bad_referer {
|
||||||
|
default 0;
|
||||||
|
~(?i)(adcash|advair|allegra|ambien|amoxicillin|adult|anal|asshole|babes|baccarat|betting|bithack|blackjack|cash|casino|celeb|cheap|cialis|craps|credit|click|cunt|deal|debt|drug|diamond|effexor|equity|faxo|finance|fisting|forsale|gambling|gaysex|girl|hardcore|hold-em|holdem|iconsurf|ilovevitaly|insurance|interest|internetsupervision|jewelry|keno|levitra|lipitor|loan|loans|love|makemoneyonline|make-money-online|meds|money|mortgage|myftpupload|nudit|omaha|organic|paxil|pharmacy|pharmacies|phentermine|pheromone|pills|piss|poker|porn|poweroversoftware|refinance|replica|rimming|roulette|screentoolkit|seoexperimenty|sex|snuff|scout|seventwentyfour|slot|slots|syntryx|teen|texas|t0phackteam|tournament|tramadol|tramidol|valtrex|vvakhrin-ws1|viagra|vicodin|webcam|xanax|xnxx|xxxrus|zanax|zippo|zoloft) 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
## Add here all bad referer domains to be blocked - broken up into sections
|
||||||
|
## Alphabetical A - E (incl numbers)
|
||||||
|
map $http_referer $bad_urls1 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?38ha(-|.).*$|^http://(www\.)?4free(-|.).*$|^http://(www\.)?4hs8(-|.).*$|^http://(www\.)?4t(-|.).*$|^http://(www\.)?4u(-|.).*$|^http://(www\.)?6q(-|.).*$|^http://(www\.)?7makemoneyonline(-|.).*$|^http://(www\.)?8gold(-|.).*$|^http://(www\.)?911(-|.).*$|^http://(www\.)?adcash(-|.).*$|^http://(www\.)?.*(-|.)?adult(-|.).*$|^http://(www\.)?.*(-|.)?acunetix-referrer(-|.).*$|^http://(www\.)?abalone(-|.).*$|^http://(www\.)?adminshop(-|.).*$|^http://(www\.)?adultactioncam(-|.).*$|^http://(www\.)?aizzo(-|.).*$|^http://(www\.)?alphacarolinas(-|.).*$|^http://(www\.)?amateur(-|.).*$|^http://(www\.)?amateurxpass(-|.).*$|^http://(www\.)?.*(-|.)?anal(-|.).*$|^http://(www\.)?ansar-u-deen(-|.).*$|^http://(www\.)?atelebanon(-|.).*$|^http://(www\.)?beastiality(-|.).*$|^http://(www\.)?bestiality(-|.).*$|^http://(www\.)?belize(-|.).*$|^http://(www\.)?best-deals(-|.).*$|^http://(www\.)?bithack(-|.).*$|^http://(www\.)?blogincome(-|.).*$|^http://(www\.)?bontril(-|.).*$|^http://(www\.)?bruce-holdeman(-|.).*$|^http://(www\.)?.*(-|.)?blow.?job(-|.).*$|^http://(www\.)?buttons-for-website(-|.).*$|^http://(www\.)?ca-america(-|.).*$|^http://(www\.)?chatt-net(-|.).*$|^http://(www\.)?cenokos(-|.).*$|^http://(www\.)?cenoval(-|.).*$|^http://(www\.)?cityadspix(-|.).*$|^http://(www\.)?commerce(-|.).*$|^http://(www\.)?condo(-|.).*$|^http://(www\.)?conjuratia(-|.).*$|^http://(www\.)?consolidate(-|.).*$|^http://(www\.)?coswap(-|.).*$|^http://(www\.)?crescentarian(-|.).*$|^http://(www\.)?crepesuzette(-|.).*$|^http://(www\.)?darodar(-|.).*$|^http://(www\.)?dating(-|.).*$|^http://(www\.)?devaddict(-|.).*$|^http://(www\.)?discount(-|.).*$|^http://(www\.)?doobu(-|.).*$|^http://(www\.)?domainsatcost(-|.).*$|^http://(www\.)?econom.co(-|.).*$|^http://(www\.)?edakgfvwql(-|.).*$|^http://(www\.)?.*(-|.)?sex(-|.).*$|^http://(www\.)?e-site(-|.).*$|^http://(www\.)?egygift(-|.).*$|^http://(www\.)?empathica(-|.).*$|^http://(www\.)?empirepoker(-|.).*$|^http://(www\.)?e-poker-2005(-|.).*$|^http://(www\.)?escal8(-|.).*$|^http://(www\.)?eurip(-|.).*$|^http://(www\.)?exitq(-|.).*$|^http://(www\.)?eyemagination(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
## F - I
|
||||||
|
map $http_referer $bad_urls2 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?fastcrawl(-|.).*$|^http://(www\.)?fearcrow(-|.).*$|^http://(www\.)?ferretsoft(-|.).*$|^http://(www\.)?fick(-|.).*$|^http://(www\.)?finance(-|.).*$|^http://(www\.)?flafeber(-|.).*$|^http://(www\.)?fidelityfunding(-|.).*$|^http://(www\.)?freakycheats(-|.).*$|^http://(www\.)?freeality(-|.).*$|^http://(www\.)?fuck(-|.).*$|^http://(www\.)?future-2000(-|.).*$|^http://(www\.)?.*(-|.)?gay(-|.).*$|^http://(www\.)?gobongo.info(-|.).*$|^http://(www\.)?gabriola(-|.).*$|^http://(www\.)?gallerylisting(-|.).*$|^http://(www\.)?gb.com(-|.).*$|^http://(www\.)?ghostvisitor(-|.).*$|^http://(www\.)?globusy(-|.).*$|^http://(www\.)?golf-e-course(-|.).*$|^http://(www\.)?gospelcom(-|.).*$|^http://(www\.)?gradfinder(-|.).*$|^http://(www\.)?hasfun(-|.).*$|^http://(www\.)?herbal(-|.).*$|^http://(www\.)?hermosa(-|.).*$|^http://(www\.)?highprofitclub(-|.).*$|^http://(www\.)?hilton(-|.).*$|^http://(www\.)?teaminspection(-|.).*$|^http://(www\.)?hotel(-|.).*$|^http://(www\.)?houseofseven(-|.).*$|^http://(www\.)?hurricane(-|.).*$|^http://(www\.)?.*(-|.)?incest(-|.).*$|^http://(www\.)?iaea(-|.).*$|^http://(www\.)?ilovevitality(-|.).*$|^http://(www\.)?ime(-|.).*$|^http://(www\.)?info(-|.).*$|^http://(www\.)?ingyensms(-|.).*$|^http://(www\.)?inkjet-toner(-|.).*$|^http://(www\.)?isacommie(-|.).*$|^http://(www\.)?istarthere(-|.).*$|^http://(www\.)?it.tt(-|.).*$|^http://(www\.)?italiancharms(-|.).*$|^http://(www\.)?iwantu(-|.).*$|^http://(www\.)?ilovevitality(-|.).*$|^http://(www\.)?iskalko.ru(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
## J - P
|
||||||
|
map $http_referer $bad_urls3 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?jfcadvocacy(-|.).*$|^http://(www\.)?jmhic(-|.).*$|^http://(www\.)?juris(-|.).*$|^http://(www\.)?kylos(-|.).*$|^http://(www\.)?laser-eye(-|.).*$|^http://(www\.)?leathertree(-|.).*$|^http://(www\.)?lillystar(-|.).*$|^http://(www\.)?linkerdome(-|.).*$|^http://(www\.)?livenet(-|.).*$|^http://(www\.)?low-limit(-|.).*$|^http://(www\.)?lowest-price(-|.).*$|^http://(www\.)?luxup.ru(-|.).*$|^http://(www\.)?macsurfer(-|.).*$|^http://(www\.)?mall.uk(-|.).*$|^http://(www\.)?maloylawn(-|.).*$|^http://(www\.)?marketing(-|.).*$|^http://(www\.)?.*(-|.)?mature(-|.).*$|^http://(www\.)?mcdortaklar(-|.).*$|^http://(www\.)?mediavisor(-|.).*$|^http://(www\.)?medications(-|.).*$|^http://(www\.)?mirror.sytes(-|.).*$|^http://(www\.)?mp3(-|.).*$|^http://(www\.)?(-|.)musicbox1(-|.).*$|^http://(www\.)?myftpupload(-|.).*$|^http://(www\.)?naked(-|.).*$|^http://(www\.)?netdisaster(-|.).*$|^http://(www\.)?netfirms(-|.).*$|^http://(www\.)?newtruths(-|.).*$|^http://(www\.)?no-limit(-|.).*$|^http://(www\.)?nude(-|.).*$|^http://(www\.)?nudeceleb(-|.).*$|^http://(www\.)?nutzu(-|.).*$|^http://(www\.)?odge(-|.).*$|^http://(www\.)?oiline(-|.).*$|^http://(www\.)?onlinegamingassoc(-|.).*$|^http://(www\.)?outpersonals(-|.).*$|^http://(www\.)?o-o-6-o-o.ru(-|.).*$|^http://(www\.)?o-o-8-o-o.ru(-|.).*$|^http://(www\.)?pagetwo(-|.).*$|^http://(www\.)?paris(-|.).*$|^http://(www\.)?passions(-|.).*$|^http://(www\.)?peblog(-|.).*$|^http://(www\.)?peng(-|.).*$|^http://(www\.)?perfume-cologne(-|.).*$|^http://(www\.)?personal(-|.).*$|^http://(www\.)?php-soft(-|.).*$|^http://(www\.)?pisoc(-|.).*$|^http://(www\.)?pisx(-|.).*$|^http://(www\.)?popwow(-|.).*$|^http://(www\.)?porn(-|.).*$|^http://(www\.)?prescriptions(-|.).*$|^http://(www\.)?priceg(-|.).*$|^http://(www\.)?.*(-|.)?pus*y(-|.).*$|^http://(www\.)?printdirectforless(-|.).*$|^http://(www\.)?ps2cool(-|.).*$|^http://(www\.)?psnarones(-|.).*$|^http://(www\.)?psxtreme(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
## Q - Z
|
||||||
|
map $http_referer $bad_urls4 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?quality-traffic(-|.).*$|^http://(www\.)?registrarprice(-|.).*$|^http://(www\.)?reliableresults(-|.).*$|^http://(www\.)?rimpim(-|.).*$|^http://(www\.)?ro7kalbe(-|.).*$|^http://(www\.)?rohkalby(-|.).*$|^http://(www\.)?ronnieazza(-|.).*$|^http://(www\.)?rulo.biz(-|.).*$|^http://(www\.)?responsinator(-|.).*$|^http://(www\.)?s5(-|.).*$|^http://(www\.)?samiuls(-|.).*$|^http://(www\.)?savefrom(-|.).*$|^http://(www\.)?savetubevideo.com(-|.).*$|^http://(www\.)?screentoolkit.com(-|.).*$|^http://(www\.)?searchedu(-|.).*$|^http://(www\.)?semalt.com(-|.).*$|^http://(www\.)?seoexperimenty(-|.).*$|^http://(www\.)?seventwentyfour(-|.).*$|^http://(www\.)?seventwentyfour.*$|^http://(www\.)?sex(-|.).*$|^http://(www\.)?sexsearch(-|.).*$|^http://(www\.)?sexsq(-|.).*$|^http://(www\.)?shoesdiscount(-|.).*$|^http://(www\.)?site-4u(-|.).*$|^http://(www\.)?site5(-|.).*$|^http://(www\.)?slatersdvds(-|.).*$|^http://(www\.)?slftsdybbg.ru(-|.).*$|^http://(www\.)?sml338(-|.).*$|^http://(www\.)?sms(-|.).*$|^http://(www\.)?smsportali(-|.).*$|^http://(www\.)?socialseet.ru(-|.).*$|^http://(www\.)?software(-|.).*$|^http://(www\.)?sortthemesitesby(-|.).*$|^http://(www\.)?spears(-|.).*$|^http://(www\.)?spoodles(-|.).*$|^http://(www\.)?sportsparent(-|.).*$|^http://(www\.)?srecorder(-|.).*$|^http://(www\.)?stmaryonline(-|.).*$|^http://(www\.)?superiends.org(-|.).*$|^http://(www\.)?strip(-|.).*$|^http://(www\.)?suttonjames(-|.).*$|^http://(www\.)?talk.uk-yankee(-|.).*$|^http://(www\.)?tecrep-inc(-|.).*$|^http://(www\.)?teen(-|.).*$|^http://(www\.)?terashells(-|.).*$|^http://(www\.)?thatwhichis(-|.).*$|^http://(www\.)?thorcarlson(-|.).*$|^http://(www\.)?.*(-|.)?tits(-|.).*$|^http://(www\.)?.*(-|.)?titten(-|.).*$|^http://(www\.)?tmsathai(-|.).*$|^http://(www\.)?traffixer(-|.).*$|^http://(www\.)?tranny(-|.).*$|^http://(www\.)?valeof(-|.).*$|^http://(www\.)?video(-|.).*$|^http://(www\.)?vinhas(-|.).*$|^http://(www\.)?vixen1(-|.).*$|^http://(www\.)?vpshs(-|.).*$|^http://(www\.)?vrajitor(-|.).*$|^http://(www\.)?vodkoved.ru(-|.).*$|^http://(www\.)?w3md(-|.).*$|^http://(www\.)?websocial.me(-|.).*$|^http://(www\.)?webdevsquare(-|.).*$|^http://(www\.)?whois(-|.).*$|^http://(www\.)?withdrawal(-|.).*$|^http://(www\.)?worldemail(-|.).*$|^http://(www\.)?wslp24(-|.).*$|^http://(www\.)?ws-op(-|.).*$|^http://(www\.)?xnxx(-|.).*$|^http://(www\.)?xopy(-|.).*$|^http://(www\.)?xxx(-|.).*$|^http://(www\.)?yelucie(-|.).*$|^http://(www\.)?youradulthosting(-|.).*$|^http://(www\.)?ykecwqlixx.ru(-|.).*$|^http://(www\.)?yougetsignal.com(-|.).*$|^http://(www\.)?(-|.)zindagi(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
## Domains Linked to Yontoo Browser Malware and a Few Other New Ones
|
||||||
|
## Have split this into it's own section to keep lines shorter NOTE: changes to instructions
|
||||||
|
## adding if ($bad_urls5) and if ($bad_urls6) to your site(s) config.
|
||||||
|
map $http_referer $bad_urls5 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?101raccoon.ru(-|.).*$|^http://(www\.)?28n2gl3wfyb0.ru(-|.).*$|^http://(www\.)?627ad6438b58439cad1fc8cf6d67a92e.com(-|.).*$|^http://(www\.)?6ab9743d0152486387559b4abaa02ada.com(-|.).*$|^http://(www\.)?a342ae9750004b14b55f7310eff0ab65.com(-|.).*$|^http://(www\.)?aa08daf7e13b6345e09e92f771507fa5f4.com(-|.).*$|^http://(www\.)?aa14ab57a3339c4064bd9ae6fad7495b5f.com(-|.).*$|^http://(www\.)?aa625d84f1587749c1ab011d6f269f7d64.com(-|.).*$|^http://(www\.)?aa81bf391151884adfa3dd677e41f94be1.com(-|.).*$|^http://(www\.)?aa8780bb28a1de4eb5bff33c28a218a930.com(-|.).*$|^http://(www\.)?aa8b68101d388c446389283820863176e7.com(-|.).*$|^http://(www\.)?aa9bd78f328a6a41279d0fad0a88df1901.com(-|.).*$|^http://(www\.)?aa9d046aab36af4ff182f097f840430d51.com(-|.).*$|^http://(www\.)?aaa38852e886ac4af1a3cff9b47cab6272.com(-|.).*$|^http://(www\.)?aab94f698f36684c5a852a2ef272e031bb.com(-|.).*$|^http://(www\.)?aac500b7a15b2646968f6bd8c6305869d7.com(-|.).*$|^http://(www\.)?aac52006ec82a24e08b665f4db2b5013f7.com(-|.).*$|^http://(www\.)?aad1f4acb0a373420d9b0c4202d38d94fa.com(-|.).*$|^http://(www\.)?asrv-a.akamoihd.net(-|.).*$|^http://(www\.)?asrvrep-a.akamaihd.net(-|.).*$|^http://(www\.)?bestpriceninja.com(-|.).*$|^http://(www\.)?bronzeaid-a.akamaihd.net(-|.).*$|^http://(www\.)?browsepulse-a.akamaihd.net(-|.).*$|^http://(www\.)?cashkitten-a.akamaihd.net(-|.).*$|^http://(www\.)?coolbar.pro(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
map $http_referer $bad_urls6 {
|
||||||
|
default 0;
|
||||||
|
~(?i)(^http://(www\.)?davebestdeals.com(-|.).*$|^http://(www\.)?discovertreasure-a.akamaihd.net(-|.).*$|^http://(www\.)?discovertreasurenow.com(-|.).*$|^http://(www\.)?foxydeal.com(-|.).*$|^http://(www\.)?gameonasia.com(-|.).*$|^http://(www\.)?gameplexcity.com(-|.).*$|^http://(www\.)?gamerextra.com(-|.).*$|^http://(www\.)?gamerscorps.com(-|.).*$|^http://(www\.)?gamewrath.com(-|.).*$|^http://(www\.)?generousdeal-a.akamaihd.net(-|.).*$|^http://(www\.)?girlgamerdaily.com(-|.).*$|^http://(www\.)?hdapp1008-a.akamaihd.net(-|.).*$|^http://(www\.)?highstairs-a.akamaihd.net(-|.).*$|^http://(www\.)?hotshoppymac.com(-|.).*$|^http://(www\.)?matchpal-a.akamaihd.net(-|.).*$|^http://(www\.)?mecash.ru(-|.).*$|^http://(www\.)?monarchfind-a.akamaihd.net(-|.).*$|^http://(www\.)?myshopmatemac.com(-|.).*$|^http://(www\.)?nottyu.xyz(-|.).*$|^http://(www\.)?onlinemegax.com(-|.).*$|^http://(www\.)?outrageousdeal-a.akamaihd.net(-|.).*$|^http://(www\.)?pijoto.net(-|.).*$|^http://(www\.)?recordpage-a.akamaihd.net(-|.).*$|^http://(www\.)?resultshub-a.akamaihd.net(-|.).*$|^http://(www\.)?rvzr-a.akamaihd.net(-|.).*$|^http://(www\.)?savingsslider-a.akamaihd.net(-|.).*$|^http://(www\.)?searchinterneat-a.akamaihd.net(-|.).*$|^http://(www\.)?searchwebknow-a.akamaihd.net(-|.).*$|^http://(www\.)?seeresultshub-a.akamaihd.net(-|.).*$|^http://(www\.)?shoppytoolmac.com(-|.).*$|^http://(www\.)?skytraf.xyz(-|.).*$|^http://(www\.)?splendorsearch-a.akamaihd.net(-|.).*$|^http://(www\.)?strongsignal-a.akamaihd.net(-|.).*$|^http://(www\.)?surfbuyermac.com(-|.).*$|^http://(www\.)?treasuretrack-a.akamaihd.net(-|.).*$|^http://(www\.)?webshoppermac.com(-|.).*$|^http://(www\.)?pospr.waw.pl(-|.).*$|^http://(www\.)?abclauncher.com(-|.).*$|^http://(www\.)?alert-fjg.xyz(-|.).*$|^http://(www\.)?analytics-ads.xyz(-|.).*$|^http://(www\.)?bamo.xsl.pt(-|.).*$|^http://(www\.)?compliance-olga.top(-|.).*$|^http://(www\.)?digital-video-processing.com(-|.).*$|^http://(www\.)?eu-cookie-law.info(-|.).*$|^http://(www\.)?findpik.com(-|.).*$|^http://(www\.)?forum20.smailik.org(-|.).*$|^http://(www\.)?free-share-buttons.top(-|.).*$|^http://(www\.)?free-social-buttons2.xyz(-|.).*$|^http://(www\.)?free-social-buttons3.xyz(-|.).*$|^http://(www\.)?free-social-buttons4.xyz(-|.).*$|^http://(www\.)?free-social-buttons5.xyz(-|.).*$|^http://(www\.)?front.to(-|.).*$|^http://(www\.)?infokonkurs.ru(-|.).*$|^http://(www\.)?mapquestz.us(-|.).*$|^http://(www\.)?quick-offer.com(-|.).*$|^http://(www\.)?rank-checker.online(-|.).*$|^http://(www\.)?rankchecker.online(-|.).*$|^http://(www\.)?rapidokbrain.com(-|.).*$|^http://(www\.)?real-time-analytics.com(-|.).*$|^http://(www\.)?sharebutton.net(-|.).*$|^http://(www\.)?sharebutton.org(-|.).*$|^http://(www\.)?shemale-sex.net(-|.).*$|^http://(www\.)?site-speed-check.site(-|.).*$|^http://(www\.)?site-speed-checker.site(-|.).*$|^http://(www\.)?trafficmania.com(-|.).*$|^http://(www\.)?website-speed-up.site(-|.).*$|^http://(www\.)?website-speed-up.top(-|.).*$|^http://(www\.)?xn--80aagddcgkbcqbad7amllnejg6dya.xn--p1ai(-|.).*$|^http://(www\.)?xn--80aikhbrhr.net(-|.).*$|^http://(www\.)?pila.pl(-|.).*$|^http://(www\.)?dytohqka.su(-|.).*$|^http://(www\.)?fqvjhqciw.net.ru(-|.).*$|^http://(www\.)?wycjrqzy.ua(-|.).*$|^http://(www\.)?0ca29773681c7e82.com(-|.).*$|^http://(www\.)?intervsem.ru(-|.).*$|^http://(www\.)?candy-glam-hp.com(-|.).*$|^http://(www\.)?thecoolimages.net(-|.).*$|^http://(www\.)?rebuildermedical.com(-|.).*$|^http://(www\.)?gaygalls.net(-|.).*$|^http://(www\.)?keywordteam.net(-|.).*$|^http://(www\.)?netfacet.net(-|.).*$|^http://(www\.)?pattersonsweb.com(-|.).*$|^http://(www\.)?trapit.com.gg(-|.).*$) 1;
|
||||||
|
}
|
||||||
|
## Add here all hosts that should be spared any referrer checking.
|
||||||
|
## Whitelist all your own IPs in this section, each IP followed by a 0;
|
||||||
|
geo $bad_referer {
|
||||||
|
127.0.0.1 0;
|
||||||
|
40.82.153.189 0;
|
||||||
|
111.111.111.111 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Geo directive to deny certain ip addresses
|
||||||
|
geo $validate_client {
|
||||||
|
default 0;
|
||||||
|
|
||||||
|
# Cyveillance
|
||||||
|
38.100.19.8/29 1;
|
||||||
|
38.100.21.0/24 1;
|
||||||
|
38.100.41.64/26 1;
|
||||||
|
38.105.71.0/25 1;
|
||||||
|
38.105.83.0/27 1;
|
||||||
|
38.112.21.140/30 1;
|
||||||
|
38.118.42.32/29 1;
|
||||||
|
65.213.208.128/27 1;
|
||||||
|
65.222.176.96/27 1;
|
||||||
|
65.222.185.72/29 1;
|
||||||
|
85.25.176.0/20 1;
|
||||||
|
85.25.192.0/20 1;
|
||||||
|
85.25.208.0/22 1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
# ===============================================
|
||||||
|
# Production Level Nginx Configuration (Sample Template)
|
||||||
|
# 서버 사양: 쿼드코어 CPU, 4GB RAM, ~50 req/s
|
||||||
|
# 백엔드: FastAPI REST API Server
|
||||||
|
# ===============================================
|
||||||
|
|
||||||
|
# HTTP 서버 블록 (포트 80) - HTTPS로 리다이렉트
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name demo.castad.net www.demo.castad.net;
|
||||||
|
|
||||||
|
# 보안을 위한 호스트 검증 - 허용되지 않은 도메인 차단
|
||||||
|
# 도메인 확장자가 다르다면 추가해줘야함
|
||||||
|
# if ($host !~* ^(www\.)?demo.castad.net\.(com|kr|net|org)$) {
|
||||||
|
# return 444;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Let's Encrypt 도메인 검증 프로그램 허용 (리다이렉트 전에 처리)
|
||||||
|
# SSL 인증서 갱신을 위해 필수
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/certbot;
|
||||||
|
try_files $uri =404; # 디렉토리 순회 공격 방지
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTP를 HTTPS로 리다이렉트 (acme-challenge 제외)
|
||||||
|
# return 301은 rewrite보다 효율적이며 $server_name이 $host보다 안전함
|
||||||
|
location / {
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS 서버 블록 (포트 443) - 메인 애플리케이션
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
http2 on;
|
||||||
|
|
||||||
|
server_name demo.castad.net www.demo.castad.net;
|
||||||
|
|
||||||
|
# 악성 봇 차단 (nginx.conf의 http 블록에서 $bad_bot 맵 정의 필요)
|
||||||
|
if ($bad_bot) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
# SSL/TLS 인증서 설정
|
||||||
|
ssl_certificate /etc/letsencrypt/live/demo.castad.net/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/demo.castad.net/privkey.pem;
|
||||||
|
ssl_dhparam /etc/ssl/certs/demo.castad.net/dhparam.pem; # openssl dhparam -out /etc/ssl/certs/demo.castad.net/dhparam.pem 2048
|
||||||
|
|
||||||
|
# 최신 SSL/TLS 설정 - SSL Labs A+ 등급 달성 가능
|
||||||
|
ssl_session_cache shared:SSL:50m; # SSL 세션 캐시 크기 증가 (트래픽 많을 시 유용)
|
||||||
|
ssl_session_timeout 10m; # SSL 세션 타임아웃
|
||||||
|
ssl_session_tickets off; # 보안 향상을 위해 세션 티켓 비활성화 (nginx >= 1.5.9)
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3; # 최신 TLS 프로토콜만 사용
|
||||||
|
ssl_prefer_server_ciphers off; # TLSv1.3에서는 클라이언트 선호 암호화 사용 (모범 사례)
|
||||||
|
# 최신 암호화 스위트 - CHACHA20-POLY1305 포함 (모바일 최적화)
|
||||||
|
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_ecdh_curve secp384r1; # ECDH 곡선 설정 (nginx >= 1.1.0)
|
||||||
|
|
||||||
|
# OCSP 스테이플링 - SSL 핸드셰이크 성능 향상
|
||||||
|
# 인증서에 OCSP URL이 없으면 자동으로 비활성화됨 (경고는 정상)
|
||||||
|
#ssl_stapling on;
|
||||||
|
#ssl_stapling_verify on;
|
||||||
|
ssl_trusted_certificate /etc/letsencrypt/live/demo.castad.net/chain.pem;
|
||||||
|
resolver 1.1.1.1 8.8.8.8 valid=300s; # Cloudflare와 Google DNS 사용
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
|
# 보안 헤더 - 다양한 공격으로부터 보호
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # HSTS - 다운그레이드 공격 방지
|
||||||
|
add_header X-Frame-Options "DENY" always; # 클릭재킹 방지
|
||||||
|
add_header X-Content-Type-Options "nosniff" always; # MIME 스니핑 방지
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always; # 레거시 XSS 보호
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 리퍼러 정보 제어
|
||||||
|
#add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' ''; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: ws:;" always;
|
||||||
|
#add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://www.youtube.com https://s.ytimg.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.tailwindcss.com; font-src 'self' data: https://fonts.gstatic.com; img-src 'self' data: https: https://i.ytimg.com https://img.youtube.com; connect-src 'self' wss: ws: https://cdn.tailwindcss.com; frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com; media-src 'self' https://www.youtube.com;" always;
|
||||||
|
add_header Content-Security-Policy "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;" always;
|
||||||
|
|
||||||
|
# XSS 방지를 위한 CSP
|
||||||
|
# 'unsafe-inline'은 범용 설정이 아니며, 보안상 위험한 설정입니다. CSP의 핵심 보호 기능을 무력화시키므로, 개발 환경이나 레거시 코드 마이그레이션 과정에서만 임시로 사용하고, 프로덕션 환경에서는 nonce, hash, 또는 외부 파일 분리 방식으로 대체해야 합니다.
|
||||||
|
|
||||||
|
# 클라이언트가 업로드할 수 있는 전체 요청 본문(body) 의 최대 허용 크기
|
||||||
|
# 요청 바디(파일, 폼 데이터 등)가 이 값을 초과하면 Nginx는 즉시 413 Request Entity Too Large 에러를 반환
|
||||||
|
# 업로드 제한선.
|
||||||
|
client_max_body_size 100M; # 최대 업로드 크기 제한 (애플리케이션에 맞게 조정)
|
||||||
|
|
||||||
|
# 파일 캐시 - I/O 성능 향상
|
||||||
|
open_file_cache max=1000 inactive=20s; # 최대 1000개 파일 캐시, 20초 비활성 시 제거
|
||||||
|
open_file_cache_valid 30s; # 캐시 유효성 검사 주기
|
||||||
|
open_file_cache_min_uses 2; # 최소 2회 사용 시 캐시
|
||||||
|
open_file_cache_errors on; # 파일 오류도 캐시
|
||||||
|
|
||||||
|
# 로깅 설정 - 버퍼링으로 I/O 감소
|
||||||
|
access_log /log/nginx/demo.castad.net.com.gunicorn_access.log main buffer=32k flush=5s;
|
||||||
|
error_log /log/nginx/demo.castad.net.com.gunicorn_error.log warn;
|
||||||
|
|
||||||
|
# frontend에 오류 페이지 정의가 되어 있는 경우 사용 가능
|
||||||
|
# # 커스텀 오류 페이지 - 더 나은 사용자 경험 및 정보 노출 방지
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
|
||||||
|
# location = /404.html {
|
||||||
|
# internal; # 내부 리다이렉트만 허용
|
||||||
|
# root /www/error_pages;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# location = /50x.html {
|
||||||
|
# internal; # 내부 리다이렉트만 허용
|
||||||
|
# root /www/error_pages;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# 프론트엔드 정적 파일 루트
|
||||||
|
root /www/o2o-castad-frontend/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fastapi 미디어 파일 - 사용자 업로드 파일
|
||||||
|
location /media {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
# gzip_static on; # 사전 압축된 .gz 파일 사용
|
||||||
|
expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증
|
||||||
|
alias /www/o2o-castad-backend/media; # Fastapi 프로젝트의 미디어 파일 경로
|
||||||
|
|
||||||
|
# 정적 파일 캐싱 - 브라우저 캐시 최적화
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fastapi 정적 파일 - CSS, JS, 이미지 등
|
||||||
|
location /static {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
# gzip_static on; # 사전 압축된 .gz 파일 사용 압축된 파일이 없다면 설정 무의미
|
||||||
|
expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증
|
||||||
|
alias /www/o2o-castad-backend/static; # Fastapi 프로젝트의 정적 파일 경로
|
||||||
|
|
||||||
|
# 정적 파일 캐싱 - 브라우저 캐시 최적화
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# 메인 애플리케이션 - 백엔드로 프록시
|
||||||
|
location /api/ {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
|
||||||
|
# 속도 제한 - DDoS 및 무차별 대입 공격 방지
|
||||||
|
# (nginx.conf의 http 블록에서 limit_req_zone과 limit_conn_zone 정의 필요)
|
||||||
|
#limit_req zone=general burst=20 nodelay; # 초당 요청 제한
|
||||||
|
#limit_conn addr 10; # IP당 동시 연결 제한
|
||||||
|
|
||||||
|
# HTTP 메서드 제한 - HTTP 동사 변조 공격 방지
|
||||||
|
limit_except GET POST HEAD OPTIONS DELETE {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 백엔드 애플리케이션으로 프록시
|
||||||
|
proxy_pass http://uvicorn-app:8000/;
|
||||||
|
|
||||||
|
# WebSocket 지원 - 실시간 통신 애플리케이션에 필수
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade; # nginx.conf에서 $connection_upgrade 맵 정의 필요
|
||||||
|
|
||||||
|
# 프록시 헤더 - 클라이언트 정보 전달
|
||||||
|
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;
|
||||||
|
|
||||||
|
# 타임아웃 설정 - 애플리케이션에 맞게 조정
|
||||||
|
proxy_connect_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
|
||||||
|
# 버퍼 설정 - 대화형 애플리케이션에 최적화 - Websocket 사용시 설정
|
||||||
|
# proxy_buffering off; # 즉시 응답 전달
|
||||||
|
# proxy_request_buffering off; # 즉시 요청 전달
|
||||||
|
|
||||||
|
# 버퍼링 활성화 (기본값) - 기본 fastapi 사용시 설정
|
||||||
|
proxy_buffering on;
|
||||||
|
proxy_request_buffering on;
|
||||||
|
|
||||||
|
# 버퍼 크기 설정 - 기본 fastapi 사용시 설정
|
||||||
|
proxy_buffer_size 4k;
|
||||||
|
proxy_buffers 8 4k;
|
||||||
|
proxy_busy_buffers_size 8k;
|
||||||
|
|
||||||
|
proxy_set_header Accept-Encoding gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Let's Encrypt 도메인 검증 프로그램 허용 (HTTPS에서도 필요시)
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/certbot;
|
||||||
|
try_files $uri =404; # 디렉토리 순회 공격 방지
|
||||||
|
}
|
||||||
|
|
||||||
|
# 정적 리소스 캐싱 - 이미지, 폰트, CSS, JS 등
|
||||||
|
# 브라우저 캐시로 로드 시간 단축 및 서버 부하 감소
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
|
||||||
|
expires 1y; # 1년 캐시
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# 닷 파일 차단 - .htaccess, .htpasswd, .svn, .git, .env 등
|
||||||
|
# 민감한 설정 파일 노출 방지
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 민감한 파일 확장자 차단 - 로그, 인증서, 스크립트, SQL 등
|
||||||
|
# 보안을 위해 직접 접근 차단
|
||||||
|
location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 민감한 설정 파일 차단 - composer, package.json, phpunit 등
|
||||||
|
# 프로젝트 메타데이터 및 설정 파일 노출 방지
|
||||||
|
location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 파비콘 - 로그 노이즈 제거
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# robots.txt - 검색 엔진 크롤러 제어
|
||||||
|
location = /robots.txt {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo "* if your webroot has sub-level, you should be insert as \\\/A\\\/B\\\/C"
|
||||||
|
echo "ex) shop\\\/django_sample"
|
||||||
|
echo -n "Enter the service web root without the path of '/www/' >"
|
||||||
|
read webroot
|
||||||
|
echo "Entered service web root: $webroot"
|
||||||
|
if [[ "$webroot" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the service portnumber >"
|
||||||
|
read portnumber
|
||||||
|
echo "Entered service portnumber: $portnumber"
|
||||||
|
if [[ "$portnumber" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the service domain >"
|
||||||
|
read domain
|
||||||
|
echo "Entered service domain: $domain"
|
||||||
|
if [[ "$domain" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the app name >"
|
||||||
|
read appname
|
||||||
|
echo "Entered app name: $appname"
|
||||||
|
if [[ "$appname" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Enter the serviceport"
|
||||||
|
echo -n "if you push enter with none, there are no port number >"
|
||||||
|
read serviceport
|
||||||
|
echo "Entered proxy port: $serviceport"
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the file name >"
|
||||||
|
read filename
|
||||||
|
echo "Entered file name: $filename"
|
||||||
|
if [[ "$filename" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sed 's/webroot/'$webroot'/g' sample_nginx.conf > $filename'1'.temp
|
||||||
|
sed 's/portnumber/'$portnumber'/g' $filename'1'.temp > $filename'2'.temp
|
||||||
|
sed 's/domain/'$domain'/g' $filename'2'.temp > $filename'3'.temp
|
||||||
|
sed 's/appname/'$appname'/g' $filename'3'.temp > $filename'4'.temp
|
||||||
|
if [[ "$serviceport" == "" ]]; then
|
||||||
|
sed 's/:serviceport/''/g' $filename'4'.temp > $filename'5'.temp
|
||||||
|
else
|
||||||
|
sed 's/serviceport/'$serviceport'/g' $filename'4'.temp > $filename'5'.temp
|
||||||
|
fi
|
||||||
|
sed 's/filename/'$filename'/g' $filename'5'.temp > ./conf.d/$filename'_gunicorn_ng'.conf
|
||||||
|
|
||||||
|
rm *.temp
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
user www-data;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
# worker_rlimit_nofile directive
|
||||||
|
# CPU: 쿼드코어, RAM: 4GB, 요청수: ~50/s 기반 설정시
|
||||||
|
worker_rlimit_nofile 8192;
|
||||||
|
# worker_rlimit_nofile 8192;
|
||||||
|
# worker_priority 0;
|
||||||
|
# worker_cpu_affinity 0001 0010 0100 1000;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
|
||||||
|
# Load ModSecurity dynamic module
|
||||||
|
# load_module /etc/nginx/modules/ngx_http_modsecurity_module.so
|
||||||
|
|
||||||
|
events {
|
||||||
|
use epoll; # 리눅스에서 권장
|
||||||
|
accept_mutex on; # 기본값이지만 명시해두면 좋음
|
||||||
|
|
||||||
|
# 단일 워커당 동시 연결 수
|
||||||
|
# worker_processes * worker_connections = 최대 동시 연결 수
|
||||||
|
# 여기에 워커가 상시 쓰는 FD(에러/액세스 로그, 리스닝 소켓, epoll 등) 오버헤드를 조금 빼고 잡아야 안전하다 (약 50~150 정도 버퍼).
|
||||||
|
|
||||||
|
# CPU: 쿼드코어, RAM: 4GB, 요청수: ~50/s 기반 설정시
|
||||||
|
# off 설정에 대한 효과
|
||||||
|
# 부하 분산: 워커 간 균등한 연결 분배
|
||||||
|
# 안정성: 한 워커가 과부하되는 것 방지
|
||||||
|
# 예측 가능한 성능: 일관된 응답 시간
|
||||||
|
multi_accept off;
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# WebSocket 및 HTTP keepalive 동시 지원을 위한 Connection 헤더 동적 설정
|
||||||
|
# - WebSocket 요청 ($http_upgrade가 있는 경우): "upgrade" 반환
|
||||||
|
# - 일반 HTTP 요청 ($http_upgrade가 없는 경우): "" 반환 (keepalive 연결 유지)
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' '';
|
||||||
|
}
|
||||||
|
|
||||||
|
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/main_access.log main;
|
||||||
|
error_log /var/log/nginx/main_error.log;
|
||||||
|
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
# Docker 내부 DNS 사용 (컨테이너 이름 해석)
|
||||||
|
resolver 127.0.0.11 valid=30s ipv6=off;
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
|
# 기본 헤더 버퍼 (대부분의 요청 처리)
|
||||||
|
client_header_buffer_size 4k;
|
||||||
|
|
||||||
|
# 큰 헤더 버퍼 (JWT, 큰 쿠키 등)
|
||||||
|
large_client_header_buffers 4 16k;
|
||||||
|
|
||||||
|
# POST나 PUT 요청으로 전송하는 본문(body) 데이터를 받을 때, Nginx가 메모리(RAM)에 임시 저장할 버퍼의 크기
|
||||||
|
client_body_buffer_size 128k; # 일반적으로 64KB~256KB 권장
|
||||||
|
client_body_timeout 15s; # 클라이언트 본문 수신 타임아웃
|
||||||
|
client_header_timeout 15s; # 클라이언트 헤더 수신 타임아웃
|
||||||
|
|
||||||
|
# 효율적인 파일 전송 설정
|
||||||
|
sendfile on; # 커널 공간에서 직접 파일 전송 (제로카피)
|
||||||
|
tcp_nopush on; # sendfile 사용 시 패킷 효율 향상
|
||||||
|
tcp_nodelay on; # Keep-alive 연결에서 지연 없이 전송 (실시간 통신에 유리)
|
||||||
|
|
||||||
|
# Keep-alive 연결 설정
|
||||||
|
keepalive_timeout 30s; # 연결 유지 시간
|
||||||
|
keepalive_requests 1000; # 연결당 최대 요청 수
|
||||||
|
send_timeout 15s; # 클라이언트로 응답 전송 타임아웃
|
||||||
|
|
||||||
|
# ===== 파일 업로드 설정 =====
|
||||||
|
client_max_body_size 50M; # 최대 업로드 크기 (필요에 따라 조정)
|
||||||
|
|
||||||
|
# ===== 프록시 타임아웃 설정 =====
|
||||||
|
proxy_connect_timeout 300s; # 백엔드 연결 타임아웃
|
||||||
|
proxy_send_timeout 300s; # 백엔드로 요청 전송 타임아웃
|
||||||
|
proxy_read_timeout 300s; # 백엔드 응답 수신 타임아웃
|
||||||
|
proxy_request_buffering off; # 대용량 파일 스트리밍 업로드 (버퍼링 비활성화)
|
||||||
|
|
||||||
|
# ===== 해시 테이블 =====
|
||||||
|
# MIME 타입 해시 테이블 설정
|
||||||
|
# mime.types 파일에 정의된 파일 확장자와 MIME 타입 매핑을 저장
|
||||||
|
# 예: .html -> text/html, .jpg -> image/jpeg 등의 매핑을 빠르게 찾기 위해 사용됨
|
||||||
|
|
||||||
|
types_hash_max_size 2048; # 기본 mime.types의 수백 개 타입을 충분히 수용하는 크기
|
||||||
|
types_hash_bucket_size 64; # 각 해시 버킷 크기, CPU 캐시 라인과 정렬하여 성능 최적화
|
||||||
|
|
||||||
|
# 서버 이름 해시 테이블 설정 (server_name 지시자에 정의된 도메인명만 해당)
|
||||||
|
# server 블록의 server_name 지시자에 설정된 도메인명들을 빠르게 매칭하기 위한 해시 테이블
|
||||||
|
server_names_hash_max_size 1024; # 여러 도메인/서브도메인 운영 시 충분한 공간 확보
|
||||||
|
server_names_hash_bucket_size 64; # 도메인명 길이를 고려한 버킷 크기 (일반적으로 32~64면 충분)
|
||||||
|
|
||||||
|
# Nginx 변수 해시 테이블 설정
|
||||||
|
# $host, $remote_addr 같은 내장 변수와 map/set으로 정의한 커스텀 변수들을 저장하는 해시 테이블
|
||||||
|
# HTTP 헤더를 변수로 변환한 $http_* 변수들도 여기에 포함됨 (예: $http_user_agent, $http_referer)
|
||||||
|
variables_hash_max_size 2048; # 내장 변수 + 커스텀 변수를 위한 충분한 공간
|
||||||
|
variables_hash_bucket_size 64; # 변수명 길이와 충돌 방지를 위한 적절한 버킷 크기
|
||||||
|
|
||||||
|
# ===== 압축 설정 =====
|
||||||
|
# 실시간 압축 비활성화 (CPU 부하 감소)
|
||||||
|
gzip off;
|
||||||
|
|
||||||
|
# 미리 압축된 .gz 파일 제공
|
||||||
|
# 예: style.css 요청 시 → style.css.gz 파일을 찾아서 전송
|
||||||
|
gzip_static on;
|
||||||
|
|
||||||
|
# Vary: Accept-Encoding 헤더 추가 (프록시 캐시 호환성)
|
||||||
|
gzip_vary on;
|
||||||
|
|
||||||
|
include /etc/nginx/proxy_params/*;
|
||||||
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
include /etc/nginx/sites-enabled/*.conf;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo "* if your webroot has sub-level, you should be insert as \\\/A\\\/B\\\/C"
|
||||||
|
echo "ex) shop\\\/django_sample"
|
||||||
|
echo -n "Enter the service web root without the path of '/www/' >"
|
||||||
|
read webroot
|
||||||
|
echo "Entered service web root: $webroot"
|
||||||
|
if [[ "$webroot" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the service portnumber >"
|
||||||
|
read portnumber
|
||||||
|
echo "Entered service portnumber: $portnumber"
|
||||||
|
if [[ "$portnumber" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the service domain >"
|
||||||
|
read domain
|
||||||
|
echo "Entered service domain: $domain"
|
||||||
|
if [[ "$domain" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the app name >"
|
||||||
|
read appname
|
||||||
|
echo "Entered app name: $appname"
|
||||||
|
if [[ "$appname" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Enter the serviceport"
|
||||||
|
echo -n "if you push enter with none, there are no port number >"
|
||||||
|
read serviceport
|
||||||
|
echo "Entered proxy port: $serviceport"
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the file name >"
|
||||||
|
read filename
|
||||||
|
echo "Entered file name: $filename"
|
||||||
|
if [[ "$filename" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sed 's/webroot/'$webroot'/g' sample_nginx_https.conf > $filename'1'.temp
|
||||||
|
sed 's/portnumber/'$portnumber'/g' $filename'1'.temp > $filename'2'.temp
|
||||||
|
sed 's/domain/'$domain'/g' $filename'2'.temp > $filename'3'.temp
|
||||||
|
sed 's/appname/'$appname'/g' $filename'3'.temp > $filename'4'.temp
|
||||||
|
if [[ "$serviceport" == "" ]]; then
|
||||||
|
sed 's/:serviceport/''/g' $filename'4'.temp > $filename'5'.temp
|
||||||
|
else
|
||||||
|
sed 's/serviceport/'$serviceport'/g' $filename'4'.temp > $filename'5'.temp
|
||||||
|
fi
|
||||||
|
sed 's/filename/'$filename'/g' $filename'5'.temp > ./conf.d/$filename'_gunicorn_https_ng'.conf
|
||||||
|
|
||||||
|
rm *.temp
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
proxy_set_header Host $http_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 Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_redirect off;
|
||||||
|
# proxy_connect_timeout, proxy_send_timeout, proxy_read_timeout은 nginx.conf에서 설정
|
||||||
|
proxy_buffers 32 4k;
|
||||||
|
proxy_headers_hash_max_size 512;
|
||||||
|
proxy_headers_hash_bucket_size 64;
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
server {
|
||||||
|
listen portnumber;
|
||||||
|
server_name domain www.domain;
|
||||||
|
|
||||||
|
if ($bad_bot) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
access_log /log/nginx/filename.com.gunicorn_access.log main;
|
||||||
|
error_log /log/nginx/filename.com.gunicorn_error.log warn;
|
||||||
|
|
||||||
|
# if ($host !~* ^(domain\.com|www\.domain\.com)$) {
|
||||||
|
# return 444;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Django media
|
||||||
|
location /media {
|
||||||
|
autoindex off;
|
||||||
|
gzip_static on;
|
||||||
|
expires max;
|
||||||
|
#alias /www/django_sample/media;
|
||||||
|
alias /www/webroot/media; # your Django project's media files - amend as required
|
||||||
|
#include /etc/nginx/mime.types;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static {
|
||||||
|
autoindex off;
|
||||||
|
gzip_static on;
|
||||||
|
expires max;
|
||||||
|
#alias /www/django_sample/static;
|
||||||
|
# normally static folder is named as /static
|
||||||
|
alias /www/webroot/static; # your Django project's static files - amend as required
|
||||||
|
#include /etc/nginx/mime.types;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
autoindex off;
|
||||||
|
proxy_pass http://appname:serviceport;
|
||||||
|
# proxy_redirect http:// https://;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Allow Lets Encrypt Domain Validation Program
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/webroot;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block dot file (.htaccess .htpasswd .svn .git .env and so on.)
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block (log file, binary, certificate, shell script, sql dump file) access.
|
||||||
|
location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block access
|
||||||
|
location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /robots.txt {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,232 @@
|
||||||
|
# ===============================================
|
||||||
|
# Production Level Nginx Configuration (Sample Template)
|
||||||
|
# 서버 사양: 쿼드코어 CPU, 4GB RAM, ~50 req/s
|
||||||
|
# 백엔드: FastAPI REST API Server
|
||||||
|
# ===============================================
|
||||||
|
|
||||||
|
# HTTP 서버 블록 (포트 80) - HTTPS로 리다이렉트
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name domain www.domain;
|
||||||
|
|
||||||
|
# 보안을 위한 호스트 검증 - 허용되지 않은 도메인 차단
|
||||||
|
# 도메인 확장자가 다르다면 추가해줘야함
|
||||||
|
if ($host !~* ^(www\.)?domain\.(com|kr|net|org)$) {
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Let's Encrypt 도메인 검증 프로그램 허용 (리다이렉트 전에 처리)
|
||||||
|
# SSL 인증서 갱신을 위해 필수
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/certbot;
|
||||||
|
try_files $uri =404; # 디렉토리 순회 공격 방지
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTP를 HTTPS로 리다이렉트 (acme-challenge 제외)
|
||||||
|
# return 301은 rewrite보다 효율적이며 $server_name이 $host보다 안전함
|
||||||
|
location / {
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS 서버 블록 (포트 443) - 메인 애플리케이션
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name domain.com www.domain.com;
|
||||||
|
|
||||||
|
# 악성 봇 차단 (nginx.conf의 http 블록에서 $bad_bot 맵 정의 필요)
|
||||||
|
if ($bad_bot) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
# SSL/TLS 인증서 설정
|
||||||
|
ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem;
|
||||||
|
ssl_dhparam /etc/ssl/certs/domain/dhparam.pem; # openssl dhparam -out /etc/ssl/certs/domain/dhparam.pem 2048
|
||||||
|
|
||||||
|
# 최신 SSL/TLS 설정 - SSL Labs A+ 등급 달성 가능
|
||||||
|
ssl_session_cache shared:SSL:50m; # SSL 세션 캐시 크기 증가 (트래픽 많을 시 유용)
|
||||||
|
ssl_session_timeout 10m; # SSL 세션 타임아웃
|
||||||
|
ssl_session_tickets off; # 보안 향상을 위해 세션 티켓 비활성화 (nginx >= 1.5.9)
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3; # 최신 TLS 프로토콜만 사용
|
||||||
|
ssl_prefer_server_ciphers off; # TLSv1.3에서는 클라이언트 선호 암호화 사용 (모범 사례)
|
||||||
|
# 최신 암호화 스위트 - CHACHA20-POLY1305 포함 (모바일 최적화)
|
||||||
|
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_ecdh_curve secp384r1; # ECDH 곡선 설정 (nginx >= 1.1.0)
|
||||||
|
|
||||||
|
# OCSP 스테이플링 - SSL 핸드셰이크 성능 향상
|
||||||
|
# 인증서에 OCSP URL이 없으면 자동으로 비활성화됨 (경고는 정상)
|
||||||
|
ssl_stapling on;
|
||||||
|
ssl_stapling_verify on;
|
||||||
|
ssl_trusted_certificate /etc/letsencrypt/live/domain/chain.pem;
|
||||||
|
resolver 1.1.1.1 8.8.8.8 valid=300s; # Cloudflare와 Google DNS 사용
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
|
# 보안 헤더 - 다양한 공격으로부터 보호
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # HSTS - 다운그레이드 공격 방지
|
||||||
|
add_header X-Frame-Options "DENY" always; # 클릭재킹 방지
|
||||||
|
add_header X-Content-Type-Options "nosniff" always; # MIME 스니핑 방지
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always; # 레거시 XSS 보호
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 리퍼러 정보 제어
|
||||||
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' ''; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: ws:;" always;
|
||||||
|
# XSS 방지를 위한 CSP
|
||||||
|
# 'unsafe-inline'은 범용 설정이 아니며, 보안상 위험한 설정입니다. CSP의 핵심 보호 기능을 무력화시키므로, 개발 환경이나 레거시 코드 마이그레이션 과정에서만 임시로 사용하고, 프로덕션 환경에서는 nonce, hash, 또는 외부 파일 분리 방식으로 대체해야 합니다.
|
||||||
|
|
||||||
|
# 클라이언트가 업로드할 수 있는 전체 요청 본문(body) 의 최대 허용 크기
|
||||||
|
# 요청 바디(파일, 폼 데이터 등)가 이 값을 초과하면 Nginx는 즉시 413 Request Entity Too Large 에러를 반환
|
||||||
|
# 업로드 제한선.
|
||||||
|
client_max_body_size 100M; # 최대 업로드 크기 제한 (애플리케이션에 맞게 조정)
|
||||||
|
|
||||||
|
# 파일 캐시 - I/O 성능 향상
|
||||||
|
open_file_cache max=1000 inactive=20s; # 최대 1000개 파일 캐시, 20초 비활성 시 제거
|
||||||
|
open_file_cache_valid 30s; # 캐시 유효성 검사 주기
|
||||||
|
open_file_cache_min_uses 2; # 최소 2회 사용 시 캐시
|
||||||
|
open_file_cache_errors on; # 파일 오류도 캐시
|
||||||
|
|
||||||
|
# 로깅 설정 - 버퍼링으로 I/O 감소
|
||||||
|
access_log /log/nginx/domain.com.gunicorn_access.log main buffer=32k flush=5s;
|
||||||
|
error_log /log/nginx/domain.com.gunicorn_error.log warn;
|
||||||
|
|
||||||
|
# frontend에 오류 페이지 정의가 되어 있는 경우 사용 가능
|
||||||
|
# # 커스텀 오류 페이지 - 더 나은 사용자 경험 및 정보 노출 방지
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
|
||||||
|
# location = /404.html {
|
||||||
|
# internal; # 내부 리다이렉트만 허용
|
||||||
|
# root /www/error_pages;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# location = /50x.html {
|
||||||
|
# internal; # 내부 리다이렉트만 허용
|
||||||
|
# root /www/error_pages;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Fastapi 미디어 파일 - 사용자 업로드 파일
|
||||||
|
location /media {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
# gzip_static on; # 사전 압축된 .gz 파일 사용
|
||||||
|
expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증
|
||||||
|
alias /www/webroot/media; # Fastapi 프로젝트의 미디어 파일 경로
|
||||||
|
|
||||||
|
# 정적 파일 캐싱 - 브라우저 캐시 최적화
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fastapi 정적 파일 - CSS, JS, 이미지 등
|
||||||
|
location /static {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
# gzip_static on; # 사전 압축된 .gz 파일 사용 압축된 파일이 없다면 설정 무의미
|
||||||
|
expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증
|
||||||
|
alias /www/webroot/static; # Fastapi 프로젝트의 정적 파일 경로
|
||||||
|
|
||||||
|
# 정적 파일 캐싱 - 브라우저 캐시 최적화
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# 메인 애플리케이션 - 백엔드로 프록시
|
||||||
|
location / {
|
||||||
|
autoindex off; # 디렉토리 목록 비활성화
|
||||||
|
|
||||||
|
# 속도 제한 - DDoS 및 무차별 대입 공격 방지
|
||||||
|
# (nginx.conf의 http 블록에서 limit_req_zone과 limit_conn_zone 정의 필요)
|
||||||
|
limit_req zone=general burst=20 nodelay; # 초당 요청 제한
|
||||||
|
limit_conn addr 10; # IP당 동시 연결 제한
|
||||||
|
|
||||||
|
# HTTP 메서드 제한 - HTTP 동사 변조 공격 방지
|
||||||
|
limit_except GET POST HEAD OPTIONS {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 백엔드 애플리케이션으로 프록시
|
||||||
|
proxy_pass http://appname:serviceport;
|
||||||
|
|
||||||
|
# WebSocket 지원 - 실시간 통신 애플리케이션에 필수
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade; # nginx.conf에서 $connection_upgrade 맵 정의 필요
|
||||||
|
|
||||||
|
# 프록시 헤더 - 클라이언트 정보 전달
|
||||||
|
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;
|
||||||
|
|
||||||
|
# 타임아웃 설정 - 애플리케이션에 맞게 조정
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
|
||||||
|
# 버퍼 설정 - 대화형 애플리케이션에 최적화 - Websocket 사용시 설정
|
||||||
|
# proxy_buffering off; # 즉시 응답 전달
|
||||||
|
# proxy_request_buffering off; # 즉시 요청 전달
|
||||||
|
|
||||||
|
# 버퍼링 활성화 (기본값) - 기본 fastapi 사용시 설정
|
||||||
|
proxy_buffering on;
|
||||||
|
proxy_request_buffering on;
|
||||||
|
|
||||||
|
# 버퍼 크기 설정 - 기본 fastapi 사용시 설정
|
||||||
|
proxy_buffer_size 4k;
|
||||||
|
proxy_buffers 8 4k;
|
||||||
|
proxy_busy_buffers_size 8k;
|
||||||
|
|
||||||
|
proxy_set_header Accept-Encoding gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Let's Encrypt 도메인 검증 프로그램 허용 (HTTPS에서도 필요시)
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
root /www/certbot;
|
||||||
|
try_files $uri =404; # 디렉토리 순회 공격 방지
|
||||||
|
}
|
||||||
|
|
||||||
|
# 정적 리소스 캐싱 - 이미지, 폰트, CSS, JS 등
|
||||||
|
# 브라우저 캐시로 로드 시간 단축 및 서버 부하 감소
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
|
||||||
|
expires 1y; # 1년 캐시
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off; # 액세스 로그 비활성화로 성능 향상
|
||||||
|
}
|
||||||
|
|
||||||
|
# 닷 파일 차단 - .htaccess, .htpasswd, .svn, .git, .env 등
|
||||||
|
# 민감한 설정 파일 노출 방지
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 민감한 파일 확장자 차단 - 로그, 인증서, 스크립트, SQL 등
|
||||||
|
# 보안을 위해 직접 접근 차단
|
||||||
|
location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 민감한 설정 파일 차단 - composer, package.json, phpunit 등
|
||||||
|
# 프로젝트 메타데이터 및 설정 파일 노출 방지
|
||||||
|
location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ {
|
||||||
|
deny all;
|
||||||
|
access_log off; # 차단된 시도 로그 비활성화
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 파비콘 - 로그 노이즈 제거
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# robots.txt - 검색 엔진 크롤러 제어
|
||||||
|
location = /robots.txt {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
|
ENV TZ=Asia/Seoul
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 1. Base packages & timezone setup
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends apt-utils && \
|
||||||
|
apt-get install -yq tzdata && \
|
||||||
|
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
|
||||||
|
apt-get install -y \
|
||||||
|
curl wget git tar gnupg2 lsb-release lz4 zstd vim \
|
||||||
|
build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
|
||||||
|
libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev \
|
||||||
|
python3-dev libmysqlclient-dev pkg-config ca-certificates
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 2. Python 3.13 build & install
|
||||||
|
# ========================================
|
||||||
|
RUN cd /usr/src && \
|
||||||
|
wget https://www.python.org/ftp/python/3.13.11/Python-3.13.11.tar.xz && \
|
||||||
|
tar -xf Python-3.13.11.tar.xz && \
|
||||||
|
cd Python-3.13.11 && \
|
||||||
|
./configure --enable-optimizations && \
|
||||||
|
make altinstall && \
|
||||||
|
rm -rf /usr/src/Python-3.13.11 /usr/src/Python-3.13.11.tar.xz
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 3. Python symlinks
|
||||||
|
# ========================================
|
||||||
|
RUN rm -f /usr/bin/python /usr/bin/python3 && \
|
||||||
|
ln -s /usr/local/bin/python3.13 /usr/bin/python && \
|
||||||
|
ln -s /usr/local/bin/python3.13 /usr/bin/python3 && \
|
||||||
|
ln -s /usr/local/bin/python3.13 /usr/local/bin/python && \
|
||||||
|
ln -s /usr/local/bin/python3.13 /usr/local/bin/python3 && \
|
||||||
|
ln -s /usr/local/bin/pip3.13 /usr/bin/pip && \
|
||||||
|
ln -s /usr/local/bin/pip3.13 /usr/bin/pip3 && \
|
||||||
|
ln -s /usr/local/bin/pip3.13 /usr/local/bin/pip && \
|
||||||
|
ln -s /usr/local/bin/pip3.13 /usr/local/bin/pip3
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 4. Python packages
|
||||||
|
# ========================================
|
||||||
|
RUN pip install --upgrade pip && \
|
||||||
|
pip install wheel && \
|
||||||
|
pip install sqlalchemy alembic pydantic && \
|
||||||
|
pip install psycopg2-binary asyncpg && \
|
||||||
|
pip install mysqlclient asyncmy && \
|
||||||
|
pip install gunicorn uvicorn[standard] && \
|
||||||
|
pip install fastapi uv poetry
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 5. Percona XtraBackup (mysql backup)
|
||||||
|
# ========================================
|
||||||
|
RUN curl -O https://repo.percona.com/apt/percona-release_latest.generic_all.deb && \
|
||||||
|
apt-get install -y ./percona-release_latest.generic_all.deb && \
|
||||||
|
rm -f percona-release_latest.generic_all.deb && \
|
||||||
|
apt-get update && \
|
||||||
|
percona-release enable pxb-84-lts && \
|
||||||
|
apt-get install -y percona-xtrabackup-84
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 6. PostgreSQL backup (pgbackrest)
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get install -y pgbackrest
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 7. Cleanup
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||||
|
update-ca-certificates
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
FROM nginx:1.26-bookworm
|
||||||
|
|
||||||
|
ENV TZ=Asia/Seoul
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 1. Base packages & timezone setup
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends apt-utils && \
|
||||||
|
apt-get install -yq tzdata && \
|
||||||
|
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 2. Required packages
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get install -y sendmail wget gnupg ca-certificates
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 3. Cron & Certbot (SSL auto-renewal)
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get install -y cron certbot python3-certbot-nginx
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 4. CA certificates
|
||||||
|
# ========================================
|
||||||
|
RUN update-ca-certificates && \
|
||||||
|
chmod 644 /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 5. Cleanup
|
||||||
|
# ========================================
|
||||||
|
RUN apt-get autoremove -y && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 6. Certbot auto-renewal cron job
|
||||||
|
# ========================================
|
||||||
|
RUN crontab -l 2>/dev/null | { cat; echo "0 5 * * 1 certbot renew --quiet --deploy-hook \"nginx -t && service nginx reload\" >> /log/nginx/crontab_\$(date +\%Y\%m\%d).log 2>&1"; } | crontab -
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 7. Add cron to nginx entrypoint
|
||||||
|
# ========================================
|
||||||
|
RUN sed -i'' -r -e "/set/i\cron" /docker-entrypoint.sh || true
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "0 6 * * 1 root docker restart nginx-gunicorn-webserver" >> /etc/crontab
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
my_array=()
|
||||||
|
delimiter="-d"
|
||||||
|
domain_string=""
|
||||||
|
|
||||||
|
apt-get update && apt-get install -y sendmail wget vim cron certbot python3-certbot-nginx ca-certificates
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the service webroot_folder >"
|
||||||
|
read webroot_folder
|
||||||
|
echo "Entered service webroot_folder: $webroot_folder"
|
||||||
|
if [[ "$webroot_folder" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "To add a subdomain, type something like 'aaa.com www.aaa.com sub.aaa.com', but all domains refer to the same web root"
|
||||||
|
echo -n "A domain in aaa.com format must be entered first."
|
||||||
|
echo -n "Enter the service domain >"
|
||||||
|
read domain
|
||||||
|
echo "Entered service domain: $domain"
|
||||||
|
if [[ "$domain" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
IFS=' ' read -ra my_array <<< "$domain"
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
echo -n "Enter the user e-mail >"
|
||||||
|
read mail
|
||||||
|
echo "Entered user e-mail: $mail"
|
||||||
|
if [[ "$mail" != "" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for element in "${my_array[@]}"; do
|
||||||
|
domain_string+=" $delimiter $element"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove leading space
|
||||||
|
# domain_string="${domain_string# }"
|
||||||
|
|
||||||
|
# for element in "${my_array[@]}"; do
|
||||||
|
if ! test -f /ssl/${my_array[0]}/dhparam.pem ; then
|
||||||
|
if ! test -f /etc/ssl/certs/${my_array[0]}/dhparam.pem ; then
|
||||||
|
echo "try to create ssl key using openssl "
|
||||||
|
if ! test -d /etc/ssl/certs/${my_array[0]}/ ; then
|
||||||
|
echo "create "${my_array[0]}" folder: /etc/ssl/certs/"${my_array[0]}"/"
|
||||||
|
mkdir -p /etc/ssl/certs/${my_array[0]}/
|
||||||
|
fi
|
||||||
|
openssl dhparam -out /etc/ssl/certs/${my_array[0]}/dhparam.pem 4096
|
||||||
|
if ! test -d /ssl/${my_array[0]}/ ; then
|
||||||
|
echo "create "${my_array[0]}" folder: /ssl/"${my_array[0]}"/"
|
||||||
|
mkdir -p /ssl/${my_array[0]}/
|
||||||
|
fi
|
||||||
|
cp /etc/ssl/certs/${my_array[0]}/dhparam.pem /ssl/${my_array[0]}/ -r
|
||||||
|
# else
|
||||||
|
# echo "copy ssl folder by already maden"
|
||||||
|
# cp /ssl/certs/$domain/dhparam.pem /etc/ssl/certs/dhparam.pem -r
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! test -d /etc/ssl/certs/${my_array[0]}/ ; then
|
||||||
|
echo "create "${my_array[0]}" folder: /etc/ssl/certs/"${my_array[0]}"/"
|
||||||
|
mkdir -p /etc/ssl/certs/${my_array[0]}/
|
||||||
|
fi
|
||||||
|
cp /ssl/${my_array[0]}/dhparam.pem /etc/ssl/certs/${my_array[0]}/ -r
|
||||||
|
fi
|
||||||
|
# done
|
||||||
|
|
||||||
|
#if ! test -d /etc/letsencrypt/live/test.com ;
|
||||||
|
if ! test -d /etc/letsencrypt/${my_array[0]}/letsencrypt ; then
|
||||||
|
echo "try to create authentication key using certbot "
|
||||||
|
certbot certonly --non-interactive --agree-tos --email $mail --webroot -w /www/$webroot_folder$domain_string
|
||||||
|
echo "certbot certonly --non-interactive --agree-tos --email "$mail" --webroot -w /www/"$webroot_folder$domain_string
|
||||||
|
# if ! test -d /ssl/letsencrypt/$domain/ ; then
|
||||||
|
# echo "create domain folder: /ssl/letsencrypt/"$domain"/"
|
||||||
|
# mkdir -p /ssl/letsencrypt/$domain/
|
||||||
|
# fi
|
||||||
|
#cp /etc/letsencrypt/ /ssl/letsencrypt/$domain/ -r
|
||||||
|
# else
|
||||||
|
# echo "copy letsencrypt folder by already maden"
|
||||||
|
# cp /ssl/letsencrypt/$domain/ /etc/letsencrypt/ -r
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <(crontab -l) <(echo '0 5 * * 1 certbot renew --quiet --deploy-hook "service nginx restart" > /log/nginx/crontab_renew.log 2>&1') | crontab -
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Nginx 로그 로테이션 설정
|
||||||
|
# - Docker 컨테이너 환경에서 무중단 운영을 위해 copytruncate 방식 사용
|
||||||
|
# - copytruncate: 로그 파일을 복사 후 원본을 비우는 방식 (서비스 재시작 불필요)
|
||||||
|
# - 로테이션 순간 극소량의 로그가 누락될 수 있으나 서비스는 중단되지 않음
|
||||||
|
/log/nginx/*.log {
|
||||||
|
daily
|
||||||
|
size 100M
|
||||||
|
rotate 30
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
create 0640 nginx nginx
|
||||||
|
sharedscripts
|
||||||
|
postrotate
|
||||||
|
# Nginx에 USR1 signal 전송
|
||||||
|
if [ -f /var/run/nginx.pid ]; then
|
||||||
|
kill -USR1 `cat /var/run/nginx.pid`
|
||||||
|
fi
|
||||||
|
endscript
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Uvicorn Celery Worker 로그 로테이션 설정
|
||||||
|
# - Docker 컨테이너 환경에서 무중단 운영을 위해 copytruncate 방식 사용
|
||||||
|
# - copytruncate: 로그 파일을 복사 후 원본을 비우는 방식 (서비스 재시작 불필요)
|
||||||
|
# - 로테이션 순간 극소량의 로그가 누락될 수 있으나 서비스는 중단되지 않음
|
||||||
|
/log/uvicorn/celery/*.log {
|
||||||
|
daily
|
||||||
|
size 100M
|
||||||
|
rotate 30
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
copytruncate
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Uvicorn Celery Beat 로그 로테이션 설정
|
||||||
|
# - Docker 컨테이너 환경에서 무중단 운영을 위해 copytruncate 방식 사용
|
||||||
|
# - copytruncate: 로그 파일을 복사 후 원본을 비우는 방식 (서비스 재시작 불필요)
|
||||||
|
# - 로테이션 순간 극소량의 로그가 누락될 수 있으나 서비스는 중단되지 않음
|
||||||
|
/log/uvicorn/celerybeat/*.log {
|
||||||
|
daily
|
||||||
|
rotate 30
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
copytruncate
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Uvicorn 로그 로테이션 설정
|
||||||
|
# - Docker 컨테이너 환경에서 무중단 운영을 위해 copytruncate 방식 사용
|
||||||
|
# - copytruncate: 로그 파일을 복사 후 원본을 비우는 방식 (서비스 재시작 불필요)
|
||||||
|
# - 로테이션 순간 극소량의 로그가 누락될 수 있으나 서비스는 중단되지 않음
|
||||||
|
/log/uvicorn/*.log {
|
||||||
|
daily
|
||||||
|
size 100M
|
||||||
|
rotate 30
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
copytruncate
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue