홈서버의 진짜 시험은 평소가 아니라 재부팅 직후에 온다. 정전이 지나가고, 커널 업데이트가 적용되고, 어느 날 외출 중에 서버가 한 번 꺼졌다 켜진다. 이때 서비스가 스스로 살아나지 않으면, 집에 돌아와 SSH로 들어가 하나씩 손으로 올리는 신세가 된다. 자동 복구는 기능이 아니라 운영의 기본값이어야 한다. 복구는 네 개의 층으로 설계한다.
1층 — 전원: 서버가 스스로 켜지는가
정전 후 전기가 들어왔을 때 본체가 자동으로 켜지는지는 BIOS/UEFI 설정에 달려 있다. 제조사마다 이름이 조금씩 다르지만 보통 “Restore on AC Power Loss” 또는 “AC Power Recovery” 항목이며, 이를 Power On으로 바꾼다. 이 설정 하나를 모르면 아래의 모든 자동화가 “전원 버튼을 눌러줄 사람”을 기다리게 된다.
2층 — 스토리지: 디스크 하나가 부팅을 막지 않게
/etc/fstab에 등록한 외장 디스크가 어느 날 인식되지 않으면, 기본 설정에서는 부팅 자체가 멈출 수 있다. 마운트 실패를 부팅 차단 사유로 취급하기 때문이다. 모든 비필수 디스크에는 nofail 옵션을 붙인다.
UUID=xxxx-xxxx /mnt/backup ext4 defaults,nofail,x-systemd.device-timeout=30 0 2
x-systemd.device-timeout=30은 그 디스크를 30초만 기다리고 포기하라는 뜻이다. 백업 디스크가 빠져 있어도 서버는 일단 떠야, 원격에서 상황이라도 볼 수 있다.
3층 — 애플리케이션: 도커 재시작 정책
도커는 컨테이너별 재시작 정책을 제공한다 (공식 문서). 네 가지의 차이를 정확히 알아야 한다.
| 정책 | 동작 | 홈서버 적합성 |
|---|---|---|
no (기본) | 아무것도 안 함 | ✗ 재부팅 시 전부 내려감 |
on-failure | 비정상 종료 시만 재시작 | △ 부팅 시 복구 안 됨(데몬 재시작 시 실행 중이던 것만) |
always | 항상 재시작, 수동으로 멈춰도 데몬 재시작 시 되살아남 | △ “내가 끈 것”까지 살아나는 게 함정 |
unless-stopped | 항상 재시작하되, 수동으로 멈춘 건 존중 | ✓ 권장 |
always와 unless-stopped의 차이가 실전에서 중요하다. 문제가 있어서 일부러 내려둔 컨테이너가 재부팅 후 멋대로 살아나는 것(always)은 원하는 동작이 아니다. 그래서 홈서버의 기본값은 unless-stopped다.
services:
jellyfin:
image: jellyfin/jellyfin:latest
restart: unless-stopped
도커 데몬 자체는 우분투 패키지 설치 시 systemd에 enable되는 것이 일반적이지만, systemctl is-enabled docker로 한 번 확인해두자. 도커 밖에서 직접 돌리는 프로그램이 있다면 그것도 nohup이나 터미널 실행이 아니라 systemd 유닛 + enable로 등록해야 같은 보장을 받는다.
서비스 간 순서가 필요할 때
한 컴포즈 파일 안의 서비스들(예: 앱 + 데이터베이스)은 depends_on으로 시작 순서를 정할 수 있다. 다만 depends_on은 기본적으로 “컨테이너가 시작됐는지”만 보장하고 “준비됐는지”는 모른다. DB가 연결을 받을 준비가 되기 전에 앱이 붙으려다 실패하는 패턴이 전형적이다. 해법은 두 가지 — DB 서비스에 healthcheck를 정의하고 depends_on에 condition: service_healthy를 거는 것, 그리고 애초에 앱이 초기 연결 실패 시 스스로 재시도하도록 두고 restart 정책이 받쳐주게 하는 것이다. 홈서버 수준에서는 후자만으로 충분한 경우가 많다.
4층 — 검증: 재부팅 테스트 없이는 완성이 아니다
여기까지 설정하고 “됐다”고 믿으면 안 된다. 자동 복구는 실제 재부팅으로만 검증된다.
sudo reboot
# 몇 분 뒤 외부에서:
ssh 서버 'docker ps --format "{{.Names}}\t{{.Status}}"'
모든 컨테이너의 Status가 Up으로 돌아왔는지, 마운트(df -h)가 전부 붙었는지 확인한다. 한 단계 더 나아가면, 부팅 후 몇 분 뒤 서비스 상태를 점검해 결과를 보내주는 스크립트를 걸어둘 수 있다 — 텔레그램 알림 구축 글에서 다루는 방식 그대로다.
이 4층 구조는 최근 실제 장애에서 한 번 검증됐다. 어느 날 새벽 서버가 통째로 멈춘 일이 있었다 — NVMe 컨트롤러가 응답을 멈추면서 대기 프로세스가 적체되어 시스템 전체가 굳은 것으로 추정됐다. 다시 부팅됐을 때 fstab의 nofail 덕에 외장 디스크 상태와 무관하게 부팅이 완주했고, cron 작업과 컨테이너는 손대지 않아도 제자리로 돌아왔다. 그날 배운 것은 “복구 자동화는 마지노선”이라는 점이다. 같은 장애를 또 기다릴 게 아니라 전조를 잡아야 한다는 생각에, NVMe 타임아웃·리셋 로그를 5분 주기 감시 항목에 추가했다 — 멈추고 나서 살아나는 층 위에, 멈추기 전에 알리는 층을 하나 더 얹은 셈이다.
점검 체크리스트
- BIOS: AC 전원 복구 = Power On
- fstab: 비필수 마운트 전부에
nofail - 모든 compose 파일에
restart: unless-stopped - 도커 외 상시 프로그램은 systemd enable
- 실제 재부팅 테스트로 전 서비스 복구 확인
이 네 층이 갖춰지면 서버는 “돌봐야 하는 기계”에서 “알아서 돌아오는 기계”가 된다. 그게 가능해야 다음 주제인 백업과 모니터링도 의미를 가진다.