[개발][Home Server] Docker로 Ghost 블로그 구축기: DB 잠금(Lock) 해제부터 SMTP 로그인 해결까지

N100 미니 PC 서버에 Ghost 블로그를 Docker로 구축하면서 겪은 수많은 시행착오(Try & Error)와 해결 방법을 기록한다. 나중에 똑같은 문제가 생겼을 때, 혹은 나와 같은 환경(Ubuntu + Docker + Synology DB)을 구성하는 사람들에게 도움이 되기를 바란다.

1. 발단: Ghost 컨테이너의 무한 재부팅

docker-compose로 야심 차게 컨테이너를 올렸으나, 로그(docker logs)를 확인해보니 다음과 같은 에러를 뱉으며 무한 재부팅이 반복되었다.

MigrationsAreLockedError: Migration lock was never released or currently a migration is running.

알고 보니 Ghost가 업데이트나 설정 변경 도중 비정상 종료되면, 데이터베이스 보호를 위해 **'Lock(잠금)'**을 걸어버리는데, 재부팅 후에도 이 잠금이 풀리지 않아 실행되지 않는 문제였다.

2. 해결: MySQL에서 강제로 잠금 해제하기

이 문제는 DB에 직접 접속해서 잠금을 풀어줘야 해결된다.

1) MySQL 클라이언트 설치 및 접속
서버에 클라이언트 도구가 없다면 설치부터 해야 한다.

sudo apt install mysql-client
mysql -h [DB_IP] -u ghost_user -p

2) 잠금 해제 쿼리 실행
migrations_lock 테이블의 locked 값을 0으로 강제 변경해 주었다.

USE ghost_data;
UPDATE migrations_lock SET locked=0;
FLUSH PRIVILEGES;
EXIT;

이후 컨테이너를 재시작하니 정상적으로 부팅되었다.


3. 난관: 외부 기기 로그인 불가 (feat. SMTP)

서버 내부망에서는 로그인이 잘 되는데, 핸드폰이나 외부 기기에서 로그인하려고 하면 무한 로딩이 걸리거나 에러가 났다.
로그를 뜯어보니 원인은 **이메일 발송 실패(EmailError)**였다.

Ghost는 새로운 기기에서 접속 시도 시 보안 인증 메일을 발송하는데, SMTP 설정이 없어서 메일을 못 보내고 에러를 뿜었던 것.

4. 최종 해결: Synology MailPlus 연동

Gmail을 쓸 수도 있지만, 기왕 구축해 둔 Synology MailPlus Server를 SMTP로 활용하기로 했다.
최종적으로 성공한 docker-compose.yml 설정은 다음과 같다.

version: '3.8'

services:
  ghost-app:
    image: ghost:5-alpine
    container_name: ghost-blog
    restart: always
    ports:
      - "2368:2368"
    environment:
      # [기본 접속 설정]
      url: N100서버 내부IP:2368
      
      # [DB 연결 (Synology MariaDB)]
      database__client: mysql
      database__connection__host: 시놀로지 내부IP
      database__connection__user: ghost_user
      database__connection__password: [비밀번호]
      database__connection__database: ghost_data
      
      # [SMTP 설정 (Synology MailPlus)]
      mail__from: 'admin@[내도메인]'
      mail__transport: SMTP
      mail__options__host: 시놀로지 내부IP
      mail__options__port: 25
      mail__options__auth__user: [시놀로지ID]
      mail__options__auth__pass: [시놀로지PW]
      
      # 내부망 통신 시 인증서 에러 무시 (필수)
      mail__options__secureConnection: 'false'
      mail__options__ignoreTLS: 'true'
      
    volumes:
      - ./ghost-content:/var/lib/ghost/content

5. 결론 및 배운 점

  1. DB Lock: Ghost가 켜지다 말았을 땐 당황하지 말고 DB locked 값을 확인하자.
  2. 로그인 문제: 로그인이 안 되면 쿠키 문제일 수도 있지만, SMTP 설정이 없어서 인증 메일을 못 보내는 게 원인일 수 있다.
  3. 로그 확인: docker logs ghost-blog는 거짓말을 하지 않는다.

이제 블로그 구축이 끝났으니, 본격적으로 자동화와 커스터마이징을 시작해봐야겠다.


💡 팁: Ghost에 붙여넣는 법

  1. Ghost 글쓰기 화면을 켭니다.
  2. 제목에 위의 제목을 붙여넣습니다.
  3. 본문 클릭 후, 위 내용을 그대로 복사해 붙여넣으면 마크다운 문법이 자동 적용되어 깔끔하게 들어갑니다.
  4. Tags#Ghost, #Docker, #HomeServer, #Troubleshooting 같은 태그를 달아주면 나중에 찾기 편합니다.