이거 빠뜨리면 나중에 고생한다. 서버 배포 체크리스트 8가지를 처음 배포할 때 가장 많이 놓치는 순서로 정리했다. 코드만 올리면 된다고 생각하기 쉽다. 실제로는 설정 하나 빠진 게 새벽 2시에 터진다.

1. 환경 변수 분리했는가
빠뜨리면: 로컬 localhost DB에 연결하거나 개발용 API 키로 운영 환경이 돌아간다.
.env 파일은 git에 올리지 않는다. 서버에는 운영용 값을 직접 설정한다.
# 서버에서 환경 변수 설정 확인
printenv | grep -E "DB_HOST|DB_PASSWORD|JWT_SECRET|API_KEY"
# .env 파일로 관리한다면
cat /app/.env
반드시 바꿔야 할 값:
DB_HOST:localhost→ RDS 엔드포인트 또는 내부 IPDB_PASSWORD: 운영 DB 비밀번호로 교체JWT_SECRET: 로컬 개발용 값 그대로 쓰면 보안 취약NODE_ENV:development→production
2. 포트와 방화벽 열려 있는가
빠뜨리면: 서버는 살아 있는데 브라우저에서 접속이 안 된다.
AWS라면 보안 그룹, GCP라면 방화벽 규칙에서 아래 포트를 열어야 한다.
# 열려 있는 포트 확인 (Linux)
ss -tlnp
# ufw 방화벽 사용 시
sudo ufw status
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 22
최소 개방 포트: 80 (HTTP), 443 (HTTPS), 22 (SSH).
Node.js 앱이 3000번 포트에서 뜬다면 직접 3000을 열 필요는 없다. Nginx가 80/443을 받아서 내부 3000으로 프록시하는 방식을 쓰는 게 낫다.
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
설정 후 Nginx 재시작: sudo systemctl restart nginx
3. 프로세스 매니저 설정했는가
빠뜨리면: 터미널을 닫으면 서버도 꺼진다. 서버가 크래시해도 자동으로 안 살아난다.
node app.js로 직접 실행하면 안 된다. PM2를 쓰자.
# PM2 설치
npm install -g pm2
# 앱 시작
pm2 start app.js --name myapp
# 서버 재부팅 시 자동 시작
pm2 startup
pm2 save
Docker를 쓴다면 restart: always 옵션을 확인한다.
# docker-compose.yml
services:
app:
image: myapp
restart: always
ports:
- "3000:3000"
4. HTTPS 적용했는가
빠뜨리면: 브라우저가 “안전하지 않은 연결” 경고를 표시한다. 로그인, 쿠키, API 통신이 평문으로 전송된다.
Let’s Encrypt로 무료 SSL 인증서를 발급한다.
# Certbot 설치 (Ubuntu/Debian)
sudo apt install certbot python3-certbot-nginx
# 인증서 발급 + Nginx 자동 설정
sudo certbot --nginx -d example.com -d www.example.com
# 자동 갱신 확인 (90일마다 갱신 필요)
sudo certbot renew --dry-run
자동 갱신 크론잡 등록:
# crontab -e 에 추가
0 12 * * * certbot renew --quiet
5. 로그 수집 경로 잡혀 있는가
빠뜨리면: 배포 후 문제가 생겨도 원인을 찾을 방법이 없다.
기본 로그 위치를 파악해둔다.
# PM2 로그
pm2 logs myapp
# Nginx 로그
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
# systemd 서비스 로그
journalctl -u myapp --since "1 hour ago"
로그 파일이 무한히 커지지 않도록 로테이션을 설정한다. PM2는 pm2-logrotate 모듈로 처리한다.
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
6. DB 마이그레이션 실행했는가
빠뜨리면: 로컬에서 잘 돌아가던 코드가 운영 DB에서 테이블을 못 찾아서 500 에러를 뱉는다.
배포 후 반드시 마이그레이션을 실행한다.
# Prisma
npx prisma migrate deploy
# Sequelize
npx sequelize-cli db:migrate
# Django
python manage.py migrate
마이그레이션을 배포 스크립트에 넣어두면 매번 기억하지 않아도 된다.
#!/bin/bash
# deploy.sh
git pull origin main
npm install --production
npx prisma migrate deploy
pm2 restart myapp
7. 도메인 DNS 연결했는가
빠뜨리면: 서버 IP로는 접속이 되는데 도메인으로는 안 된다.
DNS 변경은 전파에 최대 48시간이 걸린다. 배포 당일에 설정하면 늦다. 도메인 DNS는 배포 전날 미리 설정해야 한다.
| 레코드 타입 | 이름 | 값 |
|---|---|---|
| A | @ | 서버 공인 IP |
| A | www | 서버 공인 IP |
| CNAME | www | @ (루트 도메인 가리킴) |
DNS 전파 확인:
# 전파 상태 확인
dig example.com +short
nslookup example.com 8.8.8.8
8. 배포 후 헬스체크 했는가
빠뜨리면: 실제로 살아 있는지 모른 채 배포가 끝났다고 착각한다.
배포 직후 반드시 응답을 확인한다. 가장 빠른 방법은 curl이다.
# HTTP 응답 코드 확인
curl -I https://example.com
# 헬스체크 엔드포인트가 있다면
curl https://example.com/health
# 예상 응답
# HTTP/2 200
앱에 /health 엔드포인트를 만들어두면 모니터링 도구 연결이 쉬워진다.
// Express 예시
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
처음 서버 배포 자주 묻는 질문
8가지 중 반드시 먼저 해야 하는 순서가 있나?
DNS 설정은 전파 시간 때문에 제일 먼저 해야 한다. 나머지는 배포 직전에 순서 무관하게 확인해도 된다. 단, DB 마이그레이션은 앱 시작 직전에 실행해야 순서 오류가 없다.
GitHub Actions 같은 CI/CD 없이 배포할 때 이 체크리스트로 충분한가?
처음 배포라면 충분하다. 매번 수동으로 체크하는 게 번거롭다면 deploy.sh 스크립트에 마이그레이션, PM2 재시작, 헬스체크를 묶어두는 것부터 시작하자.
배포 직후 서버가 바로 죽으면 어떻게 진단하나?
pm2 logs --lines 50 또는 journalctl -u myapp --since "5 minutes ago" 로 즉시 로그를 확인한다. 가장 많은 원인은 환경 변수 누락, DB 연결 실패, 포트 충돌이다.
한눈에 보는 서버 배포 체크리스트
| 항목 | 확인 포인트 | 빠뜨리면 |
|---|---|---|
| 환경 변수 | 운영용 DB, API 키, 시크릿 값 | 로컬 DB에 연결, 보안 취약 |
| 포트/방화벽 | 80, 443, 22 포트 개방 | 접속 자체가 안 됨 |
| 프로세스 매니저 | PM2 또는 Docker restart: always | 터미널 종료 시 서버 꺼짐 |
| HTTPS | SSL 인증서 발급 및 자동 갱신 | 브라우저 보안 경고 |
| 로그 | 로그 경로 확인, 로테이션 설정 | 장애 원인 파악 불가 |
| DB 마이그레이션 | 운영 DB 스키마 최신 상태 | 테이블 없음 500 에러 |
| DNS | A 레코드, CNAME 설정 및 전파 | 도메인으로 접속 불가 |
| 헬스체크 | curl로 응답 코드 확인 | 배포 성공 여부 불명 |
한줄 정리: 서버 배포 체크리스트 8가지 중 DNS는 배포 전날, DB 마이그레이션은 앱 시작 직전, 헬스체크는 배포 직후 — 순서를 지키면 새벽 긴급 대응을 피할 수 있다.