모든 프레임워크(6종)에서 공통으로 참조하는 운영·커스터마이징 매뉴얼입니다. nginx · systemd · PM2 · DB 백업 · SSL · 보안 · 성능까지.
💡 요약 정리
- nginx 설정 변경 시 반드시
nginx -t 검증 후 reload해야 합니다
- systemd 서비스는 unit 파일 직접 수정 대신
override.conf를 사용합니다
- 환경변수 변경 후 서비스 restart가 필수입니다
- 백업 책임은 고객님에게 있습니다 — 외부 스토리지 동기화를 권장합니다
- 방화벽은 반드시 카페24 방화벽관리 메뉴를 사용하세요
1. nginx 변경 표준 절차
1-1. 안전 시퀀스 5단계
nginx -t 실패 시 절대 reload 금지. 사이트 전체 다운이 발생합니다.
| STEP | 작업 | 명령 |
|---|
| 1 | 백업 | sudo cp -p /etc/nginx/sites-available/$PROJECT_NAME /etc/nginx/sites-available/$PROJECT_NAME.bak.$(date +%s) |
| 2 | 편집 | sudo nano /etc/nginx/sites-available/$PROJECT_NAME |
| 3 | 검증 (필수) | sudo nginx -t |
| 4 | 통과 시에만 reload | sudo systemctl reload nginx |
| 5 | 외부 검증 | curl -sI [도메인]/ |
1-2. reload vs restart
| 명령 | 동작 | 다운타임 |
|---|
systemctl reload nginx | 설정만 graceful 교체 | 무중단 (권장) |
systemctl restart nginx | 프로세스 재기동 | 0.5~2초 다운 |
1-3. 롤백
| 단계 | 명령 |
|---|
| 1. 백업 복원 | sudo cp /etc/nginx/sites-available/$PROJECT_NAME.bak.<timestamp> /etc/nginx/sites-available/$PROJECT_NAME |
| 2. 검증·반영 | sudo nginx -t && sudo systemctl reload nginx |
2. nginx 커스텀 레시피 12개
2-1. 업로드 파일 크기 늘리기
| 항목 | 값 |
|---|
| 지시어 | client_max_body_size 100M; |
2-2. gzip 압축 활성화
| 지시어 | 값 |
|---|
gzip | on; |
gzip_vary | on; |
gzip_min_length | 1024; |
gzip_types | text/plain text/css text/xml application/javascript application/json image/svg+xml; |
2-3. Basic Auth 추가
| 항목 | 명령 |
|---|
| htpasswd 생성 | sudo apt install apache2-utils && sudo htpasswd -c /etc/nginx/.htpasswd admin |
이후 location /admin/ 블록에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
auth_basic | "Restricted"; |
auth_basic_user_file | /etc/nginx/.htpasswd; |
proxy_pass | 127.0.0.1:8000; |
2-4. IP 화이트리스트
location /admin/ 블록에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
allow | 1.2.3.4; (허용 IP) |
deny | all; |
proxy_pass | 127.0.0.1:8000; |
2-5. WebSocket 경로
location /ws/ 블록에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
proxy_pass | 127.0.0.1:3000; |
proxy_http_version | 1.1; |
proxy_set_header Upgrade | $http_upgrade; |
proxy_set_header Connection | "upgrade"; |
proxy_read_timeout | 86400; |
2-6. 외부 정적 폴더 nginx 직접 서빙
location /assets/ 블록에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
alias | /opt/[프로젝트]/assets/; |
expires | 30d; |
add_header Cache-Control | "public, immutable"; |
2-7. HTTP → HTTPS 리다이렉트
새 server 블록(80 포트용)에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
listen | 80; |
server_name | example.com; |
return | 301 $host$request_uri; |
2-8. CORS 헤더 추가
location /api/ 블록에 다음 지시어를 추가하시면 됩니다.
| 지시어 | 값 |
|---|
add_header Access-Control-Allow-Origin | "app.example.com" always; |
add_header Access-Control-Allow-Methods | "GET, POST, PUT, DELETE, OPTIONS" always; |
| OPTIONS 분기 | if ($request_method = OPTIONS) { return 204; } |
proxy_pass | 127.0.0.1:8000; |
2-9. Rate Limit 변경
| 위치 | 설정 |
|---|
http 블록에 zone 정의 | limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; |
location /api/에 적용 | limit_req zone=api burst=100 nodelay; + proxy_pass 127.0.0.1:8000; |
2-10. 도메인 추가 (멀티)
| 항목 | 값 |
|---|
| 지시어 | server_name example.com www.example.com api.example.com; |
다중 도메인의 SSL은 카페24 SSL 인증서를 도메인별로 별도 구매·설치해 주세요.
2-11. 별도 vhost (다른 사이트)
| 단계 | 명령 |
|---|
| 1. 복사 | sudo cp /etc/nginx/sites-available/$PROJECT_NAME /etc/nginx/sites-available/another-site |
| 2. 편집 | sudo nano /etc/nginx/sites-available/another-site |
| 3. 활성화 | sudo ln -s /etc/nginx/sites-available/another-site /etc/nginx/sites-enabled/ |
| 4. 검증·반영 | sudo nginx -t && sudo systemctl reload nginx |
2-12. 보안 헤더 강화
| 헤더 | 값 |
|---|
X-Frame-Options | "SAMEORIGIN" always; |
X-Content-Type-Options | "nosniff" always; |
Referrer-Policy | "strict-origin-when-cross-origin" always; |
Strict-Transport-Security | "max-age=63072000; includeSubDomains; preload" always; |
3. systemd 서비스 변경 (Python · Java (systemd))
unit 파일 직접 수정 금지 → override.conf 사용
| 작업 | 명령 |
|---|
| 오버라이드 편집 | sudo systemctl edit [프로젝트] |
| 적용 | sudo systemctl daemon-reload && sudo systemctl restart [프로젝트] |
| 확인 | systemctl cat [프로젝트] |
자주 쓰는 override 예시
[Service] 섹션 안에 다음 키를 사용하시면 됩니다 (Django gunicorn 워커 변경 + JVM 옵션 예시).
| 키 | 값 |
|---|
| ExecStart= (기존 무효화) | (빈 값으로 원본 비움) |
| ExecStart= (덮어쓰기) | /opt/[프로젝트]/.venv/bin/gunicorn --bind 127.0.0.1:8000 --workers 4 [프로젝트].wsgi:application |
Environment | "JAVA_OPTS=-Xms512m -Xmx1g" |
4. 환경변수 변경
| 작업 | 명령 |
|---|
| 편집 | sudo nano /etc/[프로젝트]/env |
| 적용 (Python · Java (systemd)) | sudo systemctl restart [프로젝트] |
| 적용 (Node.js (PM2)) | sudo -u appuser pm2 restart [프로젝트] --update-env |
| 권한 확인 | ls -l /etc/[프로젝트]/env (0640 root:appuser) |
5. 포트 변경 / 추가 포트
방화벽은 카페24 [방화벽관리] 메뉴 사용. 서버 내부 iptables/ufw 직접 변경은 카페24 방화벽과 충돌하여 SSH 끊김이 발생할 수 있습니다.
- 외부 노출 새 포트는 카페24 방화벽관리에서 인바운드 허용 + nginx에 추가 vhost
- 서버 내부 라우팅 단계 IP 제한은 nginx
allow/deny로 처리하시면 됩니다 (위 §2-4)
6. DB 운영
6-1. PostgreSQL 17
추가 사용자/DB 생성
sudo -u postgres psql 접속 후 다음 SQL을 순차 실행하시면 됩니다.
| SQL |
|---|
CREATE DATABASE myapp_extra; |
CREATE USER myapp_extra_user WITH ENCRYPTED PASSWORD 'StrongPass!'; |
GRANT ALL PRIVILEGES ON DATABASE myapp_extra TO myapp_extra_user; |
비밀번호 변경
| 항목 | 명령 |
|---|
| SQL | ALTER USER [DB사용자] WITH PASSWORD 'NewStrongPass!'; |
이후 /etc/[프로젝트]/env의 DB_PASSWORD 동기화 + 서비스 restart 필수.
백업 / 복원
| 용도 | 명령 |
|---|
| 단일 DB 백 업 | sudo -u postgres pg_dump [DB명] | gzip > /var/backups/[DB명]_$(date +%Y%m%d).sql.gz |
| 전체 백업 | sudo -u postgres pg_dumpall | gzip > /var/backups/all_$(date +%Y%m%d).sql.gz |
| 복원 | gunzip < /var/backups/[DB명]_20260430.sql.gz | sudo -u postgres psql [DB명] |
6-2. MariaDB 11.4
추가 사용자/DB
sudo mariadb 접속 후 다음 SQL을 순차 실행하시면 됩니다.
| SQL |
|---|
CREATE DATABASE myapp_extra DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; |
CREATE USER 'myapp_extra_user'@'127.0.0.1' IDENTIFIED BY 'StrongPass!'; |
GRANT ALL PRIVILEGES ON myapp_extra.* TO 'myapp_extra_user'@'127.0.0.1'; |
FLUSH PRIVILEGES; |
백업 / 복원
| 용도 | 명령 |
|---|
| 단일 DB | sudo mariadb-dump [DB명] | gzip > /var/backups/[DB명]_$(date +%Y%m%d).sql.gz |
| 복원 | gunzip < /var/backups/[DB명]_20260430.sql.gz | sudo mariadb [DB명] |
백업 책임은 고객님에게 있습니다. 만료 후 7일 경과 시 데이터 삭제 가능. 외 부 스토리지(S3 등)로 추가 동기화를 강력히 권장드립니다.
6-3. 자동 일일 백업 (cron)
sudo crontab -e에 다음과 같은 라인 추가하시면 됩니다.
| 용도 | cron 라인 |
|---|
| 매일 03:00 백업 (PG) | 0 3 * * * sudo -u postgres pg_dump [DB명] | gzip > /var/backups/[DB명]_$(date +\%Y\%m\%d).sql.gz |
| 매일 03:00 백업 (Maria) | 0 3 * * * mariadb-dump [DB명] | gzip > /var/backups/[DB명]_$(date +\%Y\%m\%d).sql.gz |
| 30일 보존 | 0 4 * * * find /var/backups/ -name "*.sql.gz" -mtime +30 -delete |
7. 로그 관리
위치 매트릭스
| 로그 종류 | 위치 |
|---|
| 앱 (Python · Java (systemd)) | journalctl -u [프로젝트] |
| 앱 (Node.js (PM2)) | /var/log/[프로젝트]/{out,error}.log + pm2 logs |
| nginx access | /var/log/nginx/[프로젝트]_access.log |
| nginx error | /var/log/nginx/[프로젝트]_error.log |
| DB (PG) | /var/log/postgresql/postgresql-17-main.log |
| DB (Maria) | /var/log/mysql/error.log |
| fail2ban | /var/log/fail2ban.log |
| SSH | /var/log/auth.log |
logrotate (PM2)
| 항목 | 명령 |
|---|
| 설치 | sudo -u appuser pm2 install pm2-logrotate |
| 최대 크기 | sudo -u appuser pm2 set pm2-logrotate:max_size 50M |
| 보존 | sudo -u appuser pm2 set pm2-logrotate:retain 30 |
8. 디스크 / 메모리 / 스왑
| 항목 | 명령 |
|---|
| 디스크 | df -h |
| 메모리 | free -h |
| 용량 점유 확인 | sudo du -sh /opt/[프로젝트] /var/log /var/backups |
스왑 추가 (DEV A 빌드 OOM 방지)
| STEP | 명령 |
|---|
| 1. 파일 할당 | sudo fallocate -l 2G /swapfile |
| 2. 권한 | sudo chmod 600 /swapfile |
| 3. 스왑 포맷 | sudo mkswap /swapfile |
| 4. 활성화 | sudo swapon /swapfile |
영구 적용은 echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab으로 fstab에 추가해 주세요. 영구적으로 메모리가 부족하시면 DEV B 이상 요금제 변경이 근본 해결입니다.
9. 인증서 / 도메인
| 유형 | 처리 |
|---|
| 무료 도메인 (자동) | 아이디.mycafe24.com SSL 자동 발급·자동 갱신 — 별도 작업 불필요 |
| 보유 도메인 | SSL 별도 구매 필요. 카페24 SSL 인증서 구매 후 나의 서비스 관리에서 설치 |
10. 성능 튜닝
| 대상 | 조정 위치 | 예시 |
|---|
| nginx worker | /etc/nginx/nginx.conf | worker_processes auto; · worker_connections 4096; |
| gunicorn (Django) | systemd override | --workers 4 --threads 2 --timeout 60 |
| uvicorn (FastAPI) | systemd override | --workers 4 |
| PM2 cluster | ecosystem.config.js | instances: 'max', exec_mode: 'cluster' |
| JVM (Spring Boot) | /etc/[프로젝트]/env | JAVA_OPTS=-Xms512m -Xmx1536m -XX:+UseG1GC |
JVM 메모리 — 요금제별 권장
| 요금제 | Xmx 권장 |
|---|
| DEV A | 1g (빌드는 swap 또는 로컬) |
| DEV B | 2g |
| DEV C | 4g |
| DEV D | 8g |
11. 모니터링
| 도구 | 명령 |
|---|
| top | top (q로 종료) |
| htop | sudo apt install htop |
| PM2 모니터링 | sudo -u appuser pm2 monit |
12. 보안 강화
12-1. SSH 키 로그인 강제
| STEP | 작업 |
|---|
| 1 | 로컬 SSH 키 등록 — ssh-copy-id root@아이디.mycafe24.com |
| 2 | /etc/ssh/sshd_config 편집 — PasswordAuthentication no |
| 3 | 검증 — sudo sshd -t |
| 4 | 적용 — sudo systemctl reload ssh |
| 5 | 새 세션 재접속 확인 후 기존 세션 종료 |
12-2. fail2ban 정책 강화
/etc/fail2ban/jail.local의 [sshd] 섹션에 다음 키를 사용하시면 됩니다.
| 키 | 값 |
|---|
enabled | true |
port | ssh |
maxretry | 3 |
findtime | 600 |
bantime | 7200 |
| 작업 | 명령 |
|---|
| 적용 | sudo systemctl restart fail2ban |
| 상태 확인 | sudo fail2ban-client status sshd |
| 차단 IP 해제 | sudo fail2ban-client set sshd unbanip 1.2.3.4 |
13. 재부팅 / 자동 재시작
| 그룹 | 확인 |
|---|
| Python · Java (systemd) (systemd) | sudo systemctl is-enabled [프로젝트] (enabled여야 정상) |
| Node.js (PM2) (PM2) | sudo -u appuser pm2 save 후 sudo systemctl is-enabled pm2-appuser |
pm2 save를 안 하면 새로 추가한 앱은 재부팅 후 사라집니다.
14. 함정 / FAQ
| 카테고리 | 함정 | 해결 |
|---|
| 일반 | env 수정 후 변경 미반영 | 반드시 systemd restart 또는 PM2 restart --update-env |
| nginx | nginx -t 통과했는데 502 | 앱이 실제로 listen 중인지 ss -tlnp | grep <PORT> |
| nginx | 새 도메인 추가했는데 인증서 없음 | 카페24 SSL 인증서 별도 구매·설치 |
| systemd | unit 직접 수정 후 변경 미반영 | daemon-reload 누락. systemctl edit 사용 권장 |
| PM2 | pm2 list에 앱 안 보임 (root에서) | 반드시 sudo -u appuser pm2 ... |
| PM2 | 재부팅 후 앱 사라짐 | pm2 save 누락 |
| DB | Connection refused | 서비스 미기동 (systemctl status) |
| 인증서 | 무료 도메인 HTTPS 안 됨 | 자동. 결제 후 약 10분 안에 자동 적용 |
| 인증서 | 보유 도메인 HTTPS 안 됨 | SSL 별도 구매 후 설치 |
가장 위험한 시나리오 — SSH 끊김
한 번 끊긴 SSH를 사용자가 직접 복구할 수단은 사실상 없습니다.
예방 필수 3원칙
-
별도 SSH 세션을 하나 더 열어둔 채 작업
- 변경 전
cp -p로 백업
- 적용 후 새 세션 재접속 확인 → 그 다음 기존 세션 종료
끊겼을 때
- 카페24 [방화벽관리]에서 22번 포트 허용 IP 확인
- 안 되면 [서버호스팅 관리 → 서버 재시작]
- 안 되면 → 고객센터 문의 / 재설치 (데이터 손실 위험, 백업 가능 여부부터 확인)
변경 작업 전 안전 체크리스트 (8개)
| 항목 | 내용 |
|---|
| ☐ 1 | 변경 파일 백업 (cp -a $FILE $FILE.bak.$(date +%s)) |
| ☐ 2 | 검증 명령 알고 있는가 (nginx -t, sshd -t, systemctl status) |
| ☐ 3 | 롤백 절차 알고 있는가 |
| ☐ 4 | reload vs restart 어느 쪽 필요한지 판단 (reload=무중단, restart=0.5~2초 다운) |
| ☐ 5 | 변경 후 영향 받을 다른 서비스 (env 변경 시 systemctl restart vs pm2 restart --update-env) |
| ☐ 6 | 외부 동작 검증 방법 준 비 (curl -sI [도메인]/) |
| ☐ 7 | 작업 시간대 적절 (피크 회피) |
| ☐ 8 | SSH 끊김 대비 (별도 세션 + 백업 + 재접속 확인) |