Rocky Linux 9에 Strapi 설치와 Nginx 역방향 프록시 구성 가이드

Strapi는 JavaScript로 작성된 오픈소스 헤드리스 콘텐츠 관리 시스템(CMS)입니다. 일반적인 헤드리스 CMS와 같이 Strapi는 프론트엔드를 기본 제공하지 않으며 API를 통해 React, Next.js 같은 프레임워크로 웹사이트를 구축할 수 있습니다. 플러그인 시스템 기반으로 관리 패널과 API를 확장 가능하게 설계되어 있으며, 각 구성 요소를 거의 모든 사용 사례에 맞게 커스터마이즈할 수 있습니다. 또한 관리자와 최종 사용자의 권한을 세밀하게 관리할 수 있는 내장 사용자 시스템을 제공합니다.
이 문서에서는 Rocky Linux 9 서버에 Strapi 커뮤니티 버전을 PostgreSQL과 함께 설치하고, Nginx를 역방향 프록시로 설정하여 HTTPS로 서비스하는 전체 절차를 설명합니다.
주요 대상 독자
- Rocky Linux 9 기반 서버에 Strapi를 배포하려는 개발자 및 운영자
- 자체 호스팅으로 헤드리스 CMS를 운영하려는 소규모 팀
- Nginx와 Let’s Encrypt로 프로덕션 준비를 하려는 시스템 관리자
중요: 이 튜토리얼은 root가 아닌 sudo 권한을 가진 사용자로 작업한다고 가정합니다. 실운영에서는 강한 암호, 방화벽 규칙, 정기 백업을 반드시 적용하세요.
전제 조건
- 최소 2GB RAM, 1 CPU 코어 이상을 가진 Rocky Linux 9 서버.
- sudo 권한을 가진 비루트 사용자.
- 예:
strapi.example.com
같은 완전한 도메인 이름(FQDN). - 시스템 최신화:
$ sudo dnf update
- 필요한 패키지 몇 가지 설치:
$ sudo dnf install wget curl nano unzip yum-utils -y
일부 패키지는 이미 설치되어 있을 수 있습니다.
목차
- 전제 조건
- 방화벽 구성
- PostgreSQL 설치 및 데이터베이스 준비
- Node.js 설치
- Strapi 설치 및 초기 빌드
- PM2로 서비스화
- Nginx 설치
- SSL 발급과 자동 갱신
- Nginx 역방향 프록시 설정
- Strapi 업그레이드 절차
- 보안 강화 및 운영 체크리스트
- 트러블슈팅 요점
- 역할별 체크리스트
- 팩트 박스 및 용어집
- 요약
1 단계 방화벽 구성
Rocky Linux는 Firewalld를 사용합니다. 우선 방화벽 상태를 확인하세요.
$ sudo firewall-cmd --state
running
기본 영역은 public입니다. 현재 활성화된 서비스와 포트를 확인합니다.
$ sudo firewall-cmd --permanent --list-services
예시 출력:
cockpit dhcpv6-client ssh
Strapi는 HTTP(80)와 HTTPS(443)를 사용하므로 두 포트를 열어줍니다.
$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reload
다시 서비스 목록을 확인하면 다음과 유사한 결과를 얻습니다.
cockpit dhcpv6-client http https ssh
중요: 개발 중에는 1337 포트를 임시로 열어 확인할 수 있지만, 프로덕션에서는 반드시 Nginx를 통해 역방향 프록시로 서비스하는 것을 권장합니다.
2 단계 PostgreSQL 설치 및 구성
Strapi는 PostgreSQL 11 이상을 지원합니다. Rocky Linux 9은 기본적으로 PostgreSQL 13을 포함하지만, 이 가이드에서는 PostgreSQL 15를 사용합니다.
PostgreSQL GPG 키 추가:
$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /usr/share/keyrings/postgresql-key.gpg >/dev/null
리포지터리 RPM 설치:
$ sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
내장 모듈 비활성화 및 PostgreSQL 15 설치:
$ sudo dnf -qy module disable postgresql
$ sudo dnf install -y postgresql15-server
데이터베이스 초기화 및 서비스 활성화:
$ sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
$ sudo systemctl enable postgresql-15
$ sudo systemctl start postgresql-15
$ sudo systemctl status postgresql-15
PostgreSQL 셸로 들어가 데이터베이스와 유저를 생성합니다. 예시에서는 데이터베이스 이름을 strapidb, 유저를 strapiuser로 사용합니다. 실제로는 강력한 비밀번호로 교체하세요.
$ sudo -i -u postgres psql
postgres=# CREATE DATABASE strapidb;
postgres-# CREATE USER strapiuser WITH PASSWORD 'Your_Password';
postgres-# ALTER DATABASE strapidb OWNER TO strapiuser;
postgres-# \q
자격증명이 동작하는지 확인합니다.
$ psql --username strapiuser --password --host localhost strapidb
Password:
psql (15.1)
Type "help" for help.
strapidb=>
팁: 운영 환경에서는 로컬 호스트 대신 전용 DB 서버를 사용하고, DB 접근은 방화벽이나 VPC로 제한하세요.
3 단계 Node.js 설치
Rocky Linux 9의 기본 Node 버전은 구 버전일 수 있으므로 최신 LTS(작성 시점 v18)를 설치합니다.
Nodesource 설치 스크립트 실행:
$ curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
$ sudo dnf install nodejs -y
버전 확인:
$ node -v
v18.13.0
주의: Strapi의 특정 버전은 Node LTS 버전 범위를 요구합니다. Strapi 릴리스 노트를 확인해 호환성 문제를 방지하세요.
4 단계 Strapi 설치
npx를 사용해 Strapi 프로젝트를 생성합니다.
$ npx create-strapi-app@latest howtoforge-project
설치 중에 Custom(수동 설정)을 선택하고 데이터베이스로 postgres, 이름과 호스트, 포트, 사용자, 비밀번호를 입력합니다.
? Choose your installation type Custom (manual settings)
? Choose your preferred language JavaScript
? Choose your default database client postgres
? Database name: strapidb
? Host: 127.0.0.1
? Port: 5432
? Username: strapiuser
? Password: Your_Password
? Enable SSL connection: No
설치가 완료되면 프로젝트 디렉터리로 이동해 프로덕션 빌드를 수행합니다.
$ cd howtoforge-project
$ NODE_ENV=production npm run build
테스트로 Strapi를 직접 실행해 결과를 확인할 수 있습니다.
$ node ~/howtoforge-project/node_modules/.bin/strapi start
이때 1337 포트를 일시적으로 방화벽에서 열어 접속을 확인하세요.
$ sudo firewall-cmd --permanent --add-port=1337/tcp
$ sudo firewall-cmd --reload
브라우저로 http://
# Ctrl+C로 프로세스 중단
$ sudo firewall-cmd --permanent --remove-port=1337/tcp
$ sudo firewall-cmd --reload
5 단계 PM2로 서비스화
수동으로 node 프로세스를 켜두기보다 PM2를 사용해 데몬화하고 systemd에 등록하면 서비스가 자동 복구되고 부팅 시 자동 시작됩니다.
홈 디렉터리로 이동:
$ cd ~
PM2 설치:
$ sudo npm install pm2@latest -g
ecosystem.config.js 파일을 생성해 프로젝트 경로와 데이터베이스 환경 변수를 설정합니다. 아래 예시에서 경로와 비밀번호를 실제 값으로 바꾸세요.
module.exports = {
apps: [
{
name: 'strapi',
cwd: '/home/navjot/howtoforge-project',
script: 'npm',
args: 'start',
env: {
NODE_ENV: 'production',
DATABASE_HOST: 'localhost',
DATABASE_PORT: '5432',
DATABASE_NAME: 'strapidb',
DATABASE_USERNAME: 'strapiuser',
DATABASE_PASSWORD: 'Your_Password',
},
},
],
};
PM2로 앱 시작:
$ pm2 start ecosystem.config.js
PM2를 시스템 서비스로 등록해 재부팅 시 자동으로 복원되도록 합니다. 출력된 sudo 명령을 복사해 실행하세요.
$ pm2 startup
# 출력된 명령을 복사해서 실행
$ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u navjot --hp /home/navjot
$ pm2 save
이제 Strapi가 백그라운드에서 프로덕션 모드로 실행됩니다.
6 단계 Nginx 설치
최신 Nginx를 사용하려면 nginx.org 공식 리포지터리를 추가합니다.
$ sudo nano /etc/yum.repos.d/nginx.repo
파일에 다음 내용을 붙여넣습니다.
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
설치 및 서비스 활성화:
$ sudo dnf install -y nginx
$ sudo systemctl enable nginx --now
$ sudo systemctl status nginx
Nginx 버전 확인:
$ nginx -v
nginx version: nginx/1.22.1
7 단계 SSL 설치 (Certbot)
Let’s Encrypt 인증서를 사용하려면 Certbot을 설치합니다. Rocky Linux에서는 snapd를 통해 설치하는 방법이 안정적입니다. EPEL이 필요합니다.
$ sudo dnf install -y epel-release
$ sudo dnf install -y snapd
$ sudo systemctl enable snapd --now
$ sudo snap install core && sudo snap refresh core
$ sudo ln -s /var/lib/snapd/snap /snap
$ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
$ certbot --version
인증서 발급 예시:
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d strapi.example.com
발급 후 인증서는 /etc/letsencrypt/live/strapi.example.com
에 저장됩니다. DH 파라미터 생성(권장):
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
갱신 테스트:
$ sudo certbot renew --dry-run
자동 갱신이 정상 동작하면 설정이 완료된 것입니다.
8 단계 Nginx 역방향 프록시 구성
기본 nginx.conf에 server_names_hash_bucket_size 설정을 추가합니다.
$ sudo nano /etc/nginx/nginx.conf
# server_names_hash_bucket_size 64; 를 include 직전에 추가
역방향 프록시 설정 파일 생성:
$ sudo nano /etc/nginx/conf.d/strapi.conf
다음 내용을 붙여넣습니다. 도메인과 인증서 경로는 실제 값으로 바꿉니다.
server {
# Redirect any http requests to https
listen 80;
listen [::]:80;
server_name strapi.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name strapi.example.com;
access_log /var/log/nginx/strapi.access.log;
error_log /var/log/nginx/strapi.error.log;
# TLS configuration
ssl_certificate /etc/letsencrypt/live/strapi.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/strapi.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/strapi.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
# OCSP Stapling ---
ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:1337;
}
}
구성 문법 검사 및 재시작:
$ sudo nginx -t
$ sudo systemctl restart nginx
이제 https://strapi.example.com 으로 Strapi에 접속할 수 있습니다. 관리자 계정은 /admin
에서 생성합니다.
9 단계 Strapi 업그레이드 절차
업그레이드 전에는 반드시 백업(파일, DB)을 만듭니다. 업그레이드 절차 요약:
- PM2에서 서비스 중지
$ cd ~
$ pm2 stop ecosystem.config.js
- 프로젝트 디렉터리로 이동해 package.json에서 Strapi 관련 패키지 버전 업데이트
$ cd howtoforge-project
$ nano package.json
예시 dependencies에서 버전 번호를 최신 안정 버전으로 변경합니다.
- 패키지 설치 및 Admin 빌드
$ npm install
$ NODE_ENV=production npm run build
- PM2로 다시 시작
$ cd ~
$ pm2 start ecosystem.config.js
주의: 메이저 버전 업그레이드는 마이그레이션 스크립트와 breaking change가 있을 수 있으므로 Strapi 공식 마이그레이션 가이드를 반드시 확인하세요.
운영과 보안 강화 권장 사항
- 비밀번호와 시크릿 관리: 환경변수 또는 비밀관리 서비스 사용. 코드나 Git에 비밀번호를 절대 커밋하지 마세요.
- HTTPS 강제 적용: Nginx에서 모든 HTTP 요청을 HTTPS로 리다이렉트하세요.
- 데이터베이스 접근 제한: DB 포트는 방화벽으로 내부 IP만 허용하거나 VPC로 분리하세요.
- 최소 권한 원칙: DB 계정에 필요한 권한만 부여하세요.
- 자동 백업: 정기적인 DB 덤프 및 업로드(예: S3, 외부 스토리지).
- 로깅과 모니터링: PM2 로그, Nginx 액세스/에러 로그, 파일시스템 사용량 및 메트릭 수집.
- 취약점 점검: 운영체제 및 패키지 보안 업데이트를 정기적으로 적용.
- 관리자 UI 접근 제한: 기본적으로 관리자 패널에 IP 제한 또는 추가 인증층을 적용하세요.
보안 하드닝 체크리스트
- 모든 관리자 계정에 2FA 적용(가능하면)
- 관리자 페이지에 WAF 적용(예: ModSecurity 또는 클라우드 WAF)
- 인증서와 키 파일 권한 최소화(chmod 600)
- Nginx에서 불필요한 헤더 제거 및 보안 헤더 추가(Strict-Transport-Security, X-Frame-Options 등)
- DB 연결에 SSL 사용을 고려
대체 접근 방식 및 고려사항
- 데이터베이스 대체: MySQL을 선택할 수도 있지만, Strapi의 일부 기능과 플러그인이 PostgreSQL에 최적화되어 있을 수 있으니 요구사항을 확인하세요.
- 컨테이너화: Docker나 Kubernetes를 사용하는 경우 컨테이너 이미지와 볼륨, 시크릿 관리를 고려하면 배포가 더 일관됩니다.
- 매니지드 DB 및 매니지드 인증서: RDS, Cloud SQL, 또는 매니지드 Certs를 사용하면 운영 부담을 줄일 수 있습니다.
- CI/CD 파이프라인: 빌드와 마이그레이션을 자동화하면 다운타임을 줄일 수 있습니다.
문제 발생 시 체크포인트
- 포트 충돌: 1337 포트가 이미 사용 중인지 확인.
- DB 연결 오류: 환경변수와 pg 호스트/포트/사용자/비밀번호 확인.
- 권한 문제: file permission 또는 systemd 서비스 유저 확인.
- 인증서 문제: certbot 로그와
/etc/letsencrypt
경로의 권한 확인. - Nginx 설정 오류:
nginx -t
명령으로 문법 검사.
역할별 체크리스트
운영자(시스템 관리자):
- OS 및 패키지 업데이트 자동화 설정
- 방화벽 규칙 검토
- 백업 및 복구 테스트 수행
- 모니터링 및 알림 구성
개발자:
- Strapi 모델과 API 권한 설계
- 마이그레이션 과정 문서화
- CI 환경에서 빌드·배포 스크립트 작성
보안 담당자:
- 관리자 계정 보안 정책 수립
- 로그 주기적 점검 및 보안 이벤트 대응 절차 수립
팩트 박스
- 권장 메모리: 2GB 이상(프로덕션은 더 권장)
- 기본 Strapi 포트: 1337
- 권장 DB: PostgreSQL 11 이상(예시에서는 15 사용)
- 권장 Node 버전: Strapi 릴리스 노트 기준 LTS(작성 시점 v18)
마이그레이션 및 업그레이드 팁
- 마이너 버전 업그레이드는 일반적으로 안전하지만, 메이저 업그레이드는 breaking change 체크리스트 확인.
- 운영 중인 인스턴스는 블루-그린 배포 방법 또는 롤링 업데이트로 다운타임 최소화.
- 업그레이드 전에
npm install
을 실행하기 전에package.json
의 버전을 검증하고, 별도의 테스트 환경에서 재현 테스트 수행.
1줄 용어집
- 헤드리스 CMS: 프런트엔드를 포함하지 않고 API로 콘텐츠를 제공하는 CMS.
- PM2: Node.js 프로세스 관리를 위한 프로세스 매니저.
- Certbot: Let’s Encrypt에서 인증서를 발급받기 위한 도구.
트러블슈팅 사례와 대응 요령
- Strapi Admin이 500을 반환할 때: PM2 로그와 Strapi 로그 확인, DB 연결 정보(환경변수) 확인.
- Nginx가 SSL 연결을 거부할 때: 인증서 경로, 권한, OCSP 설정 및 dhparam 파일 존재 여부 확인.
- Certbot 갱신 실패:
/var/log/letsencrypt/letsencrypt.log
와 웹서버가 80 포트를 반환하는지 확인.
요약
- 이 가이드는 Rocky Linux 9 서버에 Strapi를 PostgreSQL과 함께 설치하고 PM2로 서비스화한 뒤 Nginx와 Certbot으로 HTTPS 환경을 구성하는 전체 과정을 다룹니다.
- 핵심 단계: 방화벽 설정 → PostgreSQL 설치 및 DB 준비 → Node.js 설치 → Strapi 생성 및 빌드 → PM2로 데몬화 → Nginx 설치 → Certbot으로 SSL 발급 → Nginx 역방향 프록시 구성 → 업그레이드 및 보안 강화.
요약 핵심 포인트:
- 프로덕션 환경에서는 항상 HTTPS와 자동 갱신을 적용하세요.
- 비밀번호 및 시크릿은 코드에 하드코딩하지 말고 환경변수 또는 시크릿 매니저를 사용하세요.
- 업그레이드는 사전 테스트와 백업이 필수입니다.
추가 질문이나, Docker/Kubernetes 환경으로의 마이그레이션 가이드가 필요하시면 알려주세요.