우분투 서버와 Ghost 블로그의 시간을 한국 시간으로 맞추기 (타임존 · NTP)
우분투 서버가 UTC로 돌고 있어 한국 시간과 9시간 어긋났다. OS 타임존부터 NTP 동기화, Docker 컨테이너, Ghost 사이트 설정까지 네 단계로 시간을 맞춘 과정을 순서대로 기록했다.
블로그를 운영하다 보니 서버 시간이 한국 시간과 다르게 표시되는 걸 발견했다. 글 발행 시각이나 로그 시간이 어긋나면 운영하면서 은근히 헷갈리기 때문에, 이참에 OS 타임존, NTP 시간 동기화, 그리고 Ghost 자체 시간 설정까지 한 번에 정리해 두기로 했다.
이 글은 내가 실제로 작업하면서 거친 순서 그대로 기록한 것이다.
1. 문제 확인: 서버가 UTC로 돌고 있었다
먼저 현재 서버 시간이 어떤 기준으로 도는지 확인했다.
date # 시스템 시간
date -u # UTC 시간
timedatectl # 타임존, NTP 동기화 상태 한눈에 보기
확인해 보니 타임존이 Etc/UTC로 잡혀 있었다. 한국 시간(KST)은 UTC보다 9시간 빠르기 때문에, 서버가 자정을 가리킬 때 한국은 이미 오전 9시였다. 시간 자체는 NTP로 잘 맞고 있었지만, **표시되는 기준 시간대(타임존)**가 한국이 아니었던 것이다.
특정 시점에 한국 시간이 어떻게 나오는지는 이렇게 바로 비교해 볼 수 있다.
TZ=Asia/Seoul date
2. OS 타임존을 한국 시간으로 변경
우분투에서는 timedatectl 한 줄이면 끝난다.
sudo timedatectl set-timezone Asia/Seoul
설정 가능한 타임존을 검색하고 싶다면:
timedatectl list-timezones | grep Seoul
변경 후 다시 timedatectl을 실행하면 Time zone: Asia/Seoul (KST, +0900)으로 바뀐 걸 확인할 수 있다. 재부팅 없이 즉시 적용된다.
3. 내부 NTP 서버로 시간 동기화 설정
회사/내부망 환경이라 외부 NTP(ntp.ubuntu.com) 대신 내부 NTP 서버를 쓰기로 했다. 우분투 최신 버전은 별도 설치 없이 systemd-timesyncd가 기본으로 시간 동기화를 담당한다.
현재 어떤 NTP 서버를 보고 있는지부터 확인했다.
timedatectl show-timesync | grep -E "ServerName|ServerAddress"
기본값은 외부 우분투 NTP였다. 이걸 내부 서버로 바꾸기 위해 드롭인(drop-in) 설정 파일을 만들었다. 메인 설정 파일을 직접 건드리지 않고 덮어쓸 수 있어 관리가 깔끔하다.
sudo install -d /etc/systemd/timesyncd.conf.d
# 내부 NTP 서버 주소를 NTP= 항목에 지정
sudo tee /etc/systemd/timesyncd.conf.d/10-custom-ntp.conf <<'EOF'
[Time]
NTP=<내부-NTP-서버-주소>
FallbackNTPServers=ntp.ubuntu.com
EOF
NTP=에는 내부망 NTP 서버 주소를 넣고, 혹시 내부 서버가 응답하지 않을 때를 대비해FallbackNTPServers로 외부 서버를 백업으로 남겨 뒀다.
설정을 적용하려면 서비스를 재시작한다. systemd-timesyncd는 별도의 "지금 동기화" 명령이 없고, 재시작 시 즉시 동기화를 시도한다.
sudo systemctl restart systemd-timesyncd
잘 적용됐는지 확인:
timedatectl show-timesync | grep -E "ServerName|ServerAddress|NTPMessage"
timedatectl | grep -E "synchronized|NTP service"
ServerAddress가 내가 지정한 내부 서버로 잡히고NTPMessage에 실제 응답 값이 채워지며System clock synchronized: yes
이 세 가지가 보이면 정상이다.
트러블슈팅 메모
NTP 서버가 ping에 응답하지 않는 경우가 있다. 처음엔 서버가 죽은 줄 알았는데, NTP는 UDP 123 포트를 사용하기 때문에 ICMP(ping) 차단과는 무관하다. 즉, ping이 안 돼도 NTP 동기화는 정상 동작할 수 있다.
만약 동기화가 끝까지 안 되면 NTP를 껐다 켜서 강제로 다시 잡게 할 수 있다.
sudo timedatectl set-ntp false && sudo timedatectl set-ntp true
그래도 안 되면 방화벽에서 UDP 123이 열려 있는지 확인이 필요하다.
4. Docker로 띄운 Ghost 컨테이너 시간대 맞추기
내 블로그는 Docker 컨테이너로 Ghost를 운영 중이다. 호스트 OS의 타임존과 컨테이너 내부 타임존은 별개이기 때문에, 컨테이너도 따로 한국 시간으로 맞춰야 한다.
docker-compose.yml의 environment에 TZ 환경변수를 추가했다.
services:
ghost:
image: ghost:6-alpine
environment:
TZ: Asia/Seoul
# ... 기존 설정 ...
여기서 주의할 점. 환경변수 변경은 단순 재시작(restart)으로는 반영되지 않는다. 컨테이너를 재생성해야 한다.
docker compose up -d
5. Ghost 관리자에서 사이트 타임존 설정 (가장 중요)
마지막이자 가장 핵심이다. OS와 컨테이너 시간을 다 맞춰도, Ghost는 자체 설정의 타임존을 기준으로 글 발행 시각·예약 발행 시간을 처리한다.
Ghost 관리자에서 직접 바꿔야 한다.
Settings → General → Site timezone →
(GMT +9:00) Seoul선택
이 설정을 바꾸지 않으면, 서버 시간을 아무리 맞춰도 예약 발행이 9시간 어긋나는 일이 생긴다. 실제로 시간 관련 동작에 가장 직접적인 영향을 주는 건 이 설정이었다.
정리
시간 하나 맞추는 데 의외로 레벨이 세 개나 있었다.
| 레벨 | 대상 | 설정 방법 |
|---|---|---|
| OS | 호스트 서버 | timedatectl set-timezone Asia/Seoul |
| 시간 동기화 | NTP | systemd-timesyncd 드롭인 설정 |
| 컨테이너 | Docker | docker-compose.yml의 TZ |
| 애플리케이션 | Ghost | 관리자 → Settings → Site timezone |
겉으로 보이는 증상은 "발행 시간이 9시간 어긋난다" 하나지만, 원인은 이 중 어디든 될 수 있다. 다음에 또 헷갈리지 않도록, OS → NTP → 컨테이너 → 앱 순서로 점검하는 흐름을 기록으로 남겨 둔다.