시놀로지 NAS에 Docker로 Ghost 설치하기 (Ghost 6.10.3-alpine + MySQL 8.0.44 + Nginx Proxy Manager HTTPS)
이 글에서는 시놀로지 NAS(DSM)에서 컨테이너를 이용해 Ghost 블로그를 설치하고, Nginx Proxy Manager(NPM) 뒤에서 HTTPS 도메인으로 서비스하는 구성을 정리합니다.
구성 요약
- Ghost:
ghost:6.10.3-alpine - DB:
mysql:8.0.44 - 외부 서비스 도메인:
https://blog.oopstorage.com - Ghost 외부 노출 포트: 2369 (호스트 2369 → 컨테이너 2368)
- Reverse Proxy: Nginx Proxy Manager에서 SSL(HTTPS) 종단
- 데이터 영속화: Ghost content / MySQL data 모두 volume로 보존
1. 준비사항
1) 사전 준비
- 시놀로지 DSM에 Container Manager(Docker) 설치
- 도메인
blog.oopstorage.com이 외부에서 NAS로 접근 가능하도록 DNS 설정 - 라우터 포트포워딩 또는 리버스 프록시 접근 환경 준비(외부 노출 시)
- (권장) Nginx Proxy Manager 컨테이너를 별도로 운영 중이어야 함
2) 설치 폴더 구성(권장)
NAS에 아래처럼 프로젝트 폴더를 준비합니다.
ghost/docker-compose.yml.env
2. 환경변수(.env) 분리
민감한 비밀번호/설정은 .env로 분리하면 관리가 편하고 안전합니다.
.env 파일 예시:
TZ=Asia/Seoul
MYSQL_DATABASE=ghost
MYSQL_USER=oOpsKorean
MYSQL_PASSWORD=CHANGE_ME_GHOST_DB_PASSWORD
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD
MYSQL_USER는 root가 아닌 일반 사용자로 설정해야 합니다.- 비밀번호는 반드시 강력하게 설정하세요.
3. Docker Compose 작성
아래는 최종적으로 정상 구동에 성공한 docker-compose.yml 입니다.
version: "3.8"
services:
db:
image: mysql:8.0.44
container_name: ghost-db
restart: unless-stopped
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --mysqlx=0
environment:
TZ: ${TZ}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
volumes:
- ghost-db-data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
networks:
- ghost-net
ghost:
image: ghost:6.10.3-alpine
container_name: ghost
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
# 호스트 2369 -> 컨테이너 2368(Ghost 기본)
- "2369:2368"
environment:
TZ: ${TZ}
NODE_ENV: production
# 외부 공개 도메인(HTTPS)으로 고정 (NPM이 SSL 종단)
url: "https://blog.oopstorage.com"
database__client: mysql
database__connection__host: db
database__connection__user: ${MYSQL_USER}
database__connection__password: ${MYSQL_PASSWORD}
database__connection__database: ${MYSQL_DATABASE}
# Reverse Proxy(NPM) 뒤 운영 시 필수 권장
trust_proxy: "true"
volumes:
- ghost-content:/var/lib/ghost/content
networks:
- ghost-net
networks:
ghost-net:
volumes:
ghost-db-data:
ghost-content:
구성 포인트
- DB가 준비되기 전에 Ghost가 먼저 뜨는 문제를 줄이기 위해
healthcheck+depends_on(condition: service_healthy)를 적용했습니다. url은 반드시 실제 서비스 도메인인https://blog.oopstorage.com으로 고정해야 합니다.- 내부 IP/포트를 넣어두면 리다이렉트/리소스 URL 생성이 꼬일 수 있습니다.
trust_proxy: "true"는 NPM처럼 리버스 프록시(SSL 종단) 뒤에서 Ghost가 “HTTPS 요청”을 올바르게 인지하도록 도와줍니다.
4. 컨테이너 실행
프로젝트 폴더에서 compose를 실행합니다.
docker compose up -d
(DSM UI를 사용한다면 Container Manager에서 프로젝트/스택으로 배포해도 동일합니다.)
실행 후 확인:
ghost-db컨테이너: 정상 기동 및 healthcheck 통과ghost컨테이너: DB 연결 후 정상 기동
내부 포트 테스트(선택):
http://NAS_IP:2369로 접속 시 Ghost 응답 확인
(단,url이 HTTPS 도메인으로 고정되어 있으면 접속 시 HTTPS로 유도될 수 있습니다.)
5. Nginx Proxy Manager(NPM) 설정
NPM에서 Proxy Host를 생성합니다.
- Domain Names:
blog.oopstorage.com - Scheme:
http - Forward Hostname / IP: NAS 내부 IP (예:
192.168.1.210) - Forward Port:
2369
SSL 탭:
- Let’s Encrypt 인증서 발급
- Force SSL 활성화
이후 외부에서 아래 주소로 접속:
https://blog.oopstorage.com
6. 한글 글꼴 적용 및 폰트 크기 조정
6.1. Code Injection 설정
- Ghost Admin → Settings → Code Injection → Site Header
<!-- Prism.js CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/themes/prism-twilight.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/plugins/toolbar/prism-toolbar.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/plugins/line-numbers/prism-line-numbers.min.css">- Ghost Admin → Settings → Code Injection → Site Footer
<!-- Prism.js Core -->
<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.min.js" defer></script>
<!-- Prism.js Plugins -->
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/autoloader/prism-autoloader.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/toolbar/prism-toolbar.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/line-numbers/prism-line-numbers.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/show-language/prism-show-language.min.js" defer></script>
<!-- Adds line numbers to code blocks -->
<script>
window.addEventListener('DOMContentLoaded', (event) => {
document.querySelectorAll('pre[class*=language-]').forEach(function (node) {
node.classList.add('line-numbers');
});
Prism.highlightAll();
});
</script>7. 참고 및 주의사항
- 어드민 에디터(글쓰기 화면)는 Code Injection이 적용되지 않음
- 프론트엔드(블로그 방문자 화면)만 커스텀 가능