프로덕션 데이터베이스를 직접 운영해야 하는 이유
개발할 때는 데이터베이스가 로컬에 있으면 충분했습니다. 하지만 서비스를 실제로 올리면 사용자가 쓴 데이터, 결제 기록, 게시글 전부 서버에 쌓입니다. 서버 디스크가 고장 나거나 누군가 실수로 데이터베이스를 날려버리면 백업이 없으면 복구할 방법이 없습니다. 그래서 프로덕션에서는 데이터베이스를 직접 설치하고 관리해야 합니다.
이 튜토리얼에서는 VPS에 PostgreSQL을 배포하고 보안 설정부터 매일 자동 백업까지 구축하는 전체 과정을 다룹니다. 데이터를 지키는 1인 운영의 핵심입니다.
1. 왜 PostgreSQL인가?
MySQL도 훌륭한 데이터베이스지만 최근 트렌드는 PostgreSQL입니다. SQL 표준을 엄격하게 지켜서 다른 데이터베이스로 마이그레이션하기 좋고, JSON 데이터 타입을 기본 지원해서 REST API 응답을 그대로 저장할 수도 있습니다. 전문 검색 확장인 pg_trgm도 내장되어 있어 검색 기능도 쉽게 붙입니다. 복잡한 쿼리에서 성능이 안정적이고 동시 처리에 강하며, 커뮤니티가 활발해 문제 해결책을 찾기 쉽습니다. 다음 글에서 다루는 Docker Compose에서도 PostgreSQL이 기본 데이터베이스로 쓰입니다.
2. 설치 + 초기 보안
Ubuntu 기준입니다.
sudo apt update
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable postgresql
sudo systemctl status postgresql
패키지를 설치하면 postgres라는 기본 사용자와 서비스가 자동으로 만들어지고, 재부팅해도 자동으로 시작됩니다. 설치 직후 가장 먼저 해야 할 일은 기본 postgres 계정의 비밀번호 변경입니다. 기본값은 비밀번호가 없거나 매우 약해서 그 상태로 두면 누구나 접속할 수 있습니다.
sudo -u postgres psql
-- psql 안에서:
ALTER USER postgres WITH PASSWORD '강력한비밀번호';
\q
3. pg_hba.conf 접근 제어
PostgreSQL의 접근 제어는 pg_hba.conf 파일로 관리합니다. 위치는 /etc/postgresql/{버전}/main/ 안입니다. 기본값은 모든 로컬 접속을 peer 인증(운영체제 계정 이름으로 접속)으로 허용하는데, 이것을 md5 인증(비밀번호 해시)으로 바꿔야 합니다.
# /etc/postgresql/16/main/pg_hba.conf
# host 항목을 peer -> md5 로 변경
host all all 127.0.0.1/32 md5
host all all 10.0.0.0/24 md5 # VPN 대역만 허용
sudo systemctl restart postgresql
4. listen_addresses + 방화벽
listen_addresses 기본값은 localhost만 듣는 것입니다. 외부에서 접속하려면 특정 IP나 인터페이스로 바꿔야 하지만 0.0.0.0으로 열면 모든 IP에서 접속 가능해지므로 위험합니다. 신뢰할 수 있는 IP만 지정하거나, 가장 안전한 방법인 WireGuard VPN 터널을 통해서만 접속하게 합니다.
# /etc/postgresql/16/main/postgresql.conf
listen_addresses = 'localhost,10.0.0.1' # VPN IP만
sudo ufw allow from 10.0.0.0/24 to any port 5432
sudo systemctl restart postgresql
W26에서 설정한 WireGuard 터널 안으로 접속하면 pg_hba.conf에서 VPN IP 대역만 허용해 외부에서는 접속 자체가 차단됩니다. 원격 접속 테스트:
psql -h 서버VPN_IP -U postgres
5. pg_dump 백업 스크립트
백업이 없으면 데이터베이스를 직접 운영하는 의미가 없습니다. pg_dump가 PostgreSQL의 기본 백업 도구입니다. 전체 데이터베이스를 하나의 파일로 덤프합니다.
#!/bin/bash
# /usr/local/bin/pg-backup.sh
set -euo pipefail
DB_NAME="myapp"
BACKUP_DIR="/mnt/backup/postgres"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/pg-backup.log"
mkdir -p "$BACKUP_DIR"
pg_dump -Fc "$DB_NAME" | gzip > "$BACKUP_DIR/backup_${TIMESTAMP}.dump.gz"
if [ $? -eq 0 ]; then
echo "[$(date)] 백업 성공: backup_${TIMESTAMP}.dump.gz" >> "$LOG_FILE"
else
echo "[$(date)] 백업 실패" >> "$LOG_FILE"
fi
# 7일 이상 된 백업 자동 삭제
find "$BACKUP_DIR" -name "backup_*.dump.gz" -mtime +7 -delete
-Fc 옵션은 커스텀 포맷으로 압축도 함께하고, 타임스탬프를 파일명에 붙여 겹치지 않게 합니다. W28에서 배운 셸 스크립팅 패턴(에러 핸들링 + 로그)을 그대로 적용했습니다.
6. cron 자동 백업 + 보관 정책
# /etc/cron.d/pg-backup
# 매일 새벽 3시에 실행
0 3 * * * postgres /usr/local/bin/pg-backup.sh
백업 파일이 계속 쌓이면 디스크를 꽉 채우므로 find -mtime +7로 7일이 지난 파일은 자동 삭제합니다(로테이션). 이렇게 하면 매일 백업이 자동으로 돌고 오래된 건 스스로 정리됩니다.
7. 복원 실습 + pgAdmin
백업이 있으면 복원도 간단합니다. pg_restore로 덤프 파일에서 데이터를 되돌립니다.
createdb -U postgres restore_test
pg_restore -U postgres -d restore_test backup_20260101_030000.dump.gz
큰 데이터베이스면 복원에 시간이 걸리고, 복원 중인 DB는 사용할 수 없으니 유지보수 시간에 하세요. 복원 전에 현재 데이터를 다시 백업해 두는 것도 안전합니다.
pgAdmin은 PostgreSQL의 공식 웹 관리 도구입니다. W29에서 배운 Nginx 뒤에 두면 admin.example.com 같은 도메인으로 접근할 수 있고, SQL 쿼리를 웹에서 실행하며 테이블 구조도 시각적으로 볼 수 있습니다. 단, 웹에서 접근 가능하니 반드시 인증과 방화벽을 철저히 해야 합니다.
마무리: 데이터를 지키는 1인 운영
오늘 배운 것을 정리하면: PostgreSQL을 VPS에 설치하고, 기본 보안을 설정하고, pg_dump로 매일 백업이 자동으로 돌게 했으며, 오래된 백업은 자동으로 정리됩니다. 이제 데이터가 사라져도 어제로 되돌릴 수 있습니다. 다음 글에서는 Docker Compose로 웹·DB·캐시 프로덕션 스택을 한 번에 구축합니다.
추천 VPS: 이 튜토리얼은 Vultr(서울 리전, 100달러 크레딧), DigitalOcean, Hetzner 어디서나 동일하게 적용됩니다.



















