서버를 오래 켜두다 보면 업데이트만큼 신경 쓰이는 것이 백업입니다. Oracle Cloud Free Tier ARM 인스턴스에 Rocky Linux 9.x를 올리고 Docker Compose v2로 서비스를 돌려보니, 컨테이너는 다시 만들 수 있어도 볼륨 안의 데이터는 한 번 잃으면 복구가 쉽지 않았습니다.
Docker 홈서버에서 백업할 것
Docker 기반 홈서버에서 지켜야 할 대상은 크게 컨테이너 볼륨, Compose 설정 파일, 데이터베이스 덤프 세 가지입니다.
컨테이너 이미지는 다시 받을 수 있고 컨테이너도 다시 생성할 수 있습니다. 하지만 /var/lib/docker/volumes 안의 앱 데이터나 직접 바인드 마운트한 ./data, ./config 폴더는 서버의 실제 상태에 가깝습니다.
특히 홈서버 서비스 중에는 SQLite, PostgreSQL, MariaDB처럼 데이터베이스를 함께 쓰는 경우가 많습니다. 이런 서비스는 폴더를 그대로 복사하기보다, 가능하면 백업 직전에 덤프 파일을 따로 만든 뒤 함께 백업하는 방식이 더 안전합니다.
Restic을 선택한 이유
Restic은 단일 바이너리로 동작하고, 암호화를 기본으로 지원합니다. S3 호환 저장소, 로컬 디스크, SFTP 같은 백엔드도 폭넓게 사용할 수 있습니다. 개인 홈서버에서는 설정이 과하게 무겁지 않고 복구 명령이 명확한 점이 장점이었습니다.
Oracle Cloud Free Tier ARM에 Rocky Linux 9.x, Docker Compose v2 조합이라면 백업 자동화 자체는 크게 복잡하지 않습니다. 중요한 것은 도구보다 기준이었습니다. 무엇을 백업할지, 언제 멈출지, 실제로 복구되는지를 정해두면 Restic은 그 흐름을 안정적으로 받쳐줍니다.
저는 Compose 파일과 볼륨 데이터, DB 덤프를 함께 묶고 systemd timer로 매일 새벽 실행합니다. 그리고 가끔 restic restore로 직접 꺼내봅니다. 홈서버는 결국 혼자 관리하는 작은 운영 환경이라서, 나중의 제가 다시 봐도 이해할 수 있는 단순한 구성이 가장 오래 갑니다.
컨테이너가 올라온 뒤에는 브라우저에서 http://서버IP:3001로 접속해 관리자 계정을 만들면 됩니다. 내부망에서만 사용할 계획이라면 공유기 포트포워딩은 열지 않는 편이 낫습니다.
재시작 정책과 볼륨을 먼저 챙긴 이유
Uptime Kuma는 모니터링 도구라서 다른 서비스보다 더 꾸준히 살아 있어야 합니다. 그래서 restart: unless-stopped를 넣어 Docker 데몬 재시작이나 서버 재부팅 이후에도 자동으로 올라오게 했습니다.
always를 쓰는 경우도 있지만, 제가 쓰는 홈서버에서는 관리자가 명시적으로 컨테이너를 내렸다면 그 상태를 유지하는 쪽이 더 자연스러웠습니다. 그래서 unless-stopped 정책이 운영 방식에 더 잘 맞았습니다.
항목
장점
단점
restart: unless-stopped
서버 재부팅 후 자동 복구되고, 사용자가 직접 내린 상태는 유지됩니다. 홈서버 운영에 가장 무난한 선택입니다.
장애 테스트 중 컨테이너를 내려둔 사실을 잊으면 계속 꺼진 상태로 남을 수 있습니다.
restart: always
Docker가 살아나는 순간 컨테이너도 다시 올라옵니다.
의도적으로 중지한 컨테이너도 다시 살아날 수 있어 점검 중에는 불편할 수 있습니다.
재시작 정책 없음
동작이 단순하고 예측하기 쉽습니다.
서버 재부팅 후 모니터링이 꺼진 채 방치될 가능성이 큽니다.
볼륨은 ./data:/app/data처럼 잡아두면 /opt/uptime-kuma/data에 설정과 이력이 남습니다. 나중에 서버를 옮기거나 백업할 때도 이 디렉터리만 챙기면 복구가 비교적 간단합니다.
서비스별로 다른 방식으로 감시하기
홈서버에 여러 컨테이너를 올려두면 서비스마다 확인 방식이 조금씩 달라집니다. HTTP만 확인하면 놓치는 부분이 있고, Ping만 보면 애플리케이션이 실제로 응답하는지 알기 어렵습니다.
MinIO처럼 포트 응답이 중요한 서비스는 TCP와 HTTP를 나눠서 보는 편이 좋았습니다. Immich는 웹 화면이나 API 응답 여부를 보는 쪽이 실용적이고, Open WebUI는 로그인 화면이 뜨는지만 확인해도 초기 장애 감지에는 충분했습니다.
서비스
확인 방식
한계
MinIO
TCP 9000, 콘솔 HTTP 응답을 나눠 보면 스토리지 접근 문제를 빨리 알 수 있습니다.
인증이 필요한 API까지 깊게 확인하려면 별도 엔드포인트 설계가 필요합니다.
Immich
HTTP 상태 확인으로 웹 서비스 장애를 감지하기 좋습니다.
백그라운드 작업 큐나 DB 상태까지는 기본 HTTP 체크만으로 부족할 수 있습니다.
Open WebUI
웹 UI 응답 여부를 간단히 확인할 수 있어 운영 부담이 적습니다.
모델 서버나 백엔드 연결 문제는 별도 체크가 필요할 수 있습니다.
Uptime Kuma에서 모니터를 추가할 때는 서비스 성격에 맞춰 이렇게 나눴습니다.
text
MinIO API TCP 192.168.0.10:9000
MinIO Console HTTP http://192.168.0.10:9001
Immich Web HTTP http://192.168.0.10:2283
Open WebUI HTTP http://192.168.0.10:3000
Home Server Ping 192.168.0.10
HTTP 체크는 상태 코드가 200번대로 돌아오는지 보는 방식이라 가장 직관적입니다. TCP는 서비스 포트가 열려 있는지 확인하는 데 좋고, Ping은 서버 자체가 네트워크에서 보이는지 확인하는 용도로 두면 됩니다.
Discord Webhook으로 알림 보내기
알림은 Telegram도 많이 쓰지만, 저는 홈서버 알림을 한 채널에 모아두기 쉬운 Discord Webhook 방식으로 설정했습니다. 이미 개인 서버나 운영 채널을 쓰고 있다면 별도 봇을 만들지 않아도 되는 점이 편합니다.
Discord에서 채널 설정으로 들어가 Webhook을 만들고 URL을 복사합니다. 그다음 Uptime Kuma의 Settings > Notifications에서 Discord를 선택한 뒤 Webhook URL을 붙여 넣으면 됩니다.
설정 후에는 바로 저장하고 끝내지 말고 Test 버튼으로 실제 알림이 오는지 확인해야 합니다. 이 단계에서 알림이 오지 않으면 장애 상황에서도 조용할 수밖에 없습니다. 채널 권한, Webhook URL 오타, 방화벽 설정을 먼저 확인하는 편이 좋습니다.
알림 문구는 길게 만들 필요가 없었습니다. 서비스명, 상태, 발생 시각 정도만 있어도 휴대폰에서 보고 바로 판단할 수 있습니다.
text
[DOWN] Immich Web
URL: http://192.168.0.10:2283
Time: 2026-07-20 01:12:30
내부망 전용과 Cloudflare Tunnel 비교
Uptime Kuma를 꼭 외부에 공개할 필요는 없습니다. 집 안이나 VPN 안에서만 확인한다면 내부 IP로 접근하는 구성이 가장 단순합니다. 외부에서도 상태를 보고 싶다면 Cloudflare Tunnel 뒤에 두는 방식도 선택할 수 있습니다.
구성
장점
단점
내부망 전용
외부 노출이 거의 없고 구성이 단순합니다. 홈서버 기본값으로 두기 좋습니다.
밖에서는 VPN 없이 접속하기 어렵습니다.
Cloudflare Tunnel
포트포워딩 없이 외부 접속 주소를 만들 수 있습니다.
계정, 터널, 접근 정책을 추가로 관리해야 합니다. 설정이 느슨하면 모니터링 화면이 노출될 수 있습니다.
내부망 전용이면 Compose의 포트 바인딩을 조금 더 제한할 수 있습니다.
yaml
ports:
- "192.168.0.10:3001:3001"
이렇게 하면 해당 내부 IP에서만 포트를 열도록 구성할 수 있습니다. 다만 서버 네트워크 환경에 따라 IP가 바뀌면 접속이 안 될 수 있으니, 홈서버에는 고정 IP를 주는 편이 관리하기 쉽습니다.
Cloudflare Tunnel 뒤에 둘 경우에는 Uptime Kuma 자체 로그인만 믿기보다 Cloudflare Access 같은 접근 제어를 함께 두는 쪽이 낫습니다. 모니터링 화면에는 서비스 주소와 장애 이력이 들어가기 때문에 생각보다 민감한 정보가 많습니다.
이력으로 장애 시작 시점 찾기
Uptime Kuma를 며칠만 켜둬도 의외로 패턴이 보입니다. 특정 시간대에 Immich가 잠깐 느려지거나, MinIO 콘솔만 간헐적으로 끊기는 식입니다.
이럴 때 “지금 죽었나?”보다 언제부터 불안정했나를 보는 게 더 중요했습니다. 로그를 뒤져볼 기준 시간이 생기기 때문입니다. 예를 들어 새벽 2시부터 HTTP 체크가 흔들렸다면, 그 시간대의 백업 작업, 컨테이너 업데이트, 스토리지 I/O를 같이 보면 됩니다.
모니터링 간격은 너무 촘촘하게 잡지 않았습니다. 개인 홈서버 기준으로는 30초에서 60초 정도면 충분했습니다. 외부 서비스처럼 SLA를 따지는 환경이 아니라면, 감지 속도보다 알림 피로도를 줄이는 쪽이 오래 갑니다.
Uptime Kuma 자체 장애에 대비하기
모니터링 도구도 결국 하나의 컨테이너입니다. 그래서 Uptime Kuma만 믿고 끝내기보다는 최소한의 백업과 점검 루틴을 만들어두는 게 좋았습니다.
/opt/uptime-kuma/data 디렉터리 주기 백업
Compose 파일을 별도 Git 저장소나 NAS에 보관
서버 재부팅 후 docker compose ps로 상태 확인
Discord 테스트 알림을 한 달에 한 번 정도 직접 실행
Uptime Kuma 컨테이너 로그 확인
bash
cd /opt/uptime-kuma
docker compose ps
docker logs --tail=100 uptime-kuma
백업은 거창하게 시작하지 않아도 됩니다. 중요한 건 설정과 이력을 잃지 않는 것입니다. 특히 알림 설정을 다시 만드는 일이 은근히 번거로워서, 데이터 디렉터리 백업은 처음 구성할 때 같이 잡아두는 편이 낫습니다.
홈서버 모니터링은 장애를 없애는 도구라기보다 장애를 늦게 발견하는 시간을 줄이는 장치에 가깝습니다. Uptime Kuma를 붙여두니 서비스별 상태를 한 화면에서 볼 수 있었고, 무엇보다 장애가 시작된 시점을 남길 수 있어 운영할 때 꽤 쓸모가 있었습니다.
콘솔에 접속하면 먼저 버킷을 만듭니다. 사진 원본용이면 photos, 백업 파일용이면 backup, 앱 첨부파일용이면 app-data처럼 목적이 드러나는 이름을 쓰는 편이 관리하기 쉽습니다.
버킷을 만든 뒤에는 루트 계정을 계속 쓰지 말고 별도 접근 키를 발급하는 흐름이 좋습니다. 콘솔의 Access Keys 메뉴에서 새 키를 만들고, 발급된 Access Key와 Secret Key를 백업 도구나 앱 설정에 넣으면 됩니다.
권한은 처음부터 넓게 주기보다 용도별로 나누는 편이 낫습니다. 백업 도구는 backup 버킷만 읽고 쓰게 하고, 사진 업로드 앱은 photos 버킷만 쓰게 하는 식입니다. 홈서버라도 루트 계정 상시 사용은 피하는 편이 운영하기 좋습니다.
외부 공개 전 내부망 테스트
MinIO를 외부에 바로 여는 것은 신중해야 합니다. 특히 9001 콘솔 포트를 인터넷에 그대로 노출하면 관리자 화면이 외부에 보이는 구조가 됩니다.
처음에는 공유기 내부망이나 VPN 안에서만 접속해보는 것을 권합니다. 외부 접속이 꼭 필요하다면 리버스 프록시, TLS 인증서, 접근 제한, 터널 구성을 먼저 정리해야 합니다. Cloudflare Tunnel이나 Nginx Proxy Manager를 붙일 수는 있지만, 그 전에 콘솔 포트와 API 포트를 어떻게 분리할지부터 정하는 게 좋습니다.
집 안에 둔 서버를 밖에서 접속하려고 하면 늘 한 지점에서 걸렸습니다. 공유기 포트포워딩은 설정 자체는 어렵지 않지만, 한 번 열어두면 계속 신경이 쓰입니다. DDNS도 공인 IP 여부나 ISP의 CGNAT 환경에 따라 생각보다 깔끔하게 끝나지 않을 때가 있었습니다.
포트포워딩을 열지 않기로 한 이유
이번 구성은 Rocky Linux 9 서버에서 Cloudflare Tunnel로 외부 접속을 붙이는 방식입니다. 서버가 Cloudflare 쪽으로 먼저 아웃바운드 연결을 만들고, 외부 요청은 그 터널을 통해 내부 서비스로 전달됩니다.
이 구조에서는 공유기에서 80, 443 같은 인바운드 포트를 열 필요가 없습니다. firewalld에도 웹 서비스 포트를 추가하지 않았습니다. SSH는 기존처럼 관리용으로만 제한해두는 쪽이 낫다고 봤고, 이 방향은 예전에 정리한 Rocky Linux 9 앵커글이나 SSH 하드닝글의 흐름과도 잘 맞았습니다.
Cloudflare 공식 문서에서도 Tunnel은 서버에서 실행되는 cloudflared가 Cloudflare와 연결을 맺는 방식으로 설명합니다. 설치와 로컬 관리형 터널 흐름은 공식 문서를 기준으로 확인했습니다.
Cloudflare Tunnel 로컬 관리형 터널 문서: https://developers.cloudflare.com/tunnel/advanced/local-management/create-local-tunnel/
cloudflared 다운로드 문서: https://developers.cloudflare.com/tunnel/downloads/
Cloudflare 패키지 저장소: https://pkg.cloudflare.com/
비슷한 선택지를 나누면 아래처럼 정리됩니다.
방식
장점
주의할 점
Cloudflare Tunnel
포트포워딩 없이 HTTP 서비스를 외부에 공개하기 쉽고 Access 정책을 붙일 수 있음
Cloudflare 프록시 제한을 받으며, 대용량 업로드에는 주의가 필요함
공유기 포트포워딩 + DDNS
구조가 단순하고 직접 제어하기 쉬움
공인 IP, ISP CGNAT, 포트 노출 문제를 직접 관리해야 함
VPN/WARP/Tailscale 계열
내부망처럼 접근할 수 있어 관리용으로 안정적
일반 웹 서비스처럼 도메인만 알려주는 공개 접근에는 별도 설계가 필요함
cloudflared 설치는 dnf repo 방식으로
Rocky Linux 9에서는 curl | bash 방식 대신 Cloudflare RPM 저장소를 추가한 뒤 dnf install로 설치했습니다. 홈서버처럼 오래 운영할 서버라면 패키지로 관리하는 편이 업데이트와 제거 면에서 깔끔합니다.
설치 후에는 SELinux 상태부터 확인했습니다. 저는 SELinux enforcing 유지를 전제로 작업했습니다.
bash
getenforce
text
Enforcing
firewalld도 확인했습니다. 이번 구성의 핵심은 외부에서 들어오는 HTTP/HTTPS 포트를 열지 않는 것이므로 http, https 서비스를 추가하지 않았습니다.
bash
sudo firewall-cmd --list-all
text
public (active)
target: default
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
중요한 점은 터널용으로 firewalld 인바운드 포트를 열지 않았다는 것입니다. 서버가 밖으로 나가는 연결을 만들기 때문에 공유기 포트포워딩도 건드리지 않았습니다.
터널 생성과 config.yml 작성
Cloudflare 계정에 도메인이 연결되어 있다는 전제에서 진행했습니다. 먼저 브라우저 인증을 한 번 거칩니다.
bash
cloudflared tunnel login
제 환경에서는 아래처럼 인증 URL이 출력됐고, 브라우저에서 도메인을 선택한 뒤 인증 파일이 생성됐습니다.
text
Please open the following URL and log in with your Cloudflare account:
https://dash.cloudflare.com/argotunnel?callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F...
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/home/rocky/.cloudflared/cert.pem
이어서 터널을 만들었습니다. 이름은 나중에 알아보기 쉽도록 homelab-rocky9로 잡았습니다.
bash
cloudflared tunnel create homelab-rocky9
text
Tunnel credentials written to /home/rocky/.cloudflared/2f7b3b7c-9a66-4c91-8b52-111111111111.json.
Created tunnel homelab-rocky9 with id 2f7b3b7c-9a66-4c91-8b52-111111111111
설정 파일은 /etc/cloudflared/config.yml에 두고 systemd에서 안정적으로 읽도록 했습니다. 아래 예시는 Immich를 http://localhost:2283으로 연결하는 형태입니다. 실제 도메인은 본인 도메인에 맞게 바꾸면 됩니다.
Cloudflare 문서에서는 마지막에 catch-all 규칙을 두는 흐름을 안내합니다. 그래서 맨 아래에 http_status:404를 넣어 정의하지 않은 호스트는 막히게 했습니다.
DNS 라우팅은 아래처럼 잡았습니다.
bash
cloudflared tunnel route dns homelab-rocky9 immich.example.com
cloudflared tunnel route dns homelab-rocky9 admin.example.com
text
2026-07-17T03:41:12Z INF Added CNAME immich.example.com which will route to this tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
2026-07-17T03:41:18Z INF Added CNAME admin.example.com which will route to this tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
여기까지 확인해야 홈서버 운영용으로 믿고 쓸 수 있습니다. 단순히 접속이 되는지보다 서버 재부팅 후에도 터널이 자동으로 살아나는지가 더 중요했습니다.
Immich 백업에서 만난 100MB 제한
Cloudflare Tunnel을 붙인 뒤 가장 먼저 확인한 서비스는 Immich였습니다. 사진 백업은 잘 됐지만, 모바일에서 찍은 영상 하나가 계속 실패했습니다. 처음에는 Immich 설정이나 nginx 업로드 제한을 의심했는데, 로그를 보니 원인은 다른 쪽에 가까웠습니다.
Cloudflare의 Request body size limit 기준으로 Free와 Pro 플랜은 요청 본문 최대 100MB입니다. 이 제한을 넘는 업로드는 413 Request Entity Too Large로 막힐 수 있습니다.
Cloudflare 요청 크기 제한 문서: https://developers.cloudflare.com/workers/platform/limits/
그래서 Immich를 Cloudflare Tunnel 하나로만 쓰는 건 제 기준에서는 애매했습니다. 사진 위주라면 문제가 적지만, 요즘 휴대폰 영상은 100MB를 넘는 경우가 흔합니다.
운영 방식
장점
주의할 점
Immich 외부 접속을 Cloudflare Tunnel로만 사용
도메인 접속이 쉽고 포트포워딩이 필요 없음
100MB 초과 영상 업로드에서 413 오류가 날 수 있음
집 안에서는 LAN 주소로 직접 백업
대용량 영상 업로드가 안정적이고 빠름
외부에서는 별도 접속 경로가 필요함
외부 백업은 WARP 또는 VPN 경로로 분리
내부망 접근처럼 사용할 수 있어 대용량 업로드에 유리함
클라이언트 설정이 추가로 필요함
현재는 집 안에서는 Immich 앱이 로컬 주소를 보도록 두고, 밖에서는 조회나 가벼운 업로드만 Tunnel을 타게 나눴습니다. 외부에서 대용량 백업까지 해야 한다면 WARP나 VPN 계열을 함께 설계하는 쪽이 현실적입니다. 이 부분은 별도 Immich글에서 모바일 백업 기준으로 더 자세히 다룰 만했습니다.
Zero Trust Access로 관리 화면 보호하기
Tunnel을 열었다고 해서 모든 경로를 그대로 공개하고 싶지는 않았습니다. 특히 Immich admin, 서버 관리용 대시보드, 내부 도구처럼 자체 로그인이 있더라도 앞단에 한 겹 더 두는 편이 낫습니다.
Cloudflare Zero Trust의 Access 정책을 쓰면 특정 이메일이나 이메일 도메인 기준으로 인증 게이트를 붙일 수 있습니다. 공식 문서에서도 Access는 self-hosted application 앞에서 요청을 검사하고, 정책에 맞는 사용자만 통과시키는 방식으로 설명합니다.
주의할 점은 OTP를 아무 이메일에나 열어두지 않는 것입니다. 홈서버 관리 화면은 특히 Everyone 허용으로 두지 않는 것이 중요합니다.
정리
Cloudflare Tunnel은 홈서버 외부 접속을 만들 때 꽤 실용적이었습니다. 특히 공유기 포트포워딩 없이 도메인 기반 HTTPS 접속을 붙일 수 있다는 점이 가장 컸습니다. Rocky Linux 9에서도 RPM 저장소를 추가해 dnf install cloudflared로 관리하면 설치 흐름이 깔끔했고, systemd 등록 후 재부팅 복구까지 확인하니 운영 부담도 적었습니다.
다만 Immich처럼 대용량 업로드가 많은 서비스는 100MB 제한을 먼저 생각해야 합니다. 저는 외부 조회와 가벼운 접근은 Tunnel, 집 안 백업은 LAN 직접 연결, 관리 화면은 Zero Trust Access로 보호하는 식으로 역할을 나눴습니다.
홈랩에서는 한 가지 도구로 전부 해결하려 하기보다 노출을 줄이고 필요한 경로만 열어두는 구성이 오래 운영하기에 편했습니다.
Immich는 공식 문서 기준으로 docker compose 설치 흐름이 잘 정리되어 있습니다. 예전 자료에서는 pgvecto-rs DB 이미지를 쓰는 경우도 많았지만, 현재 공식 Compose 예시는 ghcr.io/immich-app/postgres 계열 이미지로 정리되어 있습니다. 이미 운영 중인 서버라면 새 Compose 파일을 그대로 덮기보다, 공식 업그레이드 문서를 먼저 확인하는 쪽이 안전합니다.
docker-compose.yml 구성
Immich는 기능이 많아 보여도 기본 구성은 비교적 단순합니다. 사진 업로드와 웹 화면을 담당하는 immich-server, 검색과 얼굴 인식에 쓰이는 machine-learning, 캐시용 redis, 데이터베이스가 함께 떠야 정상적으로 동작합니다.
Immich의 장점은 사진을 단순히 저장하는 데서 끝나지 않는다는 점입니다. 업로드한 사진을 기준으로 검색, 미리보기, 얼굴 인식이 돌아가면 구글포토를 쓰던 감각과 꽤 가까워집니다.
다만 immich-machine-learning 컨테이너는 생각보다 메모리를 사용합니다. 사진 수가 많고 CPU만으로 인덱싱을 돌리면 초반 며칠은 서버가 계속 바쁠 수 있습니다. N100 미니PC나 ARM 서버처럼 저전력 장비에서는 업로드 직후 결과를 기대하기보다, 밤새 천천히 처리하게 두는 편이 현실적입니다.
CPU 인덱싱 속도는 사진 해상도와 장비에 따라 차이가 큽니다. GPU 가속을 붙이면 빨라질 수 있지만, 홈서버에서는 전력과 발열도 함께 봐야 하므로 무조건 정답이라고 보기는 어렵습니다.
모바일 앱 백업 설정
서버가 올라오면 브라우저에서 아래 주소로 접속합니다.
text
http://서버IP:2283
외부에서 쓰려면 리버스 프록시와 HTTPS까지 붙이는 편이 좋습니다. 다만 집 안에서 먼저 테스트할 때는 2283 포트만으로도 충분합니다. 모바일 앱에서는 서버 URL을 넣고 로그인한 뒤 백그라운드 자동 백업을 켜면 됩니다.
처음부터 모든 앨범을 올리기보다는 카메라 앨범부터 시작하는 편이 좋습니다. 스크린샷이나 다운로드 폴더는 나중에 필요할 때 추가해야 정리가 덜 흐트러집니다.
스토리지 설계
사진 백업은 처음에는 100GB도 커 보이지만, 가족 단위로 몇 년 치를 모으면 금방 단위가 바뀝니다. 휴대폰 사진에 동영상까지 섞이면 1TB는 시작점에 가깝고, 장기 보관은 4TB 이상부터 여유가 생깁니다.
제품
장점
단점
구글 포토
앱 완성도와 검색이 좋고 관리 부담이 거의 없습니다
용량이 늘수록 비용이 계속 붙고 데이터 위치를 직접 통제하기 어렵습니다
Immich 셀프호스팅
원본 사진을 내 서버에 보관하고 백업 정책을 직접 정할 수 있습니다
서버 운영, 업데이트, 백업을 직접 챙겨야 합니다
Synology NAS
저장소 관리와 디스크 교체가 편하고 가족용 공유에 강합니다
초기 비용이 있고 Docker 성능은 모델에 따라 차이가 납니다
N100/N150 미니PC
전력 대비 성능이 좋아 Immich 서버용으로 무난합니다
디스크 베이를 따로 구성해야 해서 저장소 설계가 필요합니다
NAS HDD
대용량을 비교적 안정적으로 운용하기 좋습니다
SSD보다 느리며 DB 저장 위치로는 적합하지 않을 수 있습니다
개인적으로는 사진 원본은 NAS HDD에 두고, DB는 SSD에 두는 구성이 가장 무난해 보였습니다. Immich 공식 안내에서도 DB를 네트워크 공유에 두는 방식은 권장하지 않으니, 처음 설계할 때 저장 위치를 나눠두는 편이 좋습니다.
마지막으로 백업은 Immich 하나로 끝내지 않는 게 안전합니다. 서버에 원본이 있고, NAS나 외장하드에 한 벌 더 있으며, 정말 중요한 사진은 외부 저장소까지 두는 3-2-1 규칙을 기준으로 잡으면 복구 선택지가 남습니다. Immich는 단순히 구글포토 화면을 대신하는 도구라기보다, 내 사진 보관 방식을 다시 정리하게 만드는 홈서버 서비스에 가깝습니다.
이 경우 대부분 Open WebUI가 Ollama를 localhost로 찾고 있거나, 두 컨테이너가 같은 Docker 네트워크에 있지 않은 상황이었습니다.
사양별 체감 속도와 선택 기준
로컬 LLM은 설치보다 사양 선택에서 기대치를 맞추는 일이 더 중요합니다. 특히 CPU만 있는 서버와 GPU가 있는 서버는 체감 차이가 큽니다.
제품명
가격대
주요 특징
추천 대상
Oracle Cloud ARM Free Tier
무료 가능
비용 부담은 거의 없지만 LLM 추론은 느린 편
테스트용, 가벼운 모델 실험
Intel N100 미니 PC
10만~20만원대
전력 소모가 낮고 24시간 운영 부담이 적음
홈서버 입문, 문서 요약 위주
Ryzen 5급 미니 PC
30만~50만원대
CPU 추론 기준으로 N100보다 여유 있음
개인용 AI 서버, 여러 서비스 병행
RTX 3060 12GB 데스크톱
중고가 변동
VRAM 12GB로 7B급 모델 운용이 수월함
응답 속도 중시, 로컬 AI 주사용
RTX 4060 Ti 16GB 데스크톱
가격 변동 큼
VRAM 여유가 있어 모델 선택 폭이 넓음
장기적으로 로컬 LLM을 자주 쓸 사람
제휴 링크를 넣는다면 표의 제품명이나 가격대 옆에 붙이는 방식이 자연스럽습니다. 다만 서버 부품은 가격 변동이 심하므로, 글을 발행할 때 실제 판매가와 재고를 한 번 더 확인하는 편이 좋습니다.
마무리 운영 포인트
Rocky Linux 9에서 Ollama와 Open WebUI를 Docker로 묶으면 관리 자체는 단순합니다. 핵심은 Ollama 주소를 컨테이너 네트워크 기준으로 잡는 것, 그리고 firewalld와 SELinux를 Rocky 방식대로 처리하는 것입니다.
처음부터 큰 모델을 올리기보다 llama3.2 같은 모델로 접속과 응답 흐름을 먼저 확인하고, 그다음 하드웨어에 맞춰 모델을 바꾸는 순서가 덜 피곤했습니다. 로컬 AI는 한 번에 완성하는 서비스라기보다, 홈서버에 하나 얹어두고 천천히 손에 맞게 조정하는 쪽에 가깝습니다.
홈서버를 켜두고 나면 처음에는 파일 저장이나 개인 웹서비스 정도만 떠올리기 쉽습니다. 그런데 운영 시간이 쌓이면 매일 확인해야 하는 작업이 생각보다 많아집니다. 이때 자동화를 잘 잡아두면 서버를 들여다보는 시간이 줄고, 운영 부담도 꽤 가벼워집니다.
처음부터 거창한 시스템을 만들 필요는 없습니다. 직접 구성해보면 백업, 알림, 정리, 모니터링처럼 반복 주기가 분명한 작업부터 자동화하는 쪽이 체감이 큽니다.
예를 들어 매일 새벽 특정 폴더를 백업하고, 실패하면 텔레그램이나 디스코드로 알림을 받는 정도만 해도 충분히 실용적입니다. Oracle Cloud Free Tier 같은 ARM 서버, Synology NAS, Docker Compose 기반 홈랩에서도 이런 수준의 자동화는 비교적 부담 없이 시작할 수 있습니다.
먼저 해볼 만한 자동화 작업
자동화 후보는 많지만, 처음에는 실패해도 복구가 쉽고 성공하면 바로 편해지는 작업을 고르는 편이 좋습니다. 홈서버에서 자주 구성하는 흐름을 기준으로 정리하면 다음과 같습니다.
작업명
주요 역할
추천 도구
추천 대상
파일 백업 자동화
지정 폴더를 NAS, MinIO, 외장 스토리지로 주기 백업
rclone, restic, borg
사진·문서 보관이 많은 경우
컨테이너 업데이트 확인
Docker 이미지 새 버전 확인 및 알림
Watchtower, Diun
여러 서비스를 Docker로 돌리는 경우
서버 상태 알림
CPU, RAM, 디스크, 네트워크 상태 감시
Uptime Kuma, Netdata, Grafana
장애를 빨리 알고 싶은 경우
로그 정리
오래된 로그 압축·삭제
logrotate, cron
디스크 용량이 자주 줄어드는 경우
SSL 인증서 갱신
HTTPS 인증서 자동 갱신
Caddy, Traefik, Nginx Proxy Manager
외부 접속 서비스를 운영하는 경우
미디어 파일 정리
다운로드 파일명 정리, 폴더 이동
FileBot, Sonarr, Radarr
개인 미디어 서버를 쓰는 경우
사진 자동 분류
업로드 사진을 날짜별로 정리
Immich, PhotoPrism, Synology Photos
스마트폰 사진 백업이 많은 경우
정기 리포트 발송
서버 상태나 백업 결과를 메일로 전달
cron, shell script, Gotify
점검 기록을 남기고 싶은 경우
이 중 하나만 먼저 고른다면 백업 자동화가 가장 무난합니다. 홈서버는 결국 데이터를 오래 보관하는 장비에 가깝기 때문에, 서비스 편의 기능보다 백업 체계가 먼저 안정돼야 합니다.
백업은 성공 여부 확인까지 포함해야 합니다
백업 스크립트를 만들어두는 것만으로는 부족합니다. 중요한 건 백업이 실제로 성공했는지 확인하는 과정까지 자동화하는 것입니다.
예를 들어 rclone으로 MinIO나 NAS에 백업을 보낸다면, 단순 복사 명령만 cron에 넣기보다 실행 결과를 로그로 남기고 실패 시 알림을 보내는 방식이 좋습니다. restic이나 borg를 쓰면 스냅샷 기반으로 보관할 수 있어, 실수로 지운 파일을 되돌리기에도 편합니다.
이 설정은 매일 새벽 3시에 백업 스크립트를 실행하고 로그를 남기는 형태입니다. 여기에 스크립트 내부에서 실패 여부를 확인하고 알림까지 보내면 운영 부담이 확 줄어듭니다. 다만 실제 경로, 인증 정보, 저장소 주소는 환경마다 다르므로 그대로 복사하기보다 본인 서버 구조에 맞춰 조정해야 합니다.
컨테이너 업데이트는 자동 적용보다 알림이 먼저입니다
Docker Compose로 서비스를 여러 개 올려두면 업데이트 관리도 일이 됩니다. 그렇다고 모든 이미지를 자동으로 최신 버전으로 올리는 방식은 조심해야 합니다. 특히 데이터베이스, 인증, 리버스 프록시가 얽힌 서비스는 버전 변경만으로 설정이 깨질 수 있습니다.
그래서 처음에는 자동 업데이트보다 업데이트 알림 자동화를 먼저 두는 편이 낫습니다. Diun 같은 도구로 새 이미지가 나왔는지만 알려받고, 실제 반영은 주말이나 점검 가능한 시간에 직접 하는 방식입니다.
Watchtower도 편하지만, 개인 서비스가 여러 개 묶여 있다면 처음에는 모니터링 용도로만 써보는 것이 부담이 적습니다. 자동화의 목적은 손을 덜 대는 것이지, 문제가 생겼을 때 원인을 더 찾기 어렵게 만드는 것이 아닙니다.
알림 채널은 한곳으로 모으는 편이 좋습니다
홈서버 자동화가 늘어나면 알림도 함께 늘어납니다. 백업 성공, 백업 실패, 디스크 용량 부족, 서비스 다운, 인증서 갱신 결과가 각각 다른 곳으로 오면 알림을 확인하는 일 자체가 피곤해집니다.
이럴 때는 Gotify, Telegram Bot, Discord Webhook 중 하나를 정해 서버 알림을 한곳으로 모아두는 편이 관리하기 쉽습니다. 폐쇄적으로 쓰려면 Gotify가 깔끔하고, 외부에서도 바로 확인하려면 텔레그램이나 디스코드가 접근성이 좋습니다.
알림 기준도 너무 촘촘하게 잡을 필요는 없습니다. 성공 알림은 하루 1회 요약으로 묶고, 실패나 용량 부족처럼 바로 확인해야 하는 항목만 즉시 알림으로 보내는 정도가 적당합니다.
우선순위는 데이터 보호부터 잡습니다
처음 홈서버 자동화를 구성한다면 순서를 정해두는 것이 좋습니다. 제 기준에서는 데이터 보호 → 장애 확인 → 유지보수 절감 → 편의 기능 순서가 안정적입니다.
백업 자동화와 복구 테스트
디스크 용량, 서비스 다운 알림
로그 정리와 인증서 갱신
컨테이너 업데이트 확인
사진, 미디어, 다운로드 파일 정리
정기 리포트와 대시보드 구성
이 순서로 진행하면 서버 운영이 조금씩 손에 익습니다. 특히 복구 테스트는 한 번쯤 꼭 해보는 게 좋습니다. 백업 파일이 있어도 실제로 되돌려본 적이 없다면, 장애 상황에서 그 백업을 믿기 어렵습니다.
정리해두면 운영이 가벼워집니다
홈서버 자동화는 화려한 기능보다 반복 작업을 조용히 줄여주는 구성이 오래 갑니다. 백업, 알림, 모니터링, 정리 작업만 차근차근 묶어도 매번 서버에 접속해 확인하던 시간이 줄어듭니다.
처음부터 모든 것을 자동화하려고 하기보다, 지금 가장 자주 확인하는 작업 하나를 골라 cron이나 Docker Compose 기반으로 작게 붙여보면 됩니다. 그렇게 하나씩 쌓아두면 홈서버는 단순한 장비를 넘어, 생활 속에서 꾸준히 일해주는 개인 인프라에 가까워집니다.
로컬 LLM을 홈서버에 올려보려면 모델 이름보다 먼저 확인할 것이 있습니다. 내 장비에서 계속 켜둘 수 있는지, 그리고 한국어 질문에 대한 답변 품질이 크게 무너지지 않는지입니다.
Qwen과 Gemma는 로컬 실행 후보로 자주 언급되는 모델입니다. 다만 성격은 조금 다릅니다. Qwen은 코딩, 추론, 다국어 대응 쪽으로 폭넓게 확장하는 느낌이 강하고, Gemma는 구글 생태계 안에서 문서와 배포 흐름이 비교적 정돈된 편입니다.
홈서버 기준에서는 최고 성능보다 GGUF, Ollama, LM Studio, llama.cpp 같은 실행 환경에서 얼마나 쉽게 굴러가는지가 더 중요할 때가 많습니다. GPU 여유가 크지 않다면 4bit 양자화 모델부터 확인하는 쪽이 현실적입니다.
Qwen 쪽 인상
Qwen은 공식 블로그 기준으로 Qwen3에서 0.6B, 1.7B, 4B, 8B, 14B, 32B 같은 dense 모델과 MoE 모델을 공개했습니다. 공식 안내에서도 Ollama, LM Studio, MLX, llama.cpp 등을 로컬 사용 도구로 언급하고 있어 홈랩 환경과 잘 맞는 편입니다.
한국어 사용감은 모델 크기와 양자화 상태에 따라 차이가 납니다. 작은 모델은 빠르지만 긴 문맥을 이어가는 글쓰기나 복잡한 질문에서는 답변이 짧아지는 편입니다. 개인 서버에서도 어느 정도 활용성을 기대하려면 8B 이상부터 체감이 좋아지는 편입니다.
Gemma 쪽 인상
Gemma는 Google AI 문서 기준으로 Gemma 4가 E2B, E4B, 12B, 26B A4B, 31B 구성을 갖고 있습니다. 문서상으로는 텍스트뿐 아니라 이미지, 비디오, 일부 모델의 오디오 입력까지 확장되어 있고, 로컬 실행용 GGUF와 QAT 체크포인트도 안내되어 있습니다.
Gemma의 장점은 문서 흐름이 깔끔하다는 점입니다. 어떤 크기를 고르면 되는지, 양자화 모델을 어디서 받아야 하는지 찾기 편합니다. 다만 이전 Gemma 계열은 라이선스나 사용 조건 확인이 필요했기 때문에, 실제 배포 전에는 현재 모델 카드와 라이선스 문서를 다시 보는 것이 좋습니다.
Qwen과 Gemma 비교
모델
가격
주요 특징
추천 대상
Qwen
무료 공개 가중치 모델 중심
코딩, 추론, 다국어, 로컬 실행 도구 지원 폭이 넓음
홈서버에서 챗봇, 코딩 보조, RAG 실험을 함께 해보고 싶은 사람
Gemma
무료 공개 가중치 모델 중심
공식 문서, QAT, GGUF, 구글 생태계 연동이 잘 정리됨
안정적인 문서와 배포 경로를 따라 차근차근 구성하려는 사람
홈서버에서는 어떤 쪽이 편할까
직접 홈서버에 올린다고 생각하면, 처음부터 큰 모델을 고르기보다 작은 모델부터 확인하는 쪽이 덜 피곤합니다. CPU나 저전력 서버라면 Qwen 4B급, Gemma E2B/E4B급 양자화 모델부터 테스트하고, GPU 여유가 있으면 8B 이상으로 넘어가는 방식이 현실적입니다.
Oracle Cloud Free Tier ARM 같은 환경에서는 대형 모델 자체보다 API 서버, 벡터DB, 웹 UI를 함께 올릴 수 있는 균형이 더 중요합니다. Synology나 미니 PC도 마찬가지입니다. 모델 하나가 잘 돌아가더라도 메모리 여유가 부족하면 RAG나 웹 UI에서 금방 답답해질 수 있습니다.
정리
코딩 보조와 실험 폭을 넓게 가져가고 싶다면 Qwen, 문서와 배포 흐름을 따라 안정적으로 시작하고 싶다면 Gemma가 편합니다.
둘 다 로컬 LLM 입문용으로 충분히 의미가 있습니다. 다만 홈서버에서는 모델 이름만 보고 고르기보다 메모리, 양자화 포맷, 실행 도구 호환성을 먼저 맞춰보는 것이 시행착오를 줄이는 데 도움이 됩니다.
리눅스를 처음 데스크톱으로 쓰려는 분들이 가장 많이 부딪히는 지점은 성능보다 관리 방식입니다. 서버처럼 검은 터미널만 붙잡고 운영해야 한다고 생각하면 시작 전부터 부담이 커집니다. 하지만 요즘 리눅스 데스크톱은 생각보다 훨씬 친절합니다.
홈서버를 직접 굴리다 보면 SSH 접속, 패키지 업데이트, 로그 확인 같은 작업을 피하기 어렵습니다. 다만 처음부터 모든 작업을 명령어로 처리할 필요는 없습니다. 리눅스 데스크톱 환경을 올려두면 파일 관리, 네트워크 설정, 디스크 확인 같은 기본 작업을 화면에서 직접 확인하며 처리할 수 있습니다.
GNOME, KDE Plasma, Xfce 같은 데스크톱 환경은 윈도우를 써본 사람이라면 비교적 빠르게 익숙해질 수 있는 구조입니다. 설정 앱에서 와이파이, 사용자 계정, 디스플레이, 업데이트를 확인할 수 있고, 파일 탐색기에서 공유 폴더나 외장 디스크에 접근하기도 쉽습니다.
서버를 공부하려고 리눅스를 설치했는데 터미널 때문에 막히는 경우가 많습니다. 이럴 때 데스크톱 환경은 좋은 완충 장치가 됩니다. 명령어를 몰라도 시스템 상태를 눈으로 확인할 수 있다는 점이 초반 진입장벽을 낮춰줍니다.
홈서버 입문자에게 맞는 선택
홈서버 구축 관점에서 보면 리눅스 데스크톱은 “서버답지 않은 선택”이라기보다 관리 방식을 넓혀주는 선택에 가깝습니다. 예를 들어 Rocky Linux 9.x나 Ubuntu LTS 계열에 데스크톱 환경을 얹고, Docker Compose v2로 서비스를 관리하면 GUI와 터미널을 함께 사용할 수 있습니다.
NAS나 미니PC를 24시간 켜두는 환경이라면 화면을 항상 연결해둘 필요는 없습니다. 처음 설정할 때만 데스크톱으로 잡아두고, 어느 정도 익숙해진 뒤에는 SSH 접속 위주로 넘어가도 됩니다. 핵심은 처음부터 CLI만 고집하지 않아도 된다는 점입니다.
제품
장점
단점
Ubuntu Desktop LTS
자료가 많고 드라이버 지원이 좋아 입문자에게 부담이 적음
서버 용도로는 기본 설치 구성이 다소 무겁게 느껴질 수 있음
Linux Mint
윈도우와 비슷한 사용감이라 적응이 빠름
서버 운영 자료는 Ubuntu Server 기준보다 상대적으로 적음
Fedora Workstation
최신 커널과 패키지를 빠르게 경험할 수 있음
장기 운영보다는 업데이트 흐름을 꾸준히 따라가야 함
Rocky Linux 9.x + GUI
RHEL 계열 서버 환경과 가까워 운영 연습에 좋음
데스크톱 편의성은 Ubuntu 계열보다 덜 친절하게 느껴질 수 있음
그래픽 환경이 항상 낭비는 아닙니다
서버 운영을 조금 해본 분들은 데스크톱 환경을 올리면 리소스를 낭비한다고 말하기도 합니다. 틀린 말은 아닙니다. RAM이 1GB나 2GB 수준인 작은 VPS라면 GUI는 부담이 됩니다.
하지만 집에서 쓰는 미니PC, 남는 노트북, Synology 외 별도 테스트 장비처럼 자원이 어느 정도 있는 환경이라면 이야기가 달라집니다. 배우는 속도와 관리 편의성도 운영 비용의 일부로 봐야 합니다.
디스크 마운트가 꼬였을 때, 네트워크 연결을 확인할 때, Docker 볼륨 위치를 정리할 때 화면이 있으면 실수를 줄이기 쉽습니다. 터미널에서 lsblk, ip addr, journalctl을 하나씩 치는 방식도 중요하지만, 처음에는 GUI로 구조를 이해하고 필요한 순간에 명령어를 붙이는 흐름이 더 자연스럽습니다.
어디까지 데스크톱으로 관리할까
리눅스 데스크톱을 쓴다고 해서 모든 관리를 마우스로 끝낼 수 있는 건 아닙니다. Docker 컨테이너 재시작, 방화벽 설정, 서비스 로그 확인처럼 결국 터미널이 필요한 순간은 옵니다. 다만 그 시점이 꼭 설치 첫날일 필요는 없습니다.
처음에는 업데이트, 파일 복사, 원격 접속 설정, 브라우저에서 관리자 페이지 접속 정도를 데스크톱으로 처리해도 충분합니다. 이후 Portainer, CasaOS, Cockpit 같은 웹 기반 관리 도구를 붙이면 터미널 의존도는 더 줄어듭니다. 터미널을 완전히 피하기보다 천천히 익숙해지는 구조가 현실적입니다.
리눅스 데스크톱은 홈서버를 처음 만지는 사람에게 좋은 출발점이 될 수 있습니다. 서버 운영의 본질을 흐리는 선택이라기보다, 시스템을 눈으로 이해하고 실수를 줄이기 위한 발판에 가깝습니다. 어느 정도 익숙해진 뒤에는 필요한 서비스만 남기고 가볍게 운영하는 방향으로 바꿔도 늦지 않습니다.