호스팅 이전을 앞두고 가장 두려운 부분이 “다운타임”입니다. 결제 사이트라면 한 시간이 매출 손실이고, 검색 사이트라면 SEO 손실입니다. 잘 설계하면 실제 끊김은 수 초~수십 초로 줄일 수 있습니다.
마이그레이션 4단계
크게 네 단계입니다.
① 신규 서버 준비 (병행 구동, 트래픽 0)
② 데이터 동기화 (실시간 복제)
③ Cut-over (트래픽 전환)
④ 검증 + 구서버 정리
각 단계의 핵심은 다음과 같습니다.
1단계 — 신규 서버 준비 (병행 구동)
기존 서버는 그대로 둔 채 신규 서버에 동일한 환경을 만듭니다.
환경 동등성 확보
- OS·버전 동일 (또는 신규는 더 최신)
- PHP·Node.js·Python 버전 동일
- Nginx·Apache 설정 동일
- DB 메이저 버전 동일 (마이너는 다를 수 있음)
- 인증서, cron, systemd 단위 모두 복사
코드는 GitHub에서 동일하게 배포, 환경 변수는 같게 설정합니다.
신규 서버 단독 테스트
DNS는 아직 안 바꿉니다. hosts 파일로 신규 서버를 가리키게 해서 본인만 신규 서버로 접속:
# /etc/hosts (로컬 PC)
203.0.113.20 example.com www.example.com
이 상태로 신규 서버에서 모든 기능이 정상 동작하는지 충분히 검증합니다. 환경 설정 오류는 여기서 모두 잡습니다.
2단계 — 데이터 동기화
데이터를 두 서버에 양쪽 다 있게 만드는 단계. 두 가지를 동시에 진행합니다.
DB 실시간 복제
가장 정통적인 방법은 MySQL/PostgreSQL replication입니다. 구서버를 master, 신서버를 read replica로 설정.
# MySQL — 신규를 replica로 설정
CHANGE MASTER TO
MASTER_HOST='구서버IP',
MASTER_USER='repl_user',
MASTER_PASSWORD='...',
MASTER_LOG_FILE='mysql-bin.000123',
MASTER_LOG_POS=12345;
START SLAVE;
신서버가 구서버의 모든 쓰기를 실시간으로 따라잡습니다. SHOW SLAVE STATUS\G로 지연 0초 확인.
복제가 어려운 환경(SQLite, 패키지화된 SaaS 등)이라면 dump → 복원 → 다시 dump 직전 짧은 다운타임 방식.
파일 동기화
이미지·업로드·자산 파일은 rsync로 증분 복사:
# 매분 증분 동기화
* * * * * rsync -avz --delete /var/www/uploads/ \
newserver:/var/www/uploads/
대용량이라면 첫 동기화에 시간이 걸리니 며칠 전부터 시작하는 게 좋습니다.
3단계 — Cut-over (트래픽 전환)
가장 신중하게 진행해야 하는 단계입니다. 전환 직전에 다음을 차례로 진행합니다.
3-1) 준비 — TTL 짧게
전환 며칠 전 도메인 DNS의 TTL을 점진적으로 낮춥니다.
며칠 전: 86400 → 3600
하루 전: 3600 → 300
당일: 300 → 60
전환 시점에 60초로 낮춰져 있어야 빠르게 반영됩니다.
3-2) 구서버를 읽기 전용으로 (선택)
쓰기 충돌을 막기 위해 짧은 시간 구서버를 읽기 전용으로 전환:
# MySQL
SET GLOBAL read_only = ON;
# 또는 애플리케이션에서 메인터넌스 모드
쇼핑몰처럼 쓰기가 중요한 사이트는 이 단계를 짧게 (수 분).
3-3) 최종 데이터 동기화
남은 차이를 끝까지 따라잡고 두 서버가 완전히 동일해진 시점을 확인.
# MySQL Seconds_Behind_Master == 0
mysql -e "SHOW SLAVE STATUS\G" | grep Seconds_Behind
3-4) DNS 전환
A 레코드를 신서버 IP로 변경. 60초 TTL이라 1~2분이면 대부분 사용자가 신서버로 갑니다.
변경 전: example.com IN A 203.0.113.10 (구서버)
변경 후: example.com IN A 203.0.113.20 (신서버)
3-5) 쓰기 활성화
신서버를 쓰기 가능으로 전환:
SET GLOBAL read_only = OFF;
복제 방향을 반대로 설정하거나(신→구), 구서버는 그냥 읽기 전용 fallback으로 유지.
4단계 — 검증 + 구서버 정리
검증 (첫 1시간 집중)
- 에러율 모니터링 (5xx 비율)
- 응답 시간 그래프
- DB 연결 수
- 로그 이상 신호 (
grep -i error)
트래픽이 양쪽에서 들어오는지 확인
DNS TTL이 60초여도 일부 사용자·DNS는 캐시를 더 오래 유지. 구서버 액세스 로그를 계속 보세요.
# 구서버 로그 실시간
tail -f /var/log/nginx/access.log
48시간 정도 양쪽 트래픽이 들어옵니다. 그동안은 두 서버 모두 동작해야 합니다.
구서버 강등
- 48시간 후 신서버 트래픽이 안정적이면 구서버를 stop
- 1주일 후 구서버 백업만 남기고 해지
- 백업은 최소 30일 보관
사고 발생 시 — 롤백 카드
전환 직후 심각한 문제가 생기면 즉시 되돌립니다.
1. DNS를 구서버 IP로 다시 변경 (60초 안에 사용자 일부 복귀)
2. 신서버 단절 (방화벽 또는 stop)
3. 구서버 read_only 해제
4. 발견된 문제 진단 → 재시도
이 절차를 사전에 문서화하고 권한 있는 사람이 즉시 실행 가능해야 합니다.
DNS 전환의 함정
TTL 무시 ISP·OS
TTL 60초로 설정했어도 일부 ISP·기기가 더 오래 캐시. 48시간 양쪽 운영이 안전.
다중 도메인
example.com, www.example.com, API 서브도메인, CDN 매핑까지 모두 전환해야 함. 누락 시 일부 페이지만 깨짐.
A 레코드만 옮기면 메일이 안 옵니다. MX 레코드는 별도, 같은 서버에서 메일도 운영했다면 함께 옮기거나 SaaS로 분리.
세션 처리
사용자가 로그인 상태에서 전환되면 세션이 어떻게 되는가?
세션 스토어가 외부면 OK
Redis·Memcached·DB에 세션 저장하면 두 서버가 같은 스토어 보기에 영향 없음.
파일 세션이면
신서버에는 그 세션이 없어 사용자가 로그아웃됨. 대안:
- 신규 사용자만 신서버로 (배포 전 안내)
- 세션 데이터를 새 서버로 사전 복사
- 세션 스토어를 외부로 옮긴 뒤 마이그레이션 진행
결제·진행 중 거래
중간에 끊기면 안 되는 트랜잭션은 마이그레이션 직전에 정리 완료.
캐시 처리
CDN 캐시는 이전 후에도 그대로 남아 있어 도움이 됩니다. 신서버 부하 완화.
다만:
- 새 IP에서 인증서가 다르면 캐시 무효화 필요
- 버전 변경이 있다면 캐시 키도 갱신
메일 / 알림
마이그레이션 작업이 있다고 사용자에게 사전 안내. 작업 시간을 명시(예: 새벽 3~5시) + 무중단 목표지만 만일을 대비.
알림 채널:
- 사이트 공지 배너
- 이메일 뉴스레터
- 슬랙·텔레그램 채널 (내부 팀)
- 상태 페이지(Statuspage·Atlassian)
자주 빠지는 함정
- TTL을 안 낮춰서 전환 후 24시간 양쪽 동시 사용 → 데이터 불일치
- 백업 미실시 전환 직전 → 사고 발생 시 복구 불가
- 인증서 누락 → 신서버 HTTPS 실패
- cron·systemd 단위 미복사 → 정기 작업 누락 (백업·이메일·통계)
- DB 권한 누락 → 신서버에서 일부 쿼리만 실패
- 방화벽 차단 → 신서버가 외부 API 호출 못 함
- 로그 디렉토리 권한 → 신서버에서 로그 안 쌓임
체크리스트를 만들고 두 명이 교차 확인하는 게 사고를 줄입니다.
마이그레이션 체크리스트
- TTL을 60~300초로 충분히 사전 낮춤
- 신서버 환경이 구서버와 100% 동등
- DB 실시간 복제 정상 (지연 0)
- 파일 동기화 완료, 차이 0
- SSL 인증서 신서버에 발급·테스트
- cron·systemd 단위 모두 복사
- 모니터링·알림 채널 신서버 등록
- 롤백 절차 문서화
- 작업 시간 외부 공지
- 백업 직전 한 번 더 진행
마무리
무중단 마이그레이션은 사전 준비가 9할입니다. 전환 자체는 수 분이지만, 그 전 며칠~몇 주의 동기화·검증·체크리스트가 사고를 막습니다.
TCP-80.NET은 일본 호스팅 이전 가이드를 한국어로 제공합니다. 기존 호스팅에서 옮기실 계획이 있다면 텔레그램으로 환경을 알려주시면 절차를 상세히 안내해 드립니다.