This skill should be used when the user asks about Podman, Docker, immich, or encounters container OOM, "Tailscale IP binding" timing issues, OCI backend configuration...
Podman 컨테이너 및 홈서버 서비스 (immich, uptime-kuma, copyparty, karakeep) 운영 가이드.
Caddy HTTPS 리버스 프록시를 통해 *.greenhead.dev 도메인으로 접근한다.
홈서버 서비스는 homeserver.* 옵션으로 선언적 활성화한다:
# modules/nixos/configuration.nix — 주요 서비스만 발췌
homeserver.immich.enable = true; # 사진 백업
homeserver.uptimeKuma.enable = true; # 모니터링
homeserver.copyparty.enable = true; # 파일 서버
homeserver.karakeep.enable = true; # 웹 아카이버
homeserver.immichBackup.enable = true; # Immich DB 백업
homeserver.reverseProxy.enable = true; # Caddy HTTPS 리버스 프록시
# 부가 서비스: *Update, *Backup, *Cleanup, *Notify 등도 동일 패턴
| 경로 패턴 | 역할 |
|---|---|
modules/nixos/options/homeserver.nix |
mkOption 정의 + 서비스 모듈 import |
modules/nixos/programs/docker/runtime.nix |
Podman 런타임 공통 설정 |
modules/nixos/programs/docker/<서비스>.nix |
개별 컨테이너 정의 (immich, uptime-kuma, copyparty, karakeep 등) |
modules/nixos/programs/<서비스>-update/ |
버전 체크 + 업데이트 (immich, uptime-kuma, copyparty, karakeep) |
modules/nixos/programs/caddy.nix |
Caddy HTTPS 리버스 프록시 |
modules/nixos/lib/service-lib.sh / .nix |
공통 셸 라이브러리 + Nix wrapper |
modules/nixos/lib/mk-update-module.nix |
업데이트 모듈 생성 헬퍼 |
modules/nixos/lib/tailscale-wait.nix |
Tailscale IP 대기 유틸리티 |
libraries/constants.nix |
IP, 경로, 도메인, 리소스 제한, UID 상수 |
Docker 서비스에서 사용하는 상수 (libraries/constants.nix):
constants.network.minipcTailscaleIP - Tailscale IPconstants.paths.dockerData / mediaData - 데이터 경로constants.containers.immich.* - Immich 리소스 제한constants.ids.render - render 그룹 GID (하드웨어 가속)constants.domain.base / subdomains - 커스텀 도메인 (greenhead.dev)| 서비스 | 도메인 | localhost |
|---|---|---|
| Immich | https://immich.greenhead.dev |
127.0.0.1:2283 |
| Uptime Kuma | https://uptime-kuma.greenhead.dev |
127.0.0.1:3002 |
| Copyparty | https://copyparty.greenhead.dev |
127.0.0.1:3923 |
| Karakeep | https://archive.greenhead.dev |
127.0.0.1:3000 |
Caddy가 Cloudflare DNS-01 ACME로 Let's Encrypt 인증서를 자동 발급한다.
Tailscale IP (100.79.80.95:443)에만 바인딩되어 VPN 내부 전용이다.
모든 컨테이너는 config.time.timeZone을 참조하며, configuration.nix의 time.timeZone만 수정하면 자동 적용된다.
runtime.nix의 backend = "podman" 누락 시 Docker fallback 에러release, openvino 아님)tailscale-wait.nix로 60초 대기. Immich/Copyparty/Uptime Kuma는 127.0.0.1 바인딩 (Caddy 프록시)--network=host: localhost 서비스 모니터링을 위해 호스트 네트워크 필수secrets/cloudflare-dns-api-token.agetrustedInterfaces = [ "tailscale0" ] — 보안은 서비스 바인딩 주소에 의존secrets/immich-db-password.age, POSTGRES_PASSWORD_FILE 볼륨 마운트podman ps -a # 컨테이너 목록
podman logs <container-name> # 로그 확인
podman restart <container-name> # 컨테이너 재시작
systemctl status podman-<container-name> # systemd 서비스 상태
# modules/nixos/configuration.nix에서 변경 후 nrs 실행
4개 컨테이너 서비스가 service-lib.sh 공통 라이브러리를 공유하는 업데이트 인프라:
| 서비스 | 버전 체크 (자동) | 수동 업데이트 | 타이머 |
|---|---|---|---|
| Immich | immich-version-check |
sudo immich-update |
03:00 |
| Uptime Kuma | uptime-kuma-version-check |
sudo uptime-kuma-update |
03:30 |
| Copyparty | copyparty-version-check |
sudo copyparty-update |
04:00 |
| Karakeep | karakeep-version-check |
sudo karakeep-update --ack-bridge-risk |
06:00 |
백업 타이머:
| 서비스 | systemd 서비스 | 타이머 | 백업 위치 |
|---|---|---|---|
| Immich 원본 미러 | immich-originals-mirror |
04:30 | HDD (/mnt/data/backups/immich-originals, SSD upload-cache rsync 미러) |
| Karakeep | karakeep-backup |
05:00 | HDD (/mnt/data/backups/karakeep) |
| Immich DB | immich-db-backup |
05:30 | HDD (/mnt/data/backups/immich) |
| Anki (headless) | anki-host-backup |
04:15 (homeserver.ankiHost.backupTime) |
HDD (/mnt/data/backups/anki-host/<instance>, 인스턴스별 일일 .colpkg만; backup.enable = false인 검증용 lab은 제외. 복구점 restore-points/의 보존 계약은 Anki 호스트 README의 복구점 절) |
공통 라이브러리 함수: send_notification, fetch_github_release, get_image_digest, check_watchdog, check_initial_run, record_success, http_health_check
서비스별 Pushover 토큰 독립 운영 (agenix: pushover-immich, pushover-uptime-kuma, pushover-copyparty, pushover-karakeep).
Immich: API 버전 조회 가능 → "현재 v2.5.5 → 최신 v2.6.0" 형태 알림. 상세: references/immich-update.md
Immich DB 백업: immich-db-backup 서비스가 매일 05:30에 podman exec immich-postgres pg_dump -Fc로 커스텀 포맷 백업 생성. 대상 HDD(mediaData) 마운트 가드(RequiresMountsFor + 스크립트 mountpoint 검사), 디스크 공간 검사, pg_restore --list 무결성 검증, 원자적 파일 이동, 30일 보관. 실패 시 Pushover 알림 (pushover-immich 재사용). sudo systemctl start immich-db-backup으로 수동 실행. 복구는 별도 DB에 복원·검증한 뒤 이름을 맞바꾼다 — 절차: references/immich-update.md의 "DB 백업/복원" 절.
Immich 원본 미러·Anki(headless) 백업도 대상 HDD(mediaData) 마운트를 RequiresMountsFor로 요구한다 (immich-originals-mirror는 스크립트 자체에도 mountpoint 검사가 있다) — HDD는 nofail이라 미마운트여도 부팅은 계속되므로, 마운트 없이 쓰기·삭제·성공 기록이 진행되지 않도록 막는 가드다. RequiresMountsFor가 막으면 스크립트가 아예 실행되지 않아 실패 Pushover 알림도 나가지 않는다 — 그 무실행은 스모크 테스트의 백업 신선도 검사(아래 "런타임 스모크 테스트" 절)로 드러난다. 다만 원본 미러(immich-originals-mirror)는 신선도 검사 대상이 아니므로, 미마운트가 오래 지속되면 그 사이엔 드러나지 않는다.
Uptime Kuma/Copyparty/Karakeep: pinned tag 기준 — 설정된 이미지를 pull → digest 비교 (같은 태그의 재빌드만 반영). GitHub latest는 새 버전 알림/안내용이며, 실제 버전 반영은 해당 서비스 모듈(modules/nixos/programs/docker/*.nix)의 image 태그 수정 후 nrs. 상세: references/service-update-system.md
Karakeep 수동 업데이트는 --ack-bridge-risk 플래그가 필수다 (브릿지/로그 의존성 인지 강제).
Karakeep 이벤트 알림: karakeep-notify가 웹훅→Pushover 브리지(socat)로 아카이빙 성공/실패 알림을 전송한다.
homeserver.smokeTest.enable = true (modules/nixos/programs/smoke-test.nix, 본체
modules/nixos/programs/smoke-test/files/smoke-test.sh). 매일 06:00에 활성 서비스의 HTTPS
엔드포인트 헬스체크 + 백업 신선도(기본 상한 초과 여부) + 실패한 systemd 유닛을 검사하고,
실패 시 Pushover 요약 알림(pushover-system-monitor 공유) 뒤 유닛도 failed로 끝난다 — 수동
systemctl start도 0이 아닌 코드를 낸다. immich-cleanup의 삭제 실패도 유닛 failed로 남아
다음 날 이 검사가 한 번 더 알린다(실패를 숨기지 않기 위한 의도된 동작). 수동 실행:
sudo systemctl start homeserver-smoke-test
journalctl -u homeserver-smoke-test --no-pager -n 30
macOS에서 ~/FolderActions/upload-immich/에 파일을 넣으면 Immich에 자동 업로드. 상세: references/folder-action.md
모바일 SSH 환경에서 Immich를 활용하여 AI 에이전트(Claude Code · Codex CLI 등)에 이미지 전달. 상세: references/mobile-ssh-image.md
runtime.nix의 backend = "podman" 확인tailscale-wait.nix가 올바르게 import 되었는지 확인secrets/immich-db-password.age 존재 확인, recipient가 바뀌었으면 그 항목만 재암호화 (managing-secrets workflows.md "호스트 추가")--network=host 필수 (기본 브릿지에서는 127.0.0.1 접근 불가)sudo grep -q '^CLOUDFLARE_API_TOKEN=.' /run/caddy/env && echo 설정됨 || echo 없음 — envScript에 set -e가 없어 토큰 읽기가 실패해도 빈 값으로 키를 쓸 수 있으므로 = 뒤 문자 존재까지 확인), systemctl status caddy-env