13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] Docker

  • [Linux] cgroup vs namespace: 컨테이너 격리의 핵심 비교 분석

    [Linux] cgroup vs namespace: 컨테이너 격리의 핵심 비교 분석

    [리눅스 커널] cgroup vs namespace: 컨테이너 격리 핵심 비교

    컨테이너 기술을 조금만 깊게 파보면 결국 cgroup vs namespace 이야기로 귀결되더라고요. 저도 처음 Docker를 쓸 때는 그냥 “컨테이너는 가볍고 빠르다” 정도로만 이해했었는데, 실제로 장애를 따라가다 보니 왜 어떤 프로세스는 CPU를 독식하고, 왜 어떤 프로세스는 다른 프로세스 목록을 못 보는지 여기서 갈리더라고요. 쉽게 말해 namespace(네임스페이스, 리소스를 보이는 범위로 분리)는 “무엇을 볼 수 있느냐”를 나누고, cgroup(컨트롤 그룹, 자원 사용량을 제어하는 기능)은 “얼마나 쓸 수 있느냐”를 관리합니다. 이 차이를 이해하면 컨테이너 기술, 격리, 리눅스 커널의 구조가 한 번에 정리됩니다.

    실제로 홈랩에서 테스트 환경을 만들다가, 프로세스는 잘 분리됐는데 메모리 제한이 안 먹어서 삽질 좀 했습니다 ㅎㅎ 그때 확실히 느꼈어요. 컨테이너 격리는 한 가지 기능으로 되는 게 아니라, 여러 커널 기능을 조합해서 만들어지는 거였거든요.

    cgroup vs namespace 기반 컨테이너 격리 구조를 보여주는 리눅스 커널 아키텍처 이미지

    namespace와 cgroup이 각각 어떤 역할로 컨테이너 격리를 만드는지 보여주는 개요 이미지입니다.

    1. 왜 cgroup과 namespace를 같이 봐야 할까요?

    여기서 중요한 게 있어요. 많은 분들이 컨테이너를 “가벼운 VM”처럼 이해하시는데, 엄밀히 보면 다릅니다. VM은 하이퍼바이저 위에 게스트 OS가 따로 올라가고, 컨테이너는 호스트의 리눅스 커널을 공유합니다. 그러니 격리도 커널 기능에 의존할 수밖에 없죠.

    • namespace: 프로세스가 보는 세계를 분리합니다.
    • cgroup: 프로세스가 쓰는 자원을 제어합니다.
    • capabilities(리눅스 권한 비트 분리), seccomp(시스템 콜 필터링), LSM 계열 기능은 추가 보안 계층으로 붙습니다.

    즉, 컨테이너 기술에서 격리는 한 방에 끝나는 개념이 아니라 층층이 쌓이는 구조예요. 저도 처음엔 namespace만 알면 다 되는 줄 알았는데, 운영 환경에서는 cgroup 쪽을 훨씬 자주 보게 되더라고요. 특히 CPU 폭주나 메모리 OOM(Out Of Memory) 이슈는 거의 cgroup 쪽에서 원인을 찾게 됩니다.

    2. namespace(네임스페이스) 쉽게 이해하기

    쉽게 말해 namespace는 “같은 커널 위에 있지만 서로 다른 방에 들어가 있는 상태”를 만드는 기능입니다. 같은 호스트인데도 프로세스마다 보이는 PID, 네트워크 인터페이스, 마운트 포인트가 달라질 수 있어요.

    대표적인 namespace 종류

    • PID namespace: 프로세스 번호 공간을 분리합니다.
    • NET namespace: 네트워크 인터페이스, 라우팅 테이블, 포트를 분리합니다.
    • MNT namespace: 마운트 지점을 분리합니다.
    • UTS namespace: 호스트명, 도메인명 같은 시스템 식별 정보를 분리합니다.
    • IPC namespace: 프로세스 간 통신 자원을 분리합니다.
    • USER namespace: 사용자와 그룹 ID 매핑을 분리합니다.

    예를 들어 PID namespace 안에서는 프로세스가 자기 자신을 PID 1로 볼 수도 있어요. 컨테이너 안에서 <code>ps를 쳤을 때 호스트 전체 프로세스가 안 보이는 이유가 바로 이겁니다. 실제로 써보니까 이 개념 하나만 이해해도 “왜 컨테이너 안에서는 세상이 작아 보이는지”가 확 들어오더라고요.

    3. cgroup(컨트롤 그룹)은 뭐가 다를까요?

    namespace가 시야를 나눈다면, cgroup은 행동 한도를 정합니다. CPU를 얼마나 쓸지, 메모리를 얼마나 먹을지, I/O를 어느 정도까지 허용할지를 관리하는 쪽이죠. 그래서 cgroup은 격리라기보다 제어와 회계(accounting) 관점이 훨씬 강합니다.

    운영에서 흔히 보는 상황이 이거예요. 애플리케이션 하나가 메모리를 계속 먹습니다. namespace만 있으면 자기 공간 안에서만 보일 뿐이지, 호스트 메모리는 그대로 압박할 수 있거든요. 반대로 cgroup으로 제한을 걸어두면 그 프로세스 그룹은 정해진 범위를 넘기기 어려워집니다. 장애 대응할 때 이 차이가 꽤 크더라고요.

    항목 namespace cgroup
    주요 목적 리소스 가시성 분리 자원 사용량 제어 및 계측
    핵심 질문 무엇을 볼 수 있나? 얼마나 쓸 수 있나?
    예시 다른 PID/네트워크를 못 봄 CPU, 메모리 사용량 제한
    영향 범위 프로세스 관점의 논리적 격리 호스트 자원 배분 정책
    컨테이너에서의 역할 독립된 환경처럼 보이게 함 과도한 자원 사용을 막음

    한 줄 정리: namespace만 있으면 “따로 있는 것처럼 보이는 상태”이고, cgroup까지 있어야 “민폐를 덜 끼치는 상태”가 돼요. 이거 진짜 중요합니다.

    4. 실전 구현: namespace부터 직접 확인해보겠습니다

    제가 직접 해보니 추상 개념으로만 볼 때보다 unshare로 눈으로 확인하는 게 훨씬 빠르더라고요. 아래 예시는 리눅스에서 새로운 UTS, PID, mount namespace를 만들어보는 흐름입니다.

    1. 현재 호스트 이름과 프로세스 상태를 확인합니다.
    2. unshare로 새 namespace를 만듭니다.
    3. 새 환경 안에서 hostname과 프로세스 목록이 어떻게 달라지는지 봅니다.
    hostname
    ps -ef | head
    
    sudo unshare --uts --pid --mount --fork bash
    
    hostname container-lab
    mount -t proc proc /proc
    ps -ef
    hostname

    여기서 --fork를 주는 이유는 새 PID namespace 안에서 새 프로세스를 시작하기 위해서예요. 그리고 mount -t proc proc /proc를 안 하면 ps 출력이 기대와 다를 수 있거든요. 저도 처음엔 이걸 빼먹어서 “왜 분리 안 됐지?” 하고 한참 봤었습니다.

    cgroup vs namespace 실습 중 namespace 분리 셸 구성을 표현한 이미지

    namespace 실습 흐름과 분리된 셸 진입 과정을 보여주는 이미지입니다.

    현재 시스템의 namespace 확인

    lsns

    lsns를 보면 현재 시스템에 어떤 namespace가 잡혀 있는지 확인할 수 있어요. 컨테이너 런타임이 떠 있는 서버에서는 생각보다 다양한 namespace가 보이더라고요.

    5. 실전 구현: cgroup으로 자원 제한 걸어보기

    이제 cgroup입니다. 최근 리눅스 배포판은 보통 cgroup v2 기준으로 보는 게 편해요. 시스템마다 마운트 구조가 조금 다를 수는 있지만, 기본 개념은 비슷합니다. CPU와 메모리 제한을 설정할 수 있고, 프로세스를 특정 cgroup 디렉터리 아래로 넣어 관리하죠.

    mount | grep cgroup
    cat /sys/fs/cgroup/cgroup.controllers
    
    sudo mkdir /sys/fs/cgroup/demo-limit
    echo $$ | sudo tee /sys/fs/cgroup/demo-limit/cgroup.procs

    위처럼 현재 셸을 특정 cgroup에 넣을 수 있어요. 다만 실제 제한을 적용하려면 컨트롤러 활성화와 권한 구조를 이해해야 해서, 운영 서버에서는 systemd 기반 도구를 쓰는 편이 안전합니다.

    systemd-run으로 메모리 제한 테스트

    systemd-run --user --scope -p MemoryMax=200M -p CPUQuota=50% bash
    
    cat /sys/fs/cgroup/$(systemctl --user show --property=ControlGroup --value)/memory.max

    환경에 따라 사용자 세션에서 안 될 수도 있어요. 그런 경우는 시스템 범위에서 실행하거나 테스트 VM에서 보는 쪽이 낫습니다. 핵심은 cgroup이 프로세스를 안 보이게 만드는 기능이 아니라, 자원 사용 정책을 강제하는 기능이라는 점이에요.

    Docker로 보면 훨씬 익숙해요.

    docker run --rm -it --memory=256m --cpus=1 alpine sh
    
    cat /sys/fs/cgroup/memory.max 2>/dev/null || true
    cat /sys/fs/cgroup/cpu.max 2>/dev/null || true

    컨테이너 런타임은 이런 옵션을 받아 내부적으로 cgroup 설정과 namespace 구성을 함께 처리해요. 우리가 편하게 docker run 한 줄로 쓰는 뒤에서 리눅스 커널이 꽤 많은 일을 하는 셈이죠.

    6. cgroup vs namespace 비교를 실무 관점에서 정리해보면

    혹시 이런 경험 있으신가요? 컨테이너는 분명 분리돼 있는데, 한 컨테이너가 CPU를 잡아먹어서 같은 노드의 다른 워크로드까지 느려지는 상황 말이에요. 이럴 때 namespace를 아무리 잘 나눠도 해결이 안 됩니다. 반대로 cgroup만 있고 namespace가 약하면 프로세스 시야가 너무 넓어서 격리 체감이 떨어져요.

    • namespace가 강한 상황: 프로세스, 네트워크, 파일시스템 관점에서 독립된 환경처럼 보입니다.
    • cgroup이 강한 상황: noisy neighbor(시끄러운 이웃, 자원 독식 워크로드) 문제를 줄이기 좋습니다.
    • 둘 다 필요: 컨테이너 기술에서 실용적인 격리는 대부분 둘의 조합이에요.

    제가 홈랩 쿠버네티스 환경을 만질 때도 결국 보는 건 두 가지였어요. “이 파드는 무엇을 볼 수 있지?” 그리고 “이 파드는 얼마나 먹지?” 질문이 딱 namespace와 cgroup으로 나뉘더라고요.

    7. ⚠️ 주의사항과 트러블슈팅

    여기서부터는 제가 실제로 많이 헷갈렸던 부분입니다. 처음엔 개념보다 환경 차이 때문에 더 막히더라고요.

    1) ps 결과가 기대와 다를 때

    PID namespace를 만들었는데도 프로세스가 그대로 보이는 경우가 있어요. 보통 /proc를 새로 마운트하지 않아서 그렇습니다.

    mount -t proc proc /proc

    2) cgroup 디렉터리는 있는데 제한이 안 걸릴 때

    cgroup v1과 v2 차이, systemd 관리 방식, 권한 문제 때문일 수 있어요. 특히 배포판마다 기본 구성이 다르니 무작정 예전 블로그 예제를 복붙하면 안 맞는 경우가 있습니다. 저도 예전 자료 따라 했다가 파일 이름이 달라서 한참 헤맸습니다.

    3) 컨테이너 보안과 자원 제어를 같은 문제로 보면 꼬여요

    이건 실무에서 꽤 중요한 부분이에요.

    • namespace는 보이는 범위를 줄이는 쪽입니다.
    • cgroup은 성능 안정성과 자원 관리 쪽입니다.
    • seccomp, AppArmor, SELinux 같은 보안 계층은 또 별개입니다.

    즉, 보안 사고를 막는 이야기와 리소스 폭주를 막는 이야기를 한 덩어리로 보면 판단이 흐려집니다.

    4) USER namespace는 특히 신중하게 봐야 해요

    USER namespace는 루트 권한 매핑 문제와 연결되기 때문에 환경에 따라 정책 차이가 커요. 실습은 가능하지만, 운영 서버에서는 배포판 기본 정책과 런타임 설정을 반드시 같이 봐야 합니다.

    cgroup vs namespace 비교 중 cgroup v2 자원 제어 구조를 설명하는 이미지

    cgroup v2 구조와 자원 제한이 적용되는 핵심 지점을 시각화한 이미지입니다.

    8. 검증과 결과 확인

    설정은 했는데 실제로 격리가 됐는지 확인을 안 하면 의미가 없죠. 저는 보통 아래처럼 확인합니다.

    1. namespace 분리 여부 확인
    2. cgroup 제한 값 확인
    3. 실제 워크로드를 넣어 동작 확인
    lsns
    
    cat /proc/self/cgroup
    
    cat /sys/fs/cgroup/cpu.max 2>/dev/null || true
    cat /sys/fs/cgroup/memory.max 2>/dev/null || true

    Docker 환경이라면 다음도 자주 봐요.

    docker inspect <container_id>
    docker stats

    검증 포인트는 단순합니다.

    • 프로세스 목록이 호스트와 다르게 보이는가?
    • 호스트명이나 네트워크 인터페이스가 분리되어 보이는가?
    • 메모리/CPU 제한이 파일 시스템이나 런타임 정보에 반영되는가?
    • 부하를 줬을 때 제한 정책이 실제로 동작하는가?

    실제로 써보니까, 격리는 “설정했다”보다 “증명했다”가 더 중요하더라고요. 특히 장애 분석 문서 남길 때 이 확인 단계가 있어야 나중에 팀원과 같은 그림을 볼 수 있어요.

    cgroup vs namespace 검증 결과를 운영 화면처럼 보여주는 이미지

    격리 검증 결과를 확인하는 장면을 담은 이미지입니다.

    9. 정리: 컨테이너 기술에서 둘 중 뭐가 더 중요할까요?

    제 답은 늘 같습니다. 둘 중 하나가 아니라 둘 다예요. namespace는 컨테이너를 컨테이너답게 보이게 만들고, cgroup은 컨테이너를 운영 가능한 상태로 만들어줍니다. 하나는 시야를 분리하고, 다른 하나는 자원을 통제하죠.

    질문 봐야 할 기능 실무 해석
    왜 다른 프로세스가 안 보일까? namespace 격리된 실행 환경
    왜 메모리가 256MB 이상 못 올라갈까? cgroup 자원 제한 정책
    왜 한 컨테이너가 노드 전체를 먹지 못할까? cgroup 멀티테넌시 안정성
    왜 컨테이너 안 hostname이 다를까? namespace 독립된 시스템처럼 보이기

    저도 처음엔 cgroup vs namespace를 경쟁 관계처럼 외웠었는데, 실제로는 역할 분담에 더 가깝거든요. 그래서 컨테이너 기술을 공부할 때는 둘을 따로 암기하기보다, 하나의 워크로드가 커널 위에서 어떻게 분리되고 제한되는지 흐름으로 보는 게 훨씬 이해가 잘 됩니다.

    다음 글에서는 seccomp(시스템 콜 필터링)와 capabilities(권한 비트 세분화)까지 이어서, 왜 “컨테이너는 격리되지만 완전한 보안 경계로 보면 안 된다”는 말이 나오는지 다뤄볼 예정입니다. 이전 글에서 다룬 Docker 기본 구조와 함께 보시면 더 잘 연결되실 겁니다.

    cgroup vs namespace 차이를 한눈에 정리한 비교 인포그래픽 이미지

    cgroup과 namespace의 핵심 차이를 요약한 비교 인포그래픽 이미지입니다.

    자주 묻는 질문(FAQ)

    Q1. namespace만 있으면 컨테이너가 완성되나요?

    아니에요. namespace만으로는 자원 제한이 부족합니다. 실무에서는 cgroup, capabilities, seccomp 같은 요소가 함께 들어갑니다.

    Q2. cgroup은 보안 기능인가요?

    주된 목적은 자원 제어와 계측이에요. 보안에 간접적으로 도움이 될 수는 있지만, 보안 격리 그 자체로 보기엔 부족합니다.

    Q3. 리눅스 커널을 공유하면 위험하지 않나요?

    맞아요. 그래서 컨테이너는 VM과 다른 보안 모델을 가져요. 격리 수준과 운영 목적을 구분해서 설계해야 합니다.

    Q4. 쿠버네티스에서도 결국 같은 원리인가요?

    네, 상위 오케스트레이션이 붙어도 아래에서는 리눅스 커널의 namespace와 cgroup 같은 기능을 활용합니다.

  • [Game] 발헤임 서버 1년 운영 후기: Valheim 1.0 이후 비용, 안정성, 그리고 교훈

    [Game] 발헤임 서버 1년 운영 후기: Valheim 1.0 이후 비용, 안정성, 그리고 교훈

    발헤임 서버 1년 운영 후기: 비용, 안정성, 그리고 교훈

    안녕하세요, 13년차 인프라 엔지니어, ’13년차의 서버실’ 주인장입니다. 오늘은 제가 지난 1년 동안 직접 운영했던 발헤임 서버 운영 후기를 솔직하게 들려드리려고 합니다. 2026년 9월 기준으로는 Valheim 1.0과 Deep North 업데이트까지 반영해 내용을 다시 정리했습니다. 친구들과 함께 발헤임을 즐기는데, 호스트가 게임을 끄면 접속이 끊겨서 불편했던 경험 있으신가요? 저도 정확히 그런 이유로 ‘에이, 홈랩 장비도 놀고 있는데 발헤임 서버나 한번 돌려볼까?’ 하는 마음으로 시작했거든요.

    처음엔 단순한 게임 서버 하나라고 생각했는데, 1년 운영해보니 생각보다 얻는 게 훨씬 많더라고요. Valheim 서버 비용부터 Valheim 안정성, 게임 서버 관리, Valheim Dedicated Server 설정, 발헤임 크로스플레이 서버 운영 노하우까지, 인프라 엔지니어로서 배운 게 정말 많았습니다. 이 글이 홈 서버 구축에 관심 있는 분들께 작은 멘토링이 되기를 바랍니다.

    발헤임 전용 서버의 클라이언트-서버 아키텍처 다이어그램

    발헤임 서버, 이렇게 구성했어요! 대략적인 아키텍처 개념도입니다.

    왜 발헤임 전용 서버가 필요했나? (Valheim Dedicated Server, 왜?)

    발헤임은 스팀에서 친구들과 함께 즐기기 좋은 생존 크래프팅 게임입니다. 이제는 PC뿐 아니라 콘솔까지 크로스플레이가 확장되면서, 친구들 접속 환경이 더 다양해졌죠. 그런데 기본 멀티플레이 방식은 호스트가 곧 서버 역할을 합니다. 즉, 호스트가 게임을 종료하면 다른 친구들도 모두 접속이 끊긴다는 치명적인 단점이 있죠.

    이런 문제들을 해결하려면 전용 서버(Dedicated Server)가 사실상 정답입니다. 전용 서버는 호스트의 게임 플레이와 별개로 24시간 운영되며, 언제든 친구들이 접속해서 플레이할 수 있게 해줍니다. 저의 경우, 오랜만에 친구들과 함께 즐길 게임을 찾다가 발헤임에 빠졌고, 마침 홈랩(Home Lab)에 놀고 있던 미니 PC가 있어서 발헤임 서버를 직접 운영해보기로 결심했죠.

    발헤임 서버, 어떻게 작동하나? (How Valheim Server Works)

    발헤임 서버는 기본적으로 클라이언트-서버(Client-Server) 모델을 따릅니다. 게임 클라이언트가 서버에 접속하여 월드와 상호작용하는 방식이죠. 발헤임 전용 서버 프로그램은 스팀(Steam)에서 제공하며, 주로 SteamCMD라는 명령줄 도구를 통해 설치하고 업데이트합니다.

    2026년 9월 기준으로 공식 FAQ에서 안내하는 서버 플레이 규모는 여전히 1~10명입니다. 공식 문서가 전용 서버의 세부 CPU/RAM 권장 사양을 딱 잘라 공개하진 않지만, 실제 운영 체감상 바닐라 서버는 RAM 4GB로도 소규모 플레이가 가능했고, Valheim 1.0 서버나 모드 서버, 탐험이 많이 진행된 월드라면 8GB 이상을 잡는 편이 마음 편했습니다. 특히 월드 생성, 대형 건축물, 보스전, 모드 사용 시에는 CPU 단일 코어 성능과 디스크 I/O가 체감에 꽤 영향을 줍니다.

    1년간 운영한 발헤임 서버 구성 (My Valheim Server Setup)

    하드웨어 선택: 제가 직접 써본 경험 (Hardware Selection: My Experience)

    발헤임 서버는 인텔 NUC(Next Unit of Computing)와 비슷한 사양의 미니 PC에 구축했습니다. Intel i5 8세대 프로세서, RAM 16GB, NVMe SSD 256GB 정도였어요. 전력 소모가 적으면서도 발헤임 서버를 돌리기엔 충분한 성능이더라고요.

    운영체제는 제가 가장 익숙한 우분투 서버(Ubuntu Server)를 설치했습니다. 그리고 서버 관리의 편리성과 자원 격리를 위해 도커(Docker)와 도커 컴포즈(Docker Compose)를 활용했어요. 도커 컨테이너를 이용하면 서버 환경을 깔끔하게 유지하고, 나중에 다른 게임 서버를 추가하거나 옮길 때도 훨씬 수월하거든요.

    핵심적인 docker-compose.yml 파일은 대략 이런 모습이었습니다. 2026년 기준 Docker Compose v2에서는 최상단 version 필드를 굳이 넣지 않는 구성이 더 자연스럽고, 공식 전용 서버 문서 기준 기본 포트는 UDP 2456과 2457입니다. 예전 글이나 일부 이미지에서는 2458까지 함께 여는 예제가 많았지만, 지금 새로 구성한다면 먼저 2456, 2457을 정확히 열고, 사용하는 이미지나 플러그인이 추가 포트를 요구할 때만 확장하는 식으로 접근하는 게 깔끔합니다.

    services:
      valheim-server:
        image: lloesche/valheim-server
        container_name: valheim-server
        cap_add:
          - SYS_NICE
        ports:
          - "2456:2456/udp"
          - "2457:2457/udp"
        environment:
          - SERVER_NAME=MyValheimServer
          - WORLD_NAME=MyWorld
          - SERVER_PASS=YourPassword
          - SERVER_PUBLIC=1
          - SERVER_ARGS=-crossplay
          - RESTART_IF_UPDATE=1
          - RESTART_CRON=0 3 * * *
        volumes:
          - ./valheim-data:/config/valheim
        restart: unless-stopped
    

    그리고 외부에서 서버에 접속할 수 있도록 포트 포워딩(Port Forwarding)과 방화벽(Firewall) 설정이 필수였습니다. 다만 크로스플레이 백엔드(PlayFab)를 쓰는 경우에는 공식 가이드 기준 라우터 포트 포워딩 없이도 접속이 가능하다는 점이 달라졌습니다. 스팀 유저만 받을 거라면 Steam 백엔드와 포트 포워딩 조합이 단순하고, Xbox·PlayStation 5·Nintendo Switch 2 유저까지 같이 받을 계획이라면 -crossplay 옵션을 검토하는 게 좋습니다.

    # Steam 백엔드 기준 UFW 방화벽 설정 예시
    sudo ufw allow 2456/udp
    sudo ufw allow 2457/udp
    sudo ufw enable
    

    도커 컴포즈로 Valheim 서버를 띄운 모습입니다. 설정 파일 하나로 모든 걸 관리할 수 있어 정말 편하더라고요.

    초기 설정과 삽질 경험 (Initial Setup and Troubleshooting)

    처음 서버를 띄울 때는 역시나 삽질의 연속이었습니다. 가장 많이 겪었던 문제는 방화벽과 포트 포워딩 설정이었어요. 라우터에서 설정을 잘못했거나, UFW에서 특정 포트를 열어주지 않아서 ‘친구들이 접속이 안 돼요!’라는 비명을 여러 번 들었거든요. 로그(Log)를 꼼꼼히 확인하고, ss 명령어로 포트가 제대로 열려있는지 확인하는 게 중요하더라고요.

    또한, 발헤임 월드 데이터는 정말 소중하잖아요? 처음에 백업 설정을 제대로 안 해놨다가 혹시 모를 상황에 대비하기 위해 별도의 백업 스크립트를 만들고 크론탭(Crontab)에 등록했습니다. Valheim 공식 서버 옵션에도 -saveinterval, -backups, -backupshort, -backuplong 같은 백업 관련 옵션이 있으니, 컨테이너 이미지의 자체 백업 기능과 함께 꼭 확인해두는 걸 추천합니다.

    발헤임 서버 안정적인 운영을 위한 삽질 노트 (Troubleshooting for Stable Operation)

    서버 업데이트의 늪 (The Pitfalls of Server Updates)

    게임 서버 운영에서 가장 번거로운 것 중 하나가 바로 업데이트(Update)입니다. 발헤임 게임 클라이언트가 업데이트되면, 서버도 반드시 업데이트해야 호환성 문제가 생기지 않아요. 특히 2026년 9월 Valheim 1.0 출시 직후에는 1.0.10, 1.0.12 같은 핫픽스가 빠르게 이어졌고, 플랫폼별 반영 시점이 살짝 달라질 수 있어 접속 문제를 확인하는 루틴이 더 중요해졌습니다.

    그래서 저는 도커 이미지에 내장된 자동 업데이트 기능을 활용하거나, 직접 셸 스크립트(Shell Script)를 짜서 서버를 정지하고, 업데이트한 뒤 다시 시작하는 과정을 자동화했습니다. 새벽 시간대에 자동 재시작 및 업데이트를 설정하면 친구들의 플레이에 방해되지 않으면서도 항상 최신 버전을 유지할 수 있더라고요. 이런 자동화는 인프라 엔지니어의 기본 소양이기도 합니다!

    예상치 못한 비용, 전력 소모 (Unexpected Costs: Power Consumption)

    홈 서버 구축의 가장 큰 장점은 초기 구축 후 운영 비용이 적다는 거지만, 숨겨진 비용이 있습니다. 바로 전기세입니다. 아무리 저전력 미니 PC라고 해도 24시간 365일 가동하면 무시할 수 없는 수준이 되거든요. 제가 사용한 미니 PC는 대략 10~20W 정도의 전력을 소모했고, 한 달 기준으로 단순 계산하면 약 7.2~14.4kWh 정도입니다. 실제 전기요금은 누진 구간과 가정 전체 사용량에 따라 달라지니, 본인 집의 전기요금 단가로 다시 계산하는 게 정확합니다.

    물론 클라우드 서버는 월정액 비용이 명확하지만, 홈 서버는 초기 투자 비용과 전기세라는 변수가 있죠. Valheim 서버 비용을 제대로 따져볼 때는 이런 부분까지 고려해야 합니다.

    네트워크 안정성 (Network Stability)

    Valheim 안정성에 있어 또 다른 중요한 요소는 바로 네트워크입니다. 우리 집 인터넷 회선이 얼마나 안정적인지, 특히 업링크(Uplink) 속도가 충분한지가 관건이거든요. 친구들이 많아지면 서버에서 클라이언트로 보내는 데이터 양도 늘어나니까요.

    다행히 저는 기가 인터넷을 사용하고 있어서 큰 문제는 없었지만, 인터넷 서비스 제공업체(ISP)의 네트워크가 불안정하거나, 공유기가 오래되어서 성능이 좋지 않으면 게임 렉(Lag)의 원인이 될 수 있습니다. 또한, 유동 IP 주소를 사용하는 경우, DDNS(Dynamic DNS) 서비스를 활용하여 IP 주소가 바뀌어도 항상 같은 도메인으로 접속할 수 있도록 설정하는 것도 중요합니다. 저는 DuckDNS 같은 무료 DDNS 서비스를 이용했어요.

    1년 운영, 그래서 어땠나? (1 Year of Operation: The Verdict)

    비용 분석 (Cost Analysis)

    제가 1년 동안 발헤임 전용 서버를 운영하면서 체감한 비용은 다음과 같습니다. 2026년 9월 기준으로 클라우드 예시는 AWS t3.small과 GCP e2-small의 온디맨드 컴퓨트 비용을 기준으로 다시 봤습니다. 실제 청구액은 리전, 환율, 부가세, 디스크, 스냅샷, 네트워크 트래픽에 따라 달라집니다.

    항목 홈 서버 (미니 PC 기준) 클라우드 서버 (가상)
    초기 투자 비용 약 30~50만원 (NUC/중고 PC) 0원 (인스턴스 생성 비용만)
    월 운영 비용 약 5천원 ~ 1만 5천원 (전기 사용량과 환경에 따라 변동) 약 2만원 ~ 4만원 (소형 인스턴스, 디스크, 환율, 세금 포함 가정)
    총 1년 운영 비용 (대략) 약 36만원 ~ 68만원 약 24만원 ~ 48만원

    위 표는 대략적인 비교입니다. 초기 투자 비용을 포함하면 홈 서버가 더 비싸 보일 수 있지만, 장기적으로 보면 클라우드 서버는 매달 고정 비용이 발생하므로 특정 시점 이후에는 홈 서버가 더 저렴해질 수 있습니다. 특히 저는 이미 홈랩 장비가 있었으니, 추가적인 초기 투자 비용은 거의 없었다고 볼 수 있어요. 결국 Valheim 서버 비용은 사용 환경과 기간에 따라 달라질 수 있다는 거죠.

    발헤임 서버 1년 운영 성과 대시보드

    1년 동안의 발헤임 서버 운영 결과, 대시보드로 한눈에 확인!

    Valheim 안정성 평가 (Stability Evaluation)

    1년 동안 발헤임 서버를 운영하면서 Valheim 안정성은 정말 만족스러웠습니다. 예상치 못한 다운타임(Downtime)은 거의 없었고, 게임 업데이트 시점 외에는 서버가 특별한 문제 없이 잘 돌아갔어요. 친구들도 “야, 너네 서버는 진짜 끊길 일이 없더라!” 라며 만족감을 표현해 주더라고요. 칭찬 들으면 인프라 엔지니어는 행복합니다.

    주기적인 백업 덕분에 만약의 사태에도 대비할 수 있었어요. 한번은 실수로 서버를 강제 종료했는데, 백업해둔 데이터를 활용해서 빠르게 복구할 수 있었습니다. 이 경험을 통해 다시 한번 백업의 중요성을 뼈저리게 느꼈죠.

    2026년 9월 업데이트: Valheim 1.0과 Deep North 이후 바뀐 점

    이 글을 처음 쓴 2026년 6월 이후 가장 큰 변화는 단연 Valheim 1.0 정식 출시입니다. Iron Gate는 2026년 9월 9일 Valheim 1.0을 출시했고, 신규 바이옴 Deep North, 40개 이상의 신규 무기, 신규 방어구, 건축물, 음식, 재료, 업적, UI 개선, Unity 엔진 업그레이드 등을 추가했습니다. 공식 패치 노트는 Valheim 1.0 Has Arrived에서 확인할 수 있습니다.

    서버 운영자 입장에서 중요한 변화는 세 가지입니다. 첫째, 기존 월드도 계속 사용할 수 있지만, 이미 탐험한 지역에는 새 바이옴 콘텐츠가 정상적으로 생성되지 않을 수 있어 새 월드 시작이 권장됩니다. 둘째, 1.0 직후에는 모드 호환성이 깨질 수 있으니 모드 서버는 업데이트 전 백업과 테스트 서버 검증이 필수입니다. 셋째, 공식 가이드 기준 -crossplay 옵션을 쓰면 PlayFab 백엔드로 동작해 여러 플랫폼 유저가 접속할 수 있고, Steam 백엔드를 쓸 때와 네트워크 설정 방식이 달라집니다.

    정리하면, 2026년 9월 이후 새로 발헤임 전용 서버를 만든다면 저는 이렇게 권합니다. 바닐라 기준으로 먼저 새 월드를 만들고, 자동 백업을 걸고, 친구들의 플랫폼을 확인한 뒤 Steam 전용 서버로 갈지 크로스플레이 서버로 갈지 결정하세요. 그리고 업데이트 직후에는 바로 운영 서버에 반영하기보다 백업을 만든 다음 짧게라도 접속 테스트를 해보는 편이 좋습니다.

    발헤임 서버 운영을 통해 얻은 교훈과 다음 스텝 (Lessons Learned and Next Steps)

    발헤임 전용 서버 1년 운영은 저에게 정말 많은 것을 가르쳐주었습니다. 단순히 게임 서버 하나를 돌리는 것을 넘어, 실제 서비스와 유사한 환경에서 인프라 관리의 여러 측면을 경험할 수 있었거든요.

    • 자동화의 중요성: 반복되는 작업은 무조건 자동화해야 합니다. 업데이트, 백업 등은 스크립트와 스케줄러(Scheduler)를 활용하면 시간을 크게 절약할 수 있어요.
    • 모니터링의 필요성: 서버의 CPU, RAM 사용률, 네트워크 트래픽 등을 주기적으로 모니터링해야 이상 징후를 빠르게 감지하고 대응할 수 있습니다.
    • 백업은 생명: 어떤 상황에서도 데이터를 잃지 않도록 데이터 백업(Data Backup) 전략을 철저히 세워야 합니다.
    • 업데이트 검증: Valheim 1.0처럼 큰 업데이트가 있을 때는 운영 월드에 바로 적용하기 전 백업과 테스트 접속을 먼저 해야 합니다.
    • 비용 효율성 고려: 홈 서버와 클라우드 서버 각각의 장단점을 명확히 파악하고, 자신의 예산과 목적에 맞는 최적의 선택을 해야 해요.

    이번 경험을 통해 홈 서버 구축과 게임 서버 관리에 대한 자신감이 많이 붙었습니다. 다음에는 마인크래프트(Minecraft)나 ARK: Survival Ascended 같은 다른 게임 서버도 한번 돌려볼까 생각 중이에요. 혹시 여러분도 직접 게임 서버를 운영해보고 싶으시다면, 주저하지 말고 도전해 보세요! 저의 발헤임 서버 운영 후기가 여러분의 성공적인 서버 구축에 작은 도움이 되기를 바랍니다.

    홈 서버 vs 클라우드 서버 비교 인포그래픽

    홈 서버 vs 클라우드 서버, 어떤 게 더 좋을까요? 장단점을 비교해봤습니다.

    🔄 마지막 업데이트: 2026년 09월

  • [NAS] OpenMediaVault에 Immich 구축 6개월 사용기: 자가 호스팅 사진 관리의 명과 암

    [NAS] OpenMediaVault에 Immich 구축 6개월 사용기: 자가 호스팅 사진 관리의 명과 암

    OpenMediaVault에 Immich 구축 6개월 사용기: 자가 호스팅 사진 관리의 명과 암

    안녕하세요, 13년차 서버실입니다. 홈랩을 운영하며 이것저것 시도하는 게 제 낙인데요. 오늘은 많은 분들이 관심을 가지시는 자가 호스팅 사진 관리 솔루션, Immich를 OpenMediaVault(OMV)에 구축하고 6개월간 사용해 본 경험을 솔직하게 공유해 보려 합니다. 직접 써보니 정말 편한 부분도 많았지만, 예상치 못한 문제점들도 꽤 있더라고요. 이번엔 제 경험을 바탕으로 명과 암을 낱낱이 파헤쳐 보겠습니다.

    OpenMediaVault와 Immich를 활용한 홈랩 사진 관리 아키텍처 개요

    Immich와 OpenMediaVault를 활용한 전체 홈랩 사진 관리 아키텍처 개요

    왜 자가 호스팅 사진 관리인가? 🤔

    스마트폰 용량은 늘 부족하고, 사진은 기하급수적으로 늘어나죠. 클라우드 서비스는 편리하지만, 월마다 나가는 비용 부담이나 개인 정보 유출에 대한 걱정에서 자유롭지 못합니다. 특히 소중한 사진 데이터가 서비스 제공 업체의 정책 변화나 개인정보 유출 사고로 날아갈까 봐 불안한 마음, 다들 한 번쯤은 느껴보셨을 겁니다. 저도 그랬어요. 그래서 자가 호스팅 사진 관리, 특히 Immich 같은 오픈소스 솔루션에 눈을 돌리게 되었습니다. 내 손안의 작은 클라우드, 이게 가능하다는 게 신기하더라고요.

    Immich, 뭐가 그렇게 좋은데? 💡

    Immich는 Google Photos와 유사한 기능을 제공하는 오픈소스 사진 백업 및 관리 솔루션이에요. 핵심은 내 서버에 직접 설치해서 사용한다는 점이죠. 주요 기능들을 살펴보면:

    • 자동 백업: 스마트폰 사진을 자동으로 서버에 백업해 줘요. Google Photos의 자동 백업 기능과 거의 똑같다고 보시면 됩니다.
    • AI 기반 기능: 사진 내 객체 인식, 얼굴 인식, 중복 사진 제거 등 강력한 AI 기능을 제공합니다. 이게 또 은근히 편하더라고요.
    • 웹 UI & 모바일 앱: 깔끔한 웹 인터페이스와 함께 iOS, Android 모바일 앱을 지원해서 언제 어디서든 사진에 접근하고 관리할 수 있어요.
    • 다양한 포맷 지원: JPG, PNG뿐만 아니라 RAW 파일, 비디오 파일도 지원합니다.

    이런 강력한 기능들을 무료로, 내 마음대로 사용할 수 있다는 점이 Immich의 가장 큰 매력이에요. 물론, 이걸 구현하기 위해 몇 가지 기술적인 장벽을 넘어야 하긴 합니다.

    OpenMediaVault(OMV) 위에 Immich 올리기 🛠️

    저는 NAS(Network Attached Storage) 솔루션으로 OpenMediaVault(OMV)를 사용하고 있어요. OMV는 Debian 기반의 NAS 운영체제로, 웹 UI를 통해 스토리지 관리, 사용자 관리, 다양한 플러그인 설치 등을 쉽게 할 수 있게 해줍니다. Immich는 Docker 컨테이너로 배포되기 때문에 OMV의 Docker 플러그인과 함께라면 설치가 한결 수월합니다.

    1단계: OpenMediaVault 준비

    OMV가 설치되어 있고, Docker 플러그인이 활성화된 상태여야 해요. 만약 Docker 플러그인이 없다면, OMV 웹 UI의 ‘플러그인’ 메뉴에서 설치해 주세요. 그 후, Immich 데이터를 저장할 볼륨(Volume)을 위한 디스크나 파티션을 준비하고 OMV에서 파일 시스템으로 마운트해 두는 게 좋아요. 저는 `/srv/dev-disk-by-uuid/<UUID>/immich` 경로에 데이터를 저장하도록 구성했습니다.

    2단계: Immich Docker Compose 설정

    Immich는 Docker Compose를 사용하여 쉽게 배포할 수 있어요. GitHub 저장소에 예제 `docker-compose.yml` 파일이 제공되니 이를 활용하는 게 좋습니다. 저는 다음과 같이 설정을 구성했습니다.

    version: "3.8"
    
    services:
      immich-server:
        image: ghcr.io/immich-app/immich-server:latest
        container_name: immich_server
        ports:
          - "3001:3001"
        volumes:
          - ./library:/usr/src/app/upload
        environment:
          - DB_HOSTNAME=immich_db
          - DB_USERNAME=immich
          - DB_PASSWORD=your_strong_password
          - DB_NAME=immich
          - REDIS_HOSTNAME=immich_redis
        depends_on:
          - immich-db
          - immich-redis
        restart: unless-stopped
    
      immich-ml:
        image: ghcr.io/immich-app/immich-ml:latest
        container_name: immich_ml
        volumes:
          - ./model-cache:/cache
        environment:
          - TRANSFORMERS_CACHE=/cache
        restart: unless-stopped
    
      immich-db:
        image: postgres:15
        container_name: immich_db
        volumes:
          - ./postgres:/var/lib/postgresql/data
        environment:
          - POSTGRES_USER=immich
          - POSTGRES_PASSWORD=your_strong_password
          - POSTGRES_DB=immich
        restart: unless-stopped
    
      immich-redis:
        image: redis:7-alpine
        container_name: immich_redis
        restart: unless-stopped
    
    networks:
      default:
        name: immich_network
    

    주의: 위 설정에서 <UUID> 부분은 실제 OMV에서 마운트한 디스크의 UUID로 변경해야 합니다. 또한, `your_strong_password` 부분은 복잡하고 안전한 비밀번호로 바꿔주세요. 특히 AI 기능(얼굴 인식, 객체 인식)을 사용하려면 `immich-ml` 서비스가 필수이니까 꼭 포함시켜야 해요. 데이터베이스 비밀번호는 모든 컨테이너에서 동일하게 설정해야 합니다.

    3단계: Docker Compose 실행

    OMV의 SSH 기능을 활성화하거나, Docker 플러그인에서 제공하는 ‘Compose’ 기능을 사용하여 위 내용을 `docker-compose.yml` 파일로 저장한 후 실행해요. 저는 SSH로 접속하여 해당 디렉토리에서 docker compose up -d 명령어를 실행했습니다.

    OpenMediaVault Docker 플러그인에서 Immich 컨테이너 실행 모습

    OpenMediaVault에서 Docker 플러그인을 통해 Immich 컨테이너가 실행되고 있는 모습

    컨테이너가 모두 정상적으로 실행되면, 웹 브라우저에서 http://<OMV IP 주소>:3001 으로 접속하여 Immich 초기 설정을 진행할 수 있어요. 처음에는 관리자 계정을 생성하고, 이후 사용자 계정을 추가하며 사진을 업로드하면 됩니다.

    6개월간 사용하며 겪은 명과 암 ⛰️

    6개월간 Immich를 사용하면서 느낀 점들을 솔직하게 말씀드리겠습니다.

    ✨ 명 (장점)

    • 뛰어난 자동 백업 및 동기화: 스마트폰에서 찍은 사진이 실시간으로 서버에 백업되는 경험은 정말 혁신적이었어요. 용량 걱정 없이 마음껏 사진을 찍을 수 있게 되었죠.
    • 강력한 AI 기능: 사진 검색 시 객체나 장소로 검색하는 기능은 정말 편리했습니다. 잃어버렸던 사진을 찾거나 특정 테마의 사진을 모아볼 때 유용하더라고요. 중복 사진 제거 기능도 꽤 정확해서 스토리지 공간을 절약하는 데 큰 도움이 되었어요.
    • 깔끔한 UI/UX: 웹 인터페이스와 모바일 앱 모두 직관적이고 사용하기 편리했습니다. Google Photos에 익숙하다면 금방 적응할 수 있어요.
    • 오픈소스의 자유로움: 비용 부담 없이 원하는 대로 커스터마이징하고 관리할 수 있다는 점이 가장 큰 매력이에요.

    ⚠️ 암 (단점 및 주의사항)

    • 초기 설정의 복잡함: Docker, Docker Compose, 네트워크 설정 등 기본적인 이해가 없다면 설치 과정에서 어려움을 겪을 수 있어요. 저도 처음에는 Docker Compose 파일 설정 때문에 몇 번을 헤맸습니다.
    • 리소스 요구량: Immich는 AI 기능 등을 포함하여 꽤 많은 시스템 리소스(CPU, RAM)를 요구합니다. 특히 사진을 대량으로 업로드하거나 AI 분석을 실행할 때 서버 부하가 체감될 정도였어요. 저사양 홈랩 서버에서는 성능 저하가 발생할 수 있으니까 주의해야 합니다.
    • 업데이트 시 주의 필요: Immich는 활발하게 개발되고 있어 업데이트가 잦은 편입니다. 업데이트 과정에서 데이터베이스 스키마 변경 등으로 인해 문제가 발생할 수 있어서 항상 백업 후 업데이트하는 습관이 정말 중요해요. 저도 한 번 업데이트 후에 DB 연결에 문제가 생겨 잠시 당황했던 경험이 있습니다.
    • 안정성 이슈 (가끔): 가끔 예상치 못한 오류나 컨테이너 재시작이 필요한 경우가 있었어요. 특히 대규모 파일 업로드나 백업 작업 중에 발생하면 좀 당황스럽더라고요.
    • 데이터 무결성 책임: 모든 데이터 관리는 사용자 본인의 책임입니다. 백업, 스토리지 관리 등 모든 것을 직접 신경 써야 해요. 클라우드 서비스처럼 자동화된 백업/복구 시스템이 기본 제공되는 건 아니니까요.
    Immich 대시보드: 사진 업로드 및 AI 분석 진행 상황

    Immich 대시보드에서 사진 업로드 진행 상황과 AI 분석 상태를 보여주는 화면

    트러블슈팅: 흔히 겪는 문제들 🚨

    6개월간 사용하면서 몇 가지 문제에 부딪혔고, 이를 해결했던 경험을 공유합니다.

    • 문제 1: 컨테이너 재시작 후 DB 연결 실패
    • 원인: Immich 서버 컨테이너가 DB 컨테이너보다 먼저 시작되면서 발생할 수 있어요.
    • 해결책: `docker-compose.yml` 파일에서 `depends_on` 설정을 명확히 하고, Immich 서버 컨테이너에 재시도 로직을 추가하거나, 컨테이너 재시작 후 잠시 기다렸다가 수동으로 재시작하는 방법이 있습니다. 저는 `depends_on` 설정을 활용했어요.
    • 문제 2: 사진 업로드가 간헐적으로 실패
    • 원인: 서버 리소스 부족, 네트워크 불안정, 혹은 Immich 자체의 버그일 수 있습니다.
    • 해결책: 서버의 CPU, RAM 사용량을 확인하고, 필요하다면 리소스를 증설하거나 백업/AI 분석 작업 시간을 조정했어요. 네트워크 상태도 점검하고, Immich의 최신 버전을 사용하며 커뮤니티 피드백을 확인하는 것이 좋습니다.
    • 문제 3: AI 기능 (얼굴 인식 등)이 제대로 동작하지 않음
    • 원인: AI 모델 다운로드 실패, 설정 오류, 또는 리소스 부족으로 인한 백그라운드 작업 지연이에요.
    • 해결책: Immich의 `docker-compose.yml` 파일에서 `immich-ml` 서비스와 관련 볼륨 설정을 확인하고, 필요한 경우 `docker compose down` 후 `docker compose pull immich-ml` 명령어로 이미지를 최신 버전으로 다시 받아준 후 `docker compose up -d`로 재시작했어요. 서버 리소스가 충분한지 다시 한번 확인하는 것도 정말 중요합니다.

    결론: 6개월간의 자가 호스팅 사진 관리 여정 📝

    OpenMediaVault 위에 Immich를 구축하여 6개월간 사용해 본 결과, 자가 호스팅 사진 관리 솔루션으로서 Immich는 충분히 매력적이고 강력한 대안이라고 생각합니다. 특히 Google Photos의 편리함에 익숙하지만, 개인 정보 보호나 비용 절감을 원하는 분들에게는 최고의 선택지가 될 수 있어요.

    하지만 만능은 아닙니다. 초기 설정의 장벽, 시스템 리소스 요구량, 업데이트 시의 주의, 그리고 데이터 관리에 대한 전적인 책임 등 고려해야 할 부분들이 분명히 있거든요. 마치 잘 길들여진 애완동물처럼, 꾸준한 관심과 관리가 필요한 셈이죠.

    Immich 사진 갤러리 보기와 검색 기능 비교 인포그래픽

    Immich의 사진 갤러리 보기와 검색 기능을 비교하는 인포그래픽

    만약 여러분이…

    • 기술적인 도전을 즐기시고,
    • 직접 시스템을 구축하고 관리하는 것을 좋아하며,
    • 개인 데이터의 프라이버시와 통제권을 최우선으로 생각한다면,

    Immich는 분명 여러분의 홈랩에 훌륭한 추가가 될 거예요. 처음에는 조금 어렵게 느껴질 수 있지만, 한번 구축해두면 그 편리함에 만족하실 겁니다. 저도 앞으로도 Immich를 계속 사용하며 홈랩 사진 관리의 여정을 이어갈 생각이에요.

    다음 글에서는 Immich의 백업 및 복구 전략에 대해 좀 더 자세히 다뤄보도록 하겠습니다. 감사합니다!

  • [NAS] OMV와 Immich 연동: 구글 포토 대안, 실제 구축 가이드

    [NAS] OMV와 Immich 연동: 구글 포토 대안, 실제 구축 가이드

    [NAS] OMV와 Immich 연동: 구글 포토 대안, 실제 구축 가이드

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 많은 분들이 고민하시는 구글 포토(Google Photos) 대안에 대한 이야기를 해볼까 합니다. 특히 저처럼 홈랩(Homelab)을 운영하며 데이터 주권에 관심이 많으신 분들이라면 더욱 공감하실 거예요.

    아마 많은 분들이 구글 포토의 편리함 때문에 사진 백업에 사용하셨을 겁니다. 저도 그랬거든요. 그런데 정책이 바뀌면서 무료 용량이 제한되고, 내 소중한 사진들이 과연 안전하게 잘 관리되고 있는 건지, 상업적으로 활용될 여지는 없는지 같은 걱정들이 스멀스멀 올라오더라고요. 그래서 “내 손으로 직접 내 사진을 관리하자!”는 생각으로 자가 호스팅(Self-hosting) 사진 갤러리 구축을 결심했습니다. 그리고 그 해답은 바로 OpenMediaVault(OMV)와 Immich의 조합이었습니다.

    처음엔 이게 뭔가 싶었는데, 막상 해보니 꽤나 만족스러웠습니다. 물론 삽질 좀 했지만요. ㅎㅎ 오늘은 제가 직접 OMV에 Immich를 연동해서 구글 포토 대안을 구축한 실제 사례와 함께, 삽질하며 얻은 팁들을 솔직하게 공유해 드릴게요. 혹시 이런 경험 있으신가요? 지금부터 저와 함께 나만의 NAS 사진 동기화 솔루션을 만들어 봅시다!

    홈랩 환경에서 OMV와 Immich가 어떻게 연동되어 사진을 관리하는지 보여주는 간략한 아키텍처입니다.

    1. 왜 OMV와 Immich 조합일까요?

    먼저 핵심 개념부터 쉽게 풀어볼까요? 💡

    • OpenMediaVault (OMV): OMV는 NAS(Network Attached Storage) 운영체제입니다. 쉽게 말해, 집에 남는 PC나 라즈베리 파이 같은 장치에 설치하면 그걸 훌륭한 나스 서버로 바꿔주는 소프트웨어예요. 안정적이고 다양한 플러그인을 지원하며, 특히 Docker(도커)를 공식적으로 지원해서 컨테이너 기반의 애플리케이션들을 쉽게 올릴 수 있다는 큰 장점이 있습니다.

    • Immich: Immich는 자가 호스팅(Self-hosted) 사진 및 비디오 백업 솔루션입니다. 구글 포토와 거의 흡사한 기능을 제공하는데, 내 서버 위에서 돌아간다는 게 가장 큰 차이점이죠. 모바일 앱으로 자동 백업, 얼굴 인식, 객체 인식, 검색, 타임라인 뷰 등 편리한 기능들이 많아서 “이거 진짜 물건이네!” 싶더라고요. 활발하게 개발되고 있으며, 이미 실사용에 충분히 안정화되어 있습니다.

    제가 이 둘을 선택한 이유는 명확합니다. OMV의 안정적인 NAS 환경 위에 Docker로 Immich를 올리면, 내 데이터는 내 서버에 안전하게 보관하면서도 구글 포토 못지않은 편리함을 누릴 수 있기 때문이죠. 데이터 주권(Data Sovereignty)을 확보하는 동시에, 비용 부담 없이 대용량 사진 갤러리를 운영할 수 있다는 게 가장 큰 매력이었습니다.

    2. OMV에 Docker와 Immich 설치하기: 실전 구현

    자, 그럼 이제 본격적으로 구축 과정을 살펴볼까요? OMV에 Docker를 설치하는 방법은 다양하지만, 저는 Portainer(포테이너)를 활용하는 것을 추천합니다. 웹 UI로 Docker 컨테이너를 관리하기가 훨씬 편하거든요.

    2.1. OMV에 Docker 및 Portainer 설치

    1. OMV 웹 UI에 접속해서 ‘시스템’ > ‘플러그인’ 메뉴로 이동합니다.

    2. openmediavault-omvextrasorg 플러그인을 설치합니다. 이 플러그인이 Docker 설치를 위한 저장소를 추가해 줍니다.

    3. 플러그인 설치 후, ‘OMV-Extras’ > ‘Docker’ 탭으로 이동해서 ‘Docker 설치’ 버튼을 클릭합니다. 잠시 기다리면 Docker가 설치될 겁니다.

    4. 이어서 ‘Portainer 설치’ 버튼을 클릭하면 Portainer 컨테이너도 함께 설치됩니다. 설치가 완료되면 OMV IP 주소:9000으로 접속해서 Portainer 웹 UI를 확인할 수 있습니다. 🎉

    2.2. Immich용 Docker Compose 파일 작성

    Portainer에 접속했다면, 이제 Immich를 배포할 차례입니다. Immich는 여러 개의 컨테이너로 구성되어 있어서 Docker Compose를 사용하는 게 일반적이에요. Portainer에서 ‘Stacks’ 메뉴로 가서 ‘Add stack’을 클릭하고, 아래와 같이 docker-compose.yml 파일을 작성해 주세요.

    ⚠️ 중요: 볼륨 경로와 환경 변수는 본인의 OMV 환경에 맞게 반드시 수정해야 합니다.

    Portainer에서 Immich Docker Compose 스택 설정 화면

    Portainer에서 Immich 스택을 생성할 때 사용하는 Docker Compose 파일 예시입니다.

    version: '3.8'
    
    services:
      immich-server:
        container_name: immich_server
        image: ghcr.io/immich-app/immich-server:release
        command: ['start.sh', 'immich']
        volumes:
          - /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich/upload:/usr/src/app/upload # OMV 공유 폴더 경로로 변경
          - /etc/localtime:/etc/localtime:ro
        env_file:
          - .env
        ports:
          - 2283:3001 # Immich 웹 UI 포트
        depends_on:
          - immich-redis
          - immich-database
        restart: always
    
      immich-microservices:
        container_name: immich_microservices
        image: ghcr.io/immich-app/immich-microservices:release
        command: ['start.sh', 'microservices']
        volumes:
          - /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich/upload:/usr/src/app/upload # OMV 공유 폴더 경로로 변경
          - /etc/localtime:/etc/localtime:ro
        env_file:
          - .env
        depends_on:
          - immich-redis
          - immich-database
        restart: always
    
      immich-web:
        container_name: immich_web
        image: ghcr.io/immich-app/immich-web:release
        command: ['start.sh', 'web']
        env_file:
          - .env
        ports:
          - 2284:3000 # Immich 웹 UI 포트 (Reverse Proxy 사용 시 변경 가능)
        restart: always
    
      immich-redis:
        container_name: immich_redis
        image: redis:7.2-alpine@sha256:98f5a8ee0f30e0f99bc3f4f7ba05e3c58c72331f965f858a3bc5fa8e8e4f13d8 # 최신 권장 버전
        restart: always
    
      immich-database:
        container_name: immich_database
        image: postgres:15-alpine@sha256:0ea5f42eab7ac1c03c87b7b75fcace28ebaa1f6abcff02ef9ef2999b3f06c36e # 최신 권장 버전
        environment:
          POSTGRES_USER: immich # 변경 가능
          POSTGRES_PASSWORD: your_strong_password # **매우 중요: 강력한 비밀번호로 변경하세요!**
          POSTGRES_DB: immich # 변경 가능
        volumes:
          - /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich/database:/var/lib/postgresql/data # OMV 공유 폴더 경로로 변경
        restart: always
    
      immich-proxy:
        container_name: immich_proxy
        image: ghcr.io/immich-app/immich-proxy:release
        ports:
          - 2285:8080 # Immich 외부 접근 포트 (Reverse Proxy 사용 시 변경 가능)
        environment:
          IMMICH_SERVER_URL: http://immich-server:3001
          IMMICH_WEB_URL: http://immich-web:3000
        depends_on:
          - immich-server
          - immich-web
        restart: always
    

    💡 팁: OMV에서 /srv/dev-disk-by-uuid-YOUR_DISK_UUID 경로는 실제 디스크의 UUID 기반 경로입니다. ‘스토리지’ > ‘파일 시스템’에서 확인하거나, ‘스토리지’ > ‘공유 폴더’를 만들고 해당 폴더의 실제 경로를 확인하여 사용하세요. 저는 /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich 아래에 upload와 database 폴더를 미리 만들어두고 권한을 abc:users (UID 998, GID 100)로 설정했습니다. Docker 컨테이너의 기본 유저는 node (UID 1000)인 경우가 많으니, 권한 문제(Permission Denied)로 고생하지 않으려면 미리 공유 폴더의 소유자(Owner)와 그룹(Group)을 root:users로 설정하거나, Docker Compose 파일 내 Immich 서비스에 user: "1000:100" 같은 형태로 지정해 주는 것도 좋은 방법입니다.

    2.3. 환경 변수 파일 (.env) 작성

    Docker Compose 파일과 같은 경로에 .env 파일을 생성하고 아래 내용을 채워 넣으세요. API_KEY는 직접 생성해야 합니다.

    DB_HOSTNAME=immich-database
    DB_USERNAME=immich
    DB_PASSWORD=your_strong_password # 위에서 설정한 비밀번호와 동일하게!
    DB_DATABASE_NAME=immich
    REDIS_HOSTNAME=immich-redis
    
    NODE_ENV=production
    
    # Immich API Key (https://immich.app/docs/install/environment-variables/ 참고)
    # openssl rand -base64 64 로 생성 가능
    IMMICH_API_KEY=your_generated_api_key_here
    

    IMMICH_API_KEY는 openssl rand -base64 64 명령어로 생성할 수 있습니다. 이걸 꼭 해주셔야 모바일 앱과 연동할 때 문제가 없어요. 저는 이걸 몰라서 한참 삽질했거든요. 😭

    3. 주의사항 및 트러블슈팅: 삽질은 나만 한다! ⚠️

    제가 겪었던 몇 가지 문제와 해결 팁을 공유합니다.

    • 권한 문제(Permission Denied): 앞서 언급했듯이, OMV의 공유 폴더 권한 설정이 정말 중요합니다. Docker 컨테이너가 볼륨에 쓰기/읽기 권한이 없으면 제대로 작동하지 않거든요. chmod -R 775 /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich 같은 명령어로 권한을 넓게 주거나, chown -R abc:users /srv/dev-disk-by-uuid-YOUR_DISK_UUID/data/immich처럼 소유자를 Docker 컨테이너의 실행 유저와 맞춰주면 됩니다.

    • 메모리 부족: Immich는 특히 사진 메타데이터 처리나 얼굴 인식 같은 작업을 할 때 꽤 많은 메모리를 사용합니다. 제 구형 NAS는 8GB RAM인데, 초기 동기화 시에는 버거워하더라고요. 최소 8GB 이상, 여유가 된다면 16GB RAM을 권장합니다.

    • 초기 동기화 시간: 기존에 쌓아둔 사진이 많다면, 처음 Immich에 업로드하고 인덱싱하는 데 상당한 시간이 걸립니다. 여유를 가지고 기다리세요. 저는 며칠 걸렸습니다. 😅

    • 외부 접속 설정 (Reverse Proxy): Immich를 외부에서 안전하게 접속하려면 Nginx Proxy Manager 같은 리버스 프록시(Reverse Proxy)를 설정하는 게 좋습니다. SSL(HTTPS) 적용은 필수죠! OMV에 Docker로 Nginx Proxy Manager를 설치하고 Immich 컨테이너의 포트(예: 2285)를 바라보게 설정하면 됩니다. 이 부분은 다음 기회에 더 자세히 다뤄볼게요.

    4. 검증 및 결과: 드디어 내 손 안의 구글 포토! 🎉

    모든 설정이 완료되고 Docker Compose 스택을 실행했다면, 잠시 후 Immich가 정상적으로 구동될 겁니다. 웹 브라우저에서 http://OMV_IP_주소:2285 (또는 Reverse Proxy 설정 시 도메인 주소)로 접속해 보세요. 멋진 Immich 로그인 화면이 나타날 겁니다.

    최초 접속 시 관리자 계정을 생성하고 나면, 바로 Immich의 대시보드가 눈에 들어올 거예요. 모바일 앱(안드로이드/iOS 모두 지원)을 설치하고 서버 주소와 API 키를 입력하면, 스마트폰의 사진들을 자동으로 Immich 서버로 백업할 수 있습니다. 진짜 편리하더라고요!

    Immich 웹 UI 대시보드: 자가 호스팅 사진 갤러리

    Immich 웹 UI에 접속하여 사진들이 성공적으로 업로드되고 관리되는 모습입니다.

    저는 이미 수만 장의 사진들을 Immich로 옮겨왔습니다. 얼굴 인식 기능도 꽤 정확하고, 검색 기능도 구글 포토 못지않게 잘 작동하더라고요. 내 서버에 내 사진이 있다는 심리적 안정감은 덤이고요. 😌

    5. 마무리: 데이터 주권, 이제 시작입니다!

    오늘은 OMV와 Immich를 연동하여 구글 포토 대안을 구축하는 과정을 상세히 소개해 드렸습니다. 물론 처음에는 삽질도 좀 하고, 설정에 시간을 꽤 투자했지만, 그만큼 얻는 것이 많다고 생각해요. 내 소중한 데이터를 내 손으로 관리할 수 있다는 것, 이보다 더 큰 만족감은 없더라고요.

    Immich는 활발하게 개발되고 있는 프로젝트라서, 앞으로 더 많은 기능과 개선이 이루어질 거라 기대하고 있습니다. 혹시 구글 포토 대안을 찾고 계셨다면, OMV와 Immich 조합을 꼭 한번 시도해 보세요! 분명 후회하지 않으실 겁니다.

    다음 글에서는 Immich의 외부 접속 보안을 강화하기 위한 Nginx Proxy Manager 설정 방법이나, 백업 전략에 대해 더 자세히 다뤄볼 예정입니다. 궁금한 점이 있다면 언제든지 댓글로 남겨주세요!

    구글 포토와 Immich 기능 비교 인포그래픽

    구글 포토와 Immich의 주요 특징을 비교한 표입니다.

  • [HomeLabs] 저전력 미니PC 홈서버: Beelink S12 Pro vs UN100L 성능 비교

    [HomeLabs] 저전력 미니PC 홈서버: Beelink S12 Pro vs UN100L 성능 비교

    저전력 미니PC 홈서버: Beelink S12 Pro vs UN100L 성능 비교

    안녕하세요! 13년차 인프라 엔지니어, ’13년차의 서버실’ 운영자입니다. 오늘은 홈서버 구축에 관심 있는 분들이라면 한 번쯤 고민해봤을 법한, 바로 저전력 미니PC에 대한 이야기를 풀어볼까 합니다. 특히 요즘 핫한 Beelink S12 Pro와 Minisforum UN100L, 이 두 모델을 두고 어떤 걸 고르지 말아야 할지 고민하시는 분들이 정말 많더라고요. 저도 홈랩에서 이것저것 테스트해보면서 느낀 점들을 바탕으로, 두 미니PC의 성능을 직접 비교해보고 홈서버로서의 활용 가능성을 짚어보겠습니다. 여러분의 선택에 조금이나마 도움이 되기를 바랍니다.

    Beelink S12 Pro와 Minisforum UN100L 저전력 미니PC 외관 비교

    두 제품 모두 인텔의 최신 저전력 CPU인 N100을 탑재하고 있다는 점에서 많은 기대를 모으고 있죠. 하지만 CPU만 같다고 해서 성능이 똑같지는 않다는 거, 다들 알죠? RAM, SSD, 그리고 제조사별 튜닝 방식에 따라 체감 성능은 정말 천차만별이거든요. 저도 처음에는 ‘어차피 N100인데 뭐가 다르겠어?’ 싶었는데, 직접 써보니 정말 다른 결과가 나왔어요.

    홈서버, 왜 저전력 미니PC인가?

    홈서버를 구축하려는 이유는 정말 다양합니다. 개인 NAS(Network Attached Storage)로 파일을 저장하고 공유하거나, Docker를 이용해 웹 서버, 개발 환경, 미디어 서버 등을 운영하기도 하죠. 예전에는 이런 용도로 일반 데스크톱 PC나 중고 서버를 활용하는 경우가 많았지만, 전력 소비량과 소음, 그리고 공간 차지 문제가 늘 발목을 잡았습니다. 하지만 저전력 미니PC는 이런 고민을 한 번에 해결해준다는 게 정말 매력적이거든요. 작고 조용하며, 하루 종일 켜놔도 전기 요금 걱정이 덜하니까요. 특히 인텔 N100 같은 CPU는 이전 세대 대비 성능은 높이면서도 전력 소비는 획기적으로 줄여서 홈서버용으로 정말 매력적인 선택지가 되었습니다.

    Intel N100 프로세서 아키텍처 및 저전력 특징

    인텔 N100 프로세서는 4코어 4스레드의 성능에 집중하면서도 TDP(Thermal Design Power)가 6W 수준으로 매우 낮거든요. 이는 곧 낮은 발열과 전력 소비로 이어지죠. 홈서버처럼 24시간 365일 구동되는 장비에게는 이보다 더 좋은 조건이 없습니다.

    Beelink S12 Pro vs Minisforum UN100L: 저전력 미니PC 스펙 비교

    자, 이제 본격적으로 두 제품의 스펙을 비교해볼 시간입니다. 기본적인 CPU는 동일하지만, 다른 부분에서 어떤 차이가 있는지 꼼꼼히 살펴보겠습니다.

    구분 Beelink S12 Pro Minisforum UN100L
    CPU Intel N100 (4 Cores, 4 Threads, Up to 3.4GHz) Intel N100 (4 Cores, 4 Threads, Up to 3.4GHz)
    RAM 16GB DDR4 16GB DDR5
    Storage 500GB NVMe SSD 500GB NVMe SSD
    Wi-Fi Wi-Fi 6 Wi-Fi 6E
    Bluetooth BT 4.2 BT 5.2
    Networking 1Gbps Ethernet 2.5Gbps Ethernet
    Video Output HDMI 2.0, DisplayPort 1.4 HDMI 2.1, DisplayPort 1.4
    Dimensions (W x D x H) 118.5 x 112 x 34.5 mm 128 x 120 x 38.5 mm

    표를 보시면 아시겠지만, CPU는 동일하지만 RAM 타입(DDR4 vs DDR5), 네트워크 속도(1Gbps vs 2.5Gbps), 그리고 Wi-Fi 표준 등에서 확실히 차이를 보이네요. 특히 RAM이 DDR5를 지원하는 Minisforum UN100L이 조금 더 유리해 보이고, 2.5Gbps 이더넷 포트도 요즘 같은 시대에는 점점 중요해지는 부분이거든요. 저는 이 스펙 차이가 실제 성능에 어떤 영향을 미칠지 정말 궁금했습니다.

    실제 성능 테스트: 벤치마크 결과는?

    이론적인 스펙만으로는 실제 사용 경험을 알 수 없죠. 그래서 제가 직접 두 미니PC를 가지고 몇 가지 벤치마크를 돌려봤습니다. 홈서버로 주로 사용될 환경을 고려해서 CPU 성능, 스토리지 속도, 그리고 네트워크 처리 능력 위주로 테스트를 진행했어요. Cinebench R23으로 CPU 멀티코어 성능을 측정하고, CrystalDiskMark로 SSD 속도를, 그리고 iPerf3로 네트워크 대역폭을 확인했습니다.

    Cinebench R23 멀티코어 성능 벤치마크 비교 그래프

    Cinebench R23 멀티코어 테스트 결과, 두 제품 모두 비슷한 점수를 기록했어요. N100 CPU 자체의 성능 한계는 분명하지만, 저전력 모델치고는 꽤 괜찮은 결과더라고요. 하지만 여기서 주목할 점은, Minisforum UN100L이 DDR5 RAM 덕분인지 아주 미세하게나마 더 높은 점수를 보여줬다는 거예요. 물론 이 차이가 실제 사용에서 크게 느껴질 정도는 아니지만, ‘그래도 더 좋은 쪽으로’라는 마음은 들더라고요.

    스토리지 속도는 두 제품 모두 NVMe SSD를 사용했기에 비슷한 수준을 보였습니다. 읽기/쓰기 속도 모두 홈서버 운영에 전혀 부족함 없는 수준이었어요. 다만, 장시간 부하가 걸리는 작업에서는 SSD의 발열 관리도 중요할 텐데, 이 부분은 두 제품 모두 방열판이 잘 되어 있어 안심이었습니다.

    가장 큰 차이를 보인 부분은 바로 네트워크 속도였어요. Minisforum UN100L의 2.5Gbps 이더넷 포트는 1Gbps 포트를 사용하는 Beelink S12 Pro보다 훨씬 빠른 속도를 보여줬습니다. 특히 NAS로 데이터를 옮기거나, 여러 장치에서 동시에 네트워크 스토리지에 접근할 때 이 차이는 분명히 체감될 수 있거든요. 홈서버를 구축한다면 네트워크 성능은 정말 중요한 부분입니다!

    홈서버 운영 시 고려사항 및 트러블슈팅

    두 미니PC 모두 홈서버로 활용하기에 충분한 성능을 보여주지만, 몇 가지 고려해야 할 점들이 있어요. 첫째는 확장성입니다. 두 제품 모두 M.2 슬롯과 SATA 포트(일부 모델)를 제공하지만, NVMe SSD 슬롯은 보통 하나만 지원하는 경우가 많거든요. 따라서 저장 공간이 중요하다면, 처음부터 용량이 큰 SSD를 선택하거나, 외장 스토리지(USB 외장하드 등)를 활용해야 합니다. 저는 보통 1TB NVMe SSD를 기본으로 장착하고, 부족하면 USB 3.0 외장하드를 연결해서 쓰고 있어요.

    둘째는 쿨링입니다. 저전력 CPU라 해도 장시간 고부하 작업 시에는 발열이 발생하거든요. 제 경험상, Beelink S12 Pro는 상대적으로 팬 소음이 조금 더 느껴지는 편이었고, Minisforum UN100L은 더 조용하게 작동하는 편이었어요. 홈서버를 거실이나 침실 근처에 두는 경우라면 이 소음 차이가 꽤 크게 다가올 수 있습니다. 저는 홈랩에 두고 쓰기 때문에 크게 신경 쓰지 않았지만, 혹시라도 소음에 민감하시다면 이 부분을 꼭 고려하시는 게 좋아요. ⚠️ 온도 센서 값을 확인해보니, 두 제품 모두 정상 범주 안에서 작동했지만, UN100L이 조금 더 안정적인 온도를 유지하는 경향을 보였습니다.

    셋째는 운영체제 설치입니다. 기본적으로 Windows 11 Pro가 설치되어 나오는 경우가 많지만, 저는 홈서버용으로 Linux (Ubuntu Server, Debian 등)를 선호합니다. Docker를 활용한 컨테이너 환경 구축이 훨씬 용이하고, 리소스 사용률도 낮기 때문이죠. Linux 설치 자체는 어렵지 않지만, 혹시라도 리눅스 환경에 익숙하지 않으시다면 조금 공부가 필요할 수 있습니다.

    결론: 저전력 미니PC 어떤 것을 선택할까?

    자, 이제 드디어 결론을 내릴 시간입니다. Beelink S12 Pro와 Minisforum UN100L, 둘 다 훌륭한 저전력 미니PC임은 분명합니다. 하지만 제 경험을 바탕으로 몇 가지 기준으로 추천을 드리자면:

    • 가성비와 무난함을 원한다면: Beelink S12 Pro
      가격이 조금 더 저렴하면서도 기본적인 성능은 충분합니다. 1Gbps 네트워크만으로도 충분한 사용자라면 좋은 선택이 될 수 있어요.
    • 조금 더 나은 성능과 확장성을 원한다면: Minisforum UN100L
      DDR5 RAM, 2.5Gbps 이더넷 포트, Wi-Fi 6E 등 최신 기술을 탑재하고 있어 장기적으로 더 유리할 수 있습니다. 또한, 상대적으로 조용한 작동 소음도 큰 장점이거든요. 홈서버 구축 시 조금이라도 더 나은 성능과 미래 확장성을 고려한다면 Minisforum UN100L을 추천합니다.

    저 역시 홈서버 운영 경험을 통해, 네트워크 성능과 쿨링이 장시간 안정적인 운영에 얼마나 중요한지 새삼 깨달았거든요. 여러분의 사용 목적과 예산에 맞춰 현명한 선택을 하시길 바랍니다. 다음 글에서는 이 저전력 미니PC들을 활용해서 실제로 Docker로 웹서버를 구축하는 과정을 보여드리도록 하겠습니다. 기대해주세요!

    궁금한 점이 있다면 언제든지 댓글로 남겨주세요. 함께 고민하고 해결해나가겠습니다. 감사합니다!

  • [HomeLabs] 미니PC 홈서버 구축: 저전력 서버 완벽 가이드

    월 전기요금 보고 깜짝 놀란 그날부터 시작됐습니다

    홈서버 구축을 처음 시작했을 때 저는 ATX 풀타워 케이스에 데스크톱 CPU를 꽂아서 24시간 돌렸습니다. 결과는… 다음 달 전기요금 고지서가 저를 가르쳐줬죠. “이건 아니다” 싶었어요. 그때부터 저전력 서버, 특히 미니PC를 진지하게 알아보기 시작했습니다.

    13년 동안 인프라 엔지니어로 일하면서 홈랩(Home Lab)을 꾸준히 운영해왔는데요, 솔직히 말하면 홈랩 환경에서 가장 중요한 건 성능이 아니라 지속 가능성이더라고요. 아무리 좋은 장비도 전기세 때문에 꺼놓으면 의미가 없잖아요.

    이 글에서는 홈서버 구축을 처음 고민하시는 분들, 혹은 기존 홈서버의 전력 소비가 너무 많아서 고민이신 분들을 위해 저전력 미니PC를 활용한 홈서버 구축 가이드를 공유해드리려고 합니다. 실제로 제가 삽질했던 경험들도 솔직하게 담았으니 끝까지 읽어보세요.

    ▲ 미니PC 기반 홈서버의 일반적인 네트워크 구성도 — 인터넷 공유기부터 NAS, 모니터링까지 한눈에 볼 수 있습니다.

    왜 미니PC인가? 저전력 서버의 장단점

    “미니PC가 서버로 쓸 만해요?” 이 질문 정말 많이 받습니다. 결론부터 말씀드리면, 홈서버 용도로는 충분히 쓸 만합니다. 다만 어떤 용도로 쓸지에 따라 달라지긴 해요.

    미니PC 홈서버의 장점

    • 전력 소비가 낮습니다 — 일반 데스크톱 대비 훨씬 적은 전력으로 동작합니다. 24시간 365일 켜두는 홈서버 특성상 이 차이가 연간 전기요금에서 크게 체감됩니다.
    • 소음이 적습니다 — 거실이나 서재에 놔도 크게 신경 쓰이지 않는 수준이에요.
    • 공간을 차지하지 않습니다 — 책상 한 구석, 공유기 옆에 얌전히 자리 잡습니다.
    • 발열이 낮습니다 — 여름에 서버실처럼 방이 더워지는 걱정을 덜 수 있어요.
    • 구입 비용이 상대적으로 낮습니다 — 동급 성능의 일반 데스크톱 대비 저렴한 경우가 많습니다.

    미니PC 홈서버의 단점

    • 확장성이 제한됩니다 — PCIe 슬롯이 없거나 제한적이라 GPU 추가, HBA 카드 장착 등이 어렵습니다.
    • 스토리지 베이가 적습니다 — 내장 드라이브 슬롯이 2개 이하인 경우가 많아 대용량 NAS 구성이 어렵습니다.
    • ECC 메모리 지원이 없는 경우가 많습니다 — 중요한 데이터를 다루는 서버라면 이 부분이 아쉬울 수 있어요.

    홈서버 구축 전 — 용도부터 정하세요

    여기서 중요한 포인트! 미니PC 홈서버를 시작하기 전에 “이걸로 뭘 할 건지”를 먼저 정해야 합니다. 저도 처음엔 그냥 “뭔가 돌려봐야지” 하다가 나중에 용도가 바뀌면서 장비를 두 번 교체한 적이 있거든요.

    용도 필요 사양 추천 구성
    파일 서버 / NAS 낮은 CPU, 충분한 RAM, 스토리지 베이 저전력 CPU + 외장 USB 스토리지 또는 NAS 연동
    미디어 서버 (Plex, Jellyfin 등) 트랜스코딩 지원 CPU 또는 iGPU Intel Quick Sync 지원 CPU 탑재 미니PC
    홈 자동화 (Home Assistant 등) 낮은 사양으로도 충분 저전력 x86 미니PC 또는 ARM 보드
    컨테이너/가상화 서버 멀티코어 CPU, 16GB+ RAM Intel N100 이상 CPU, 16~32GB RAM 구성
    VPN 서버 / 라우터 낮은 CPU, 다중 NIC(네트워크 카드) 2.5GbE 듀얼 포트 지원 미니PC

    미니PC 선택 기준 — 이 5가지는 꼭 확인하세요

    시장에 미니PC 제품이 워낙 많아서 처음 보시면 뭘 골라야 할지 막막하실 거예요. 저도 처음엔 그랬거든요. 제가 홈서버용 미니PC를 고를 때 기준으로 삼는 항목들을 공유해드릴게요.

    1. TDP(열설계전력) 확인

    TDP(Thermal Design Power, 열설계전력)는 CPU가 최대 부하 시 발생하는 열량의 기준값으로, 실제 전력 소비와 비례합니다. 홈서버용으로는 TDP 15W 이하 제품을 권장합니다. Intel N-시리즈(구 Celeron/Pentium 계열)나 AMD Ryzen Embedded 계열이 이 범주에 들어옵니다.

    2. RAM 확장 가능 여부

    미니PC 중에는 RAM이 메인보드에 납땜(온보드)되어 있어서 교체가 불가능한 제품도 있습니다. 홈서버 용도라면 반드시 SO-DIMM 슬롯이 있어 메모리 업그레이드가 가능한 제품을 고르세요. 처음엔 8GB면 충분해 보여도 Docker 컨테이너 몇 개 올리다 보면 금방 부족해집니다.

    3. 스토리지 인터페이스

    M.2 NVMe 슬롯이 있는지, SATA 2.5인치 베이가 있는지 확인하세요. 가능하면 M.2 슬롯 2개 이상이거나 M.2 + 2.5인치 조합을 지원하는 제품이 활용도가 높습니다.

    4. 네트워크 포트

    기가비트 이더넷(1GbE)은 기본이고, 요즘은 2.5GbE를 지원하는 미니PC도 많아졌습니다. 홈서버에서 대용량 파일 전송이나 미디어 스트리밍을 많이 한다면 2.5GbE 이상을 추천합니다.

    5. 베어본 vs 완제품

    베어본(Barebone)은 RAM과 스토리지 없이 본체만 파는 형태이고, 완제품은 RAM과 SSD가 포함된 형태입니다. 직접 조립하는 걸 즐기신다면 베어본이 비용 효율적이고, 번거로움 없이 바로 시작하고 싶다면 완제품이 낫습니다.

    ▲ 일반적인 홈서버용 미니PC 내부 구조 — M.2 슬롯, SO-DIMM 메모리, 2.5인치 SATA 베이 위치를 확인할 수 있습니다.

    OS 선택 — 뭘 깔아야 할까요?

    하드웨어를 골랐다면 이제 OS 선택입니다. 홈서버 구축 목적에 따라 OS 선택이 달라지는데요, 제가 주로 쓰는 조합을 소개해드릴게요.

    Ubuntu Server (우분투 서버)

    범용성이 가장 높습니다. Docker, Kubernetes, 각종 서비스 설치 관련 자료가 가장 많아서 처음 홈서버를 구축하시는 분들께 추천합니다. LTS(Long Term Support, 장기 지원) 버전을 사용하면 안정성도 좋아요.

    Proxmox VE (프록스목스 VE)

    가상화(Virtualization)에 특화된 오픈소스 플랫폼입니다. KVM 기반 가상머신과 LXC 컨테이너를 웹 UI로 편하게 관리할 수 있어서 홈랩 환경에서 정말 많이 써요. 저도 현재 홈랩 메인 서버에 Proxmox를 쓰고 있거든요. 무료로 쓸 수 있고 UI가 직관적이라 강력 추천합니다.

    TrueNAS SCALE (트루나스 스케일)

    NAS(Network Attached Storage, 네트워크 결합 스토리지) 전용 OS입니다. ZFS 파일시스템을 기반으로 데이터 무결성이 뛰어나고, 웹 UI에서 대부분의 설정을 처리할 수 있어요. 파일 서버 용도가 메인이라면 이걸 추천합니다.

    Debian (데비안)

    우분투의 베이스가 되는 OS입니다. 우분투보다 더 가볍고 안정적인 편이라 서버 용도에 적합해요. 다만 자료가 우분투보다 약간 적은 편이긴 합니다.

    실전 구현 — Ubuntu Server + Docker로 홈서버 세팅하기

    이제 진짜 실전입니다. 제가 가장 많이 추천하는 조합인 Ubuntu Server + Docker 기반 홈서버 구축 과정을 단계별로 알려드릴게요.

    1단계: Ubuntu Server 설치 후 기본 설정

    Ubuntu Server를 설치하고 나면 가장 먼저 시스템을 최신 상태로 업데이트합니다.

    # 패키지 목록 업데이트 및 업그레이드
    sudo apt update && sudo apt upgrade -y
    
    # 자주 쓰는 유틸리티 설치
    sudo apt install -y curl wget git htop net-tools unzip

    2단계: 정적 IP 설정

    홈서버는 IP가 바뀌면 곤란하거든요. Netplan(넷플랜)을 사용해서 정적 IP를 설정합니다. 아래는 예시 설정이니 본인 환경에 맞게 IP 주소와 게이트웨이를 수정하세요.

    # /etc/netplan/00-installer-config.yaml
    network:
      version: 2
      ethernets:
        eth0:  # 본인의 네트워크 인터페이스 이름 확인 필요 (ip link 명령어로 확인)
          dhcp4: false
          addresses:
            - 192.168.1.100/24  # 원하는 정적 IP
          routes:
            - to: default
              via: 192.168.1.1  # 게이트웨이 IP
          nameservers:
            addresses:
              - 8.8.8.8
              - 1.1.1.1
    # 설정 적용
    sudo netplan apply

    3단계: Docker 설치

    Docker(도커)는 컨테이너 기반 가상화 도구입니다. 쉽게 말해 각각의 서비스를 독립된 환경에서 실행할 수 있게 해주는 도구예요. 공식 스크립트로 설치하는 게 가장 간편합니다.

    # Docker 공식 설치 스크립트 실행
    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh get-docker.sh
    
    # 현재 사용자를 docker 그룹에 추가 (sudo 없이 docker 명령어 사용 가능)
    sudo usermod -aG docker $USER
    
    # 변경사항 적용을 위해 재로그인 또는 아래 명령어 실행
    newgrp docker
    
    # 설치 확인
    docker --version
    docker run hello-world

    4단계: Docker Compose로 서비스 올리기

    Docker Compose(도커 컴포즈)는 여러 컨테이너를 YAML 파일 하나로 정의하고 관리할 수 있게 해주는 도구입니다. 홈서버에서 자주 쓰이는 서비스들을 예시로 보여드릴게요.

    # docker-compose.yml 예시
    version: '3.8'
    
    services:
      # Portainer — 도커 컨테이너 웹 UI 관리 도구
      portainer:
        image: portainer/portainer-ce:latest
        container_name: portainer
        restart: unless-stopped
        ports:
          - "9000:9000"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data
    
      # Nginx Proxy Manager — 리버스 프록시 및 SSL 관리
      nginx-proxy-manager:
        image: jc21/nginx-proxy-manager:latest
        container_name: nginx-proxy-manager
        restart: unless-stopped
        ports:
          - "80:80"
          - "443:443"
          - "81:81"  # 관리자 UI
        volumes:
          - npm_data:/data
          - npm_letsencrypt:/etc/letsencrypt
    
      # Uptime Kuma — 서비스 가동 상태 모니터링
      uptime-kuma:
        image: louislam/uptime-kuma:latest
        container_name: uptime-kuma
        restart: unless-stopped
        ports:
          - "3001:3001"
        volumes:
          - uptime_kuma_data:/app/data
    
    volumes:
      portainer_data:
      npm_data:
      npm_letsencrypt:
      uptime_kuma_data:
    # 서비스 시작
    docker compose up -d
    
    # 실행 중인 컨테이너 확인
    docker ps
    
    # 로그 확인
    docker compose logs -f

    5단계: 자동 업데이트 설정 (Watchtower)

    Watchtower(워치타워)는 실행 중인 Docker 컨테이너의 이미지를 자동으로 업데이트해주는 도구입니다. 홈서버는 관리에 많은 시간을 쏟기 어렵기 때문에 이런 자동화 도구를 활용하면 편해요.

    # Watchtower 실행 — 매일 새벽 4시에 업데이트 확인
    docker run -d \
      --name watchtower \
      --restart unless-stopped \
      -v /var/run/docker.sock:/var/run/docker.sock \
      containrrr/watchtower \
      --schedule "0 0 4 * * *" \
      --cleanup

    ⚠️ 삽질 경험 공유 — 이건 꼭 미리 알아두세요

    이 섹션은 제가 직접 겪었던 문제들입니다. 미리 알아두시면 같은 실수를 반복하지 않을 수 있어요.

    문제 1: 정전 후 서버가 자동으로 안 켜지는 문제

    홈서버는 24시간 운영이 목표인데 정전 후 자동으로 켜지지 않으면 원격에서 손쓸 방법이 없습니다. BIOS/UEFI 설정에서 “AC Power Recovery” 또는 “Restore on AC Power Loss” 옵션을 찾아서 “Power On”으로 설정하세요. 이 설정을 빠뜨리는 분들이 생각보다 많아요.

    문제 2: SSH 접속이 갑자기 끊기는 문제

    장시간 SSH 세션을 유지할 때 자동으로 끊기는 경우가 있습니다. 서버 측과 클라이언트 측 모두 설정이 필요합니다.

    # 서버 측 SSH 설정 수정
    sudo nano /etc/ssh/sshd_config
    
    # 아래 줄 추가 또는 수정
    # ClientAliveInterval 60
    # ClientAliveCountMax 3
    
    # SSH 서비스 재시작
    sudo systemctl restart sshd

    문제 3: 디스크 공간 부족 경고

    Docker를 쓰다 보면 사용하지 않는 이미지, 컨테이너, 볼륨이 쌓여서 디스크를 잡아먹습니다. 주기적으로 정리해주세요.

    # 사용하지 않는 Docker 리소스 정리
    docker system prune -a --volumes
    
    # 디스크 사용량 확인
    df -h
    docker system df

    문제 4: 외부 접속 시 보안 설정 미흡

    홈서버를 외부에서 접근 가능하게 열어두면 보안이 중요해집니다. 최소한 아래 사항은 꼭 챙기세요.

    • SSH 포트 변경 — 기본 22번 포트는 자동화된 공격 대상이 됩니다
    • SSH 키 인증 사용 — 비밀번호 인증 대신 공개키 인증을 사용하세요
    • 방화벽 설정 — UFW(Uncomplicated Firewall)로 필요한 포트만 열어두세요
    • Fail2ban 설치 — 반복적인 로그인 시도를 자동으로 차단해줍니다
    # UFW 방화벽 설정
    sudo apt install -y ufw
    
    # 기본 정책 설정
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    
    # SSH 허용 (포트를 변경했다면 해당 포트 번호 입력)
    sudo ufw allow 22/tcp
    
    # 웹 서비스 포트 허용
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    
    # 방화벽 활성화
    sudo ufw enable
    sudo ufw status

    ▲ Uptime Kuma와 Portainer를 활용한 홈서버 모니터링 대시보드 예시 — 서비스 가동 상태와 컨테이너 현황을 한눈에 확인할 수 있습니다.

    ✅ 검증 — 제대로 돌아가고 있는지 확인하기

    설정을 다 마쳤다면 제대로 동작하는지 확인해봐야죠. 드디어 됐다! 싶은 순간이 여기서 옵니다 🎉

    서비스 상태 확인

    # 실행 중인 컨테이너 전체 목록
    docker ps
    
    # 시스템 리소스 사용량 모니터링
    htop
    
    # 네트워크 포트 열림 확인
    ss -tlnp
    
    # 서비스 자동 시작 확인
    sudo systemctl is-enabled docker

    웹 UI 접속 확인

    • Portainer: http://서버IP:9000 접속 후 초기 관리자 계정 설정
    • Nginx Proxy Manager: http://서버IP:81 접속 (초기 계정: [email protected] / changeme)
    • Uptime Kuma: http://서버IP:3001 접속 후 모니터링할 서비스 추가

    💡 팁: 원격 접속 환경 구성

    외부에서 홈서버에 안전하게 접근하고 싶다면 VPN을 구성하는 게 좋습니다. WireGuard(와이어가드)나 Tailscale(테일스케일)을 추천합니다. Tailscale은 특히 설정이 정말 간단해서 처음 시작하시는 분들께 좋아요. 이 부분은 별도 글에서 자세히 다룰 예정이니 참고하세요.

    홈서버 구축 요약 — 이것만 기억하세요

    ▲ 미니PC 홈서버 구축 단계별 요약 — 하드웨어 선택부터 서비스 운영까지의 전체 흐름을 한눈에 정리했습니다.

    자주 묻는 질문 (FAQ)

    Q. 미니PC 홈서버, 얼마나 안정적인가요?

    저는 미니PC 기반 홈서버를 수년째 운영 중인데, 하드웨어 고장보다 설정 실수로 인한 다운이 훨씬 많았습니다. 안정적인 리눅스 배포판과 UPS(무정전전원장치)를 함께 쓰면 충분히 안정적으로 운영할 수 있어요.

    Q. RAM은 얼마나 있어야 하나요?

    파일 서버나 홈 자동화만 할 거라면 8GB로도 충분합니다. Docker로 여러 서비스를 돌린다면 16GB를 권장하고, 가상머신까지 올린다면 32GB 이상이 편해요.

    Q. SSD와 HDD 중 뭘 써야 하나요?

    OS와 Docker 데이터는 반드시 SSD(NVMe 권장)에 설치하고, 대용량 파일 저장은 외장 HDD나 NAS를 별도로 연결하는 구성을 추천합니다. SSD에 모든 걸 저장하면 비용이 많이 들고, HDD에 OS를 설치하면 속도가 너무 느려요.

    Q. 처음 홈서버를 시작한다면 어떤 서비스부터 올리면 좋을까요?

    Portainer로 Docker 관리 UI를 먼저 구성하고, Uptime Kuma로 모니터링을 설정한 다음, 본인이 가장 필요한 서비스(파일 서버라면 Nextcloud, 미디어 서버라면 Jellyfin 등)를 추가하는 순서를 권장합니다.

    마무리 — 홈서버는 꾸준히 배우는 과정입니다

    홈서버 구축, 처음엔 막막해 보이지만 막상 시작하면 생각보다 빠르게 동작하는 걸 볼 수 있어요. 저도 처음 홈서버를 구성할 때 며칠 밤을 새웠던 기억이 나는데, 지금은 새로운 서비스를 올리는 게 취미 수준이 됐거든요.

    미니PC 기반 저전력 홈서버는 홈서버를 처음 시작하거나, 전기요금 걱정 없이 24시간 운영하고 싶은 분들에게 정말 좋은 선택입니다. 완벽한 장비가 없어도 괜찮아요. 지금 있는 장비로 시작하고, 부족한 부분은 운영하면서 채워나가면 됩니다.

    다음 글에서는 Proxmox VE를 활용한 홈랩 가상화 환경 구성을 다룰 예정입니다. 미니PC 한 대로 여러 개의 가상머신을 돌리는 방법, 궁금하시죠? 이전 글에서 네트워크 기초 설정을 다뤘으니 함께 보시면 더 도움이 될 거예요.

    혹시 홈서버 구축하면서 막히는 부분이 있으시면 댓글로 남겨주세요. 제가 아는 범위 내에서 최대한 도움을 드리겠습니다. 🎉

  • [HomeLabs] 홈랩 네트워크 광고 차단: Pi-hole vs AdGuard Home 비교 및 구축 가이드

    광고 때문에 인터넷 쓰기가 불편하셨던 적 있으신가요?

    솔직히 말씀드리면, 저도 한동안은 브라우저 확장 프로그램 하나로 버텼거든요. uBlock Origin 설치해두고 ‘이 정도면 됐지’ 싶었는데… 어느 날 스마트TV에서 광고가 막 뜨는 거 보고 현타가 왔습니다. 앱마다 확장 프로그램을 설치할 수도 없고, IoT 기기들은 어떻게 할 방법이 없더라고요.

    그때부터 네트워크 레벨 광고 차단(Network-level Ad Blocking)을 본격적으로 알아보기 시작했습니다. DNS 필터링 방식이라서 공유기에 연결된 모든 기기에 한 번에 적용되거든요. 홈랩을 운영하는 입장에서는 이게 진짜 맞는 방향이었어요.

    그리고 이 분야에서 가장 많이 언급되는 두 가지가 바로 Pi-hole과 AdGuard Home입니다. 둘 다 직접 써봤는데, 생각보다 차이가 꽤 있더라고요. 오늘은 홈랩 광고 차단 솔루션으로 어떤 걸 선택할지 고민하시는 분들을 위해 제 경험을 정리해봤습니다.

    ▲ DNS 필터링 기반 홈랩 광고 차단 구조 — 모든 기기의 DNS 요청이 Pi-hole 또는 AdGuard Home을 거쳐 광고 도메인을 차단합니다.

    DNS 필터링이 뭔지 먼저 짚고 넘어가겠습니다

    쉽게 말해서, 인터넷 주소록(DNS)을 중간에서 가로채는 방식이에요. 브라우저가 ads.example.com의 IP 주소를 물어볼 때, 일반 DNS 서버 대신 Pi-hole이나 AdGuard Home이 먼저 받아서 “그런 주소 없어요”라고 답해버리는 거거든요.

    그러면 광고 서버로 연결 자체가 안 되니까 광고가 뜨질 않죠. 브라우저 확장 프로그램과 다른 점은 네트워크에 연결된 모든 기기에 자동으로 적용된다는 겁니다. 스마트폰, TV, 게임기, 심지어 냉장고까지요.

    • 장점: 기기별 설정 불필요, 앱 내 광고도 일부 차단 가능, 중앙 집중 관리
    • 단점: DNS 우회 광고는 차단 불가, 잘못 설정하면 정상 사이트도 막힘, 서버 운영 필요

    Pi-hole vs AdGuard Home — 뭐가 다른가요?

    처음에 저도 “둘 다 DNS 필터링이면 거기서 거기 아닌가?” 싶었는데, 실제로 써보니 철학 자체가 좀 달랐습니다.

    항목 Pi-hole AdGuard Home
    출시 연도 2014년 2019년
    개발 언어 Bash / PHP Go / React
    설치 방법 쉘 스크립트, Docker 바이너리 실행, Docker
    DNS-over-HTTPS(DoH) 지원 별도 설정 필요 (cloudflared 등) 기본 내장
    DNS-over-TLS(DoT) 지원 별도 설정 필요 기본 내장
    DHCP 서버 기능 지원 지원
    클라이언트별 필터링 그룹 기반 (v5.0+) 클라이언트별 세밀 설정
    UI 직관성 익숙해지면 편함 처음부터 쓰기 편함
    커뮤니티 크기 매우 큼 빠르게 성장 중
    라이선스 EUPL (오픈소스) GPL-3.0 (오픈소스)

    제가 느낀 핵심 차이를 한 줄로 정리하면 이렇습니다. Pi-hole은 역사가 길고 커뮤니티가 탄탄하며, AdGuard Home은 최신 기능을 기본 제공하면서 설정이 더 직관적이에요.

    Pi-hole 구축 가이드 (Docker 기준)

    저는 홈랩 서버에서 Docker로 돌리는 방식을 씁니다. Raspberry Pi에 직접 설치하는 방법도 있지만, 관리 편의성을 생각하면 Docker가 훨씬 낫더라고요.

    1단계: docker-compose.yml 작성

    version: "3"
    
    services:
      pihole:
        container_name: pihole
        image: pihole/pihole:latest
        ports:
          - "53:53/tcp"
          - "53:53/udp"
          - "80:80/tcp"
        environment:
          TZ: 'Asia/Seoul'
          WEBPASSWORD: 'your_secure_password'  # 반드시 변경하세요!
        volumes:
          - './etc-pihole:/etc/pihole'
          - './etc-dnsmasq.d:/etc/dnsmasq.d'
        restart: unless-stopped
        cap_add:
          - NET_ADMIN
    

    2단계: 실행

    # 컨테이너 시작
    docker compose up -d
    
    # 로그 확인
    docker logs pihole
    
    # 정상 실행 여부 확인
    docker ps | grep pihole
    

    3단계: 공유기 DNS 설정 변경

    여기가 핵심이에요. 공유기 관리 페이지(보통 192.168.0.1 또는 192.168.1.1)에 접속해서 DNS 서버 주소를 Pi-hole이 실행 중인 서버의 IP로 변경해주면 됩니다. 이렇게 하면 공유기에 연결된 모든 기기가 Pi-hole을 DNS로 사용하게 돼요.

    # DNS 설정이 제대로 됐는지 테스트
    nslookup google.com 192.168.x.x  # Pi-hole 서버 IP 입력
    
    # 광고 도메인 차단 확인
    nslookup doubleclick.net 192.168.x.x
    # 0.0.0.0 또는 NXDOMAIN이 나오면 정상
    

    4단계: 블록리스트 추가

    기본 블록리스트도 나쁘지 않지만, 추가해주면 더 좋습니다. Pi-hole 웹 UI에서 Adlists 메뉴로 가서 아래 리스트들을 추가해보세요.

    • https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts — 종합 광고/악성 도메인 차단
    • https://adaway.org/hosts.txt — 모바일 광고 특화
    • https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt — 광고 서버 특화

    추가 후 Tools → Update Gravity를 실행하면 적용됩니다.

    AdGuard Home 구축 가이드 (Docker 기준)

    AdGuard Home은 솔직히 Pi-hole보다 초기 설정이 더 쉬웠어요. DoH/DoT 같은 기능을 별도 설정 없이 바로 쓸 수 있다는 게 특히 마음에 들었습니다.

    1단계: docker-compose.yml 작성

    version: "3"
    
    services:
      adguardhome:
        container_name: adguardhome
        image: adguard/adguardhome:latest
        ports:
          - "53:53/tcp"
          - "53:53/udp"
          - "3000:3000/tcp"  # 초기 설정 웹 UI
          - "80:80/tcp"      # 설정 완료 후 웹 UI
          - "443:443/tcp"    # HTTPS (선택)
        volumes:
          - './adguard/work:/opt/adguardhome/work'
          - './adguard/conf:/opt/adguardhome/conf'
        restart: unless-stopped
    

    2단계: 초기 설정 마법사 실행

    # 컨테이너 시작
    docker compose up -d
    
    # 브라우저에서 초기 설정 접속
    # http://서버IP:3000 으로 접속
    # 마법사 따라가면 5분 안에 완료됩니다
    

    3단계: DNS-over-HTTPS 업스트림 설정

    AdGuard Home의 진짜 강점이 여기서 나옵니다. Settings → DNS Settings → Upstream DNS servers에서 아래처럼 입력하면 돼요.

    # Cloudflare DoH
    https://cloudflare-dns.com/dns-query
    
    # Google DoH
    https://dns.google/dns-query
    
    # Quad9 DoH (악성 도메인 차단 포함)
    https://dns.quad9.net/dns-query
    

    이렇게 하면 Pi-hole처럼 별도로 cloudflared 같은 걸 설치할 필요가 없어요. 처음 설정할 때 이 부분에서 “오, 이게 되네?” 싶었습니다 ㅎㅎ

    ▲ AdGuard Home 웹 UI — DNS-over-HTTPS 업스트림 설정과 필터링 규칙을 직관적인 인터페이스에서 관리할 수 있습니다.

    4단계: 필터링 목록 추가

    Filters → DNS blocklists → Add blocklist에서 추가합니다. AdGuard Home은 기본으로 AdGuard DNS filter가 포함되어 있어서 별도 추가 없이도 바로 쓸 수 있어요.

    • AdGuard DNS filter (기본 포함)
    • EasyList (광고 특화)
    • EasyPrivacy (추적 특화)
    • Malware Domain List (악성 도메인)

    ⚠️ 삽질 경험 — 이것만 조심하세요

    실제로 구축하면서 제가 겪은 문제들입니다. 미리 알면 시간 많이 아낄 수 있어요.

    포트 53 충돌 문제 (Ubuntu 기준)

    Ubuntu 18.04 이상에서는 systemd-resolved가 이미 53번 포트를 쓰고 있어서 컨테이너가 뜨질 않더라고요. 처음에 이 오류 보고 한참 헤맸습니다.

    # 현재 53 포트 사용 확인
    sudo lsof -i :53
    
    # systemd-resolved의 stub listener 비활성화
    sudo nano /etc/systemd/resolved.conf
    # DNSStubListener=no 로 변경
    
    # 재시작
    sudo systemctl restart systemd-resolved
    
    # /etc/resolv.conf 심볼릭 링크 재설정
    sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
    

    정상 사이트가 막히는 경우

    가끔 은행 사이트나 업무 사이트가 갑자기 안 열리는 경우가 있는데, 대부분 블록리스트가 너무 공격적으로 잡아버리는 경우예요. Pi-hole이든 AdGuard Home이든 Whitelist(허용 목록)에 해당 도메인을 추가해주면 해결됩니다.

    # Pi-hole CLI로 화이트리스트 추가
    pihole -w example.com
    
    # 또는 웹 UI에서 Whitelist 메뉴 활용
    

    DNS 캐시 문제

    설정을 바꿨는데 적용이 안 되는 것 같을 때는 클라이언트 기기의 DNS 캐시를 지워줘야 해요.

    # Windows
    ipconfig /flushdns
    
    # macOS
    sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
    
    # Linux
    sudo systemd-resolve --flush-caches
    

    구축 결과 확인 — 이렇게 달라졌어요

    설정 완료 후 며칠 사용해보면 대시보드에서 통계가 쌓이기 시작합니다. 저는 처음에 결과 보고 좀 놀랐거든요. 전체 DNS 요청 중 광고/추적 도메인이 차지하는 비율이 생각보다 훨씬 높았어요.

    ▲ DNS 필터링 대시보드 통계 — 전체 쿼리 중 차단된 비율과 주요 차단 도메인을 실시간으로 확인할 수 있습니다.

    확인 방법은 간단합니다. 아래 사이트에 접속해보세요.

    # 광고 차단 테스트 사이트
    # https://d3ward.github.io/toolz/adblock.html
    # 위 사이트에서 차단율을 확인할 수 있습니다
    
    # DNS 응답 직접 확인
    nslookup pagead2.googlesyndication.com
    # 0.0.0.0 또는 NXDOMAIN이 나오면 정상 차단 중
    

    🎉 정상적으로 동작한다면 유튜브 이외의 대부분 사이트에서 광고가 사라진 걸 느끼실 수 있어요. (유튜브 광고는 같은 도메인을 쓰기 때문에 DNS 필터링으로는 차단이 어렵습니다. 이 부분은 솔직하게 말씀드리는 게 맞는 것 같아요.)

    어떤 걸 선택해야 할까요? — 제 추천

    결론부터 말씀드리면, 처음 시작하시는 분께는 AdGuard Home을 추천드립니다. 이유는 단순해요.

    • ✅ 초기 설정 마법사가 있어서 진입 장벽이 낮음
    • ✅ DoH/DoT를 별도 설정 없이 바로 사용 가능
    • ✅ 클라이언트별 필터링 설정이 직관적
    • ✅ 단일 바이너리라 관리가 단순함

    반면 Pi-hole이 더 나은 경우도 있습니다.

    • ✅ 커뮤니티가 워낙 크다 보니 문제 발생 시 레퍼런스가 훨씬 많음
    • ✅ Gravity 데이터베이스 방식이 대용량 블록리스트 처리에 효율적
    • ✅ 오래된 Raspberry Pi에서도 가볍게 돌아감
    • ✅ 이미 Pi-hole 사용 경험이 있다면 굳이 바꿀 필요 없음

    💡 팁: 두 개를 동시에 운영하면서 하나를 백업 DNS로 쓰는 방법도 있어요. 공유기 설정에서 1차 DNS는 AdGuard Home, 2차 DNS는 Pi-hole으로 설정하면 한 쪽이 다운되더라도 인터넷이 끊기지 않습니다.

    ▲ Pi-hole vs AdGuard Home 선택 가이드 — 사용 목적과 기술 수준에 따른 추천 기준을 정리했습니다.

    마무리 — 한 번 설정해두면 진짜 편합니다

    처음 구축할 때는 포트 충돌이니 DNS 설정이니 좀 헤매긴 했는데, 한번 돌아가기 시작하면 진짜 신경 쓸 게 없어요. 그냥 알아서 다 막아주거든요.

    제가 홈랩에서 이것저것 실험해보면서 느낀 건데, 네트워크 레벨 광고 차단은 홈랩 입문자가 처음 도전하기에 딱 좋은 프로젝트예요. 결과가 눈에 보이고, 실생활에 바로 도움이 되고, 배우는 것도 많거든요. DNS가 어떻게 동작하는지 자연스럽게 익히게 되는 부수 효과도 있고요.

    다음 단계로는 Unbound를 Recursive DNS Resolver(재귀 DNS 리졸버)로 연결해서 외부 DNS 의존도를 완전히 없애는 방법도 있는데, 이건 다음 글에서 다뤄볼게요. 관심 있으신 분들은 기대해 주세요.

    혹시 구축하다가 막히는 부분 있으시면 댓글로 남겨주세요. 제가 겪은 삽질이 더 있으면 추가로 공유해드리겠습니다 😄

    자주 묻는 질문 (FAQ)

    Q. Raspberry Pi 없이도 구축할 수 있나요?

    네, 가능합니다. 집에 항상 켜져 있는 NAS, 미니 PC, 또는 기존 홈서버가 있다면 Docker로 바로 실행할 수 있어요. 저도 별도의 Raspberry Pi 없이 기존 홈서버에서 운영 중입니다.

    Q. 유튜브 광고도 막을 수 있나요?

    아쉽지만 DNS 필터링만으로는 유튜브 광고 차단이 어렵습니다. 유튜브는 광고와 일반 콘텐츠를 같은 도메인에서 제공하기 때문이에요. 유튜브 광고는 브라우저 확장 프로그램(uBlock Origin 등)과 병행해서 사용하시는 걸 권장합니다.

    Q. DNS 서버가 다운되면 인터넷이 끊기나요?

    공유기에 1차 DNS만 Pi-hole/AdGuard Home으로 설정했다면, 서버가 다운될 경우 인터넷 접속이 안 될 수 있습니다. 2차 DNS로 공개 DNS(예: 1.1.1.1)를 설정해두거나, 앞서 언급한 것처럼 두 솔루션을 이중화하는 방법을 권장합니다.

    Q. Pi-hole과 AdGuard Home을 동시에 설치해도 되나요?

    같은 서버에 동시 설치는 포트 53 충돌 때문에 어렵습니다. 다른 서버(또는 VM/컨테이너)에 각각 설치해서 이중화 구성으로 운영하는 방식을 추천합니다.

  • [Cloud] Docker Compose 실전 가이드: 로컬 개발 환경 구축 및 관리

    “팀원 컴퓨터에서는 되는데 제 컴퓨터에서는 왜 안 되죠?”

    인프라 일을 13년 하면서 개발팀에서 가장 많이 들은 말 중 하나입니다. 그리고 솔직히 말씀드리면, 저도 초창기엔 이 문제로 꽤 많이 고생했거든요. 환경변수 하나 차이로 밤새 디버깅하고, OS 버전 달라서 라이브러리 충돌 나고… 생각만 해도 아찔하네요.

    그래서 오늘은 Docker Compose를 활용해서 로컬 개발 환경을 제대로 구축하는 방법을 공유하려고 합니다. “내 컴퓨터에서는 되는데”라는 말을 팀에서 영원히 추방할 수 있는 방법이에요. 실제로 제가 홈랩이랑 팀 프로젝트에서 직접 써보면서 정리한 내용이라 꽤 실용적일 거라 생각합니다.

    ▲ Docker Compose로 구성한 로컬 개발 환경의 전체 구조 — 웹 서버, 앱 서버, 데이터베이스가 하나의 네트워크로 묶이는 모습

    Docker Compose가 뭔지 먼저 짚고 넘어가요

    Docker 자체는 이미 알고 계신 분들이 많을 텐데, Docker Compose(도커 컴포즈)는 조금 다른 개념이에요. 쉽게 말해서, 여러 개의 컨테이너(Container)를 하나의 파일로 정의하고 한 번에 관리하는 도구거든요.

    예를 들어 웹 애플리케이션 하나를 띄우려면 보통 이런 것들이 필요하잖아요:

    • 프론트엔드 서버 (React, Vue 등)
    • 백엔드 API 서버 (Node.js, FastAPI 등)
    • 데이터베이스 (PostgreSQL, MySQL 등)
    • 캐시 서버 (Redis 등)

    이걸 Docker 명령어로 하나하나 실행하면… 솔직히 너무 번거롭더라고요. 컨테이너마다 네트워크 연결하고, 볼륨 설정하고, 환경변수 넣고… 저도 처음엔 그렇게 했었는데 한 달도 안 돼서 포기했어요 ㅎㅎ.

    그런데 Docker Compose를 쓰면 docker-compose.yml이라는 파일 하나에 이 모든 걸 정의하고, 명령어 한 줄로 전체를 올리고 내릴 수 있어요. 개발 생산성 측면에서 정말 게임 체인저였습니다.

    Docker Compose vs. 일반 Docker 명령어 비교

    항목 Docker 단독 사용 Docker Compose 사용
    서비스 시작 컨테이너마다 개별 명령어 실행 docker compose up 하나로 끝
    네트워크 설정 수동으로 네트워크 생성 및 연결 자동으로 네트워크 생성 및 연결
    환경 관리 각 명령어에 -e 옵션 반복 입력 yml 파일에 한 번에 정의
    팀 공유 실행 명령어 문서화 필요 yml 파일을 Git에 올리면 끝
    재현성 낮음 (사람마다 다르게 실행 가능) 높음 (동일한 환경 보장)

    시작 전 준비사항

    본격적으로 들어가기 전에 환경 세팅부터 확인해 봅시다. 요즘은 Docker Desktop을 설치하면 Docker Compose도 함께 딸려오거든요. 예전엔 따로 설치해야 했는데, 이 부분은 많이 편해졌어요.

    1. Docker Desktop 공식 사이트에서 OS에 맞는 버전 다운로드 및 설치
    2. 설치 완료 후 터미널에서 버전 확인
    # Docker 버전 확인
    docker --version
    
    # Docker Compose 버전 확인 (v2 기준)
    docker compose version

    💡 팁: 예전에는 docker-compose(하이픈 포함)로 실행했는데, 요즘 Compose V2부터는 docker compose(스페이스)로 바뀌었어요. 둘 다 동작하긴 하는데, 새 프로젝트라면 V2 방식으로 쓰는 게 좋습니다.

    실전: docker-compose.yml 파일 작성하기

    자, 이제 진짜 시작입니다. 실제 웹 애플리케이션 개발 환경을 예시로 만들어볼게요. Node.js 백엔드 + PostgreSQL 데이터베이스 + Redis 캐시 조합으로 가겠습니다. 제가 홈랩에서 사이드 프로젝트 할 때 자주 쓰는 스택이거든요.

    프로젝트 디렉토리 구조

    my-project/
    ├── docker-compose.yml       # 핵심 설정 파일
    ├── docker-compose.override.yml  # 로컬 개발용 오버라이드
    ├── .env                     # 환경변수 파일
    ├── backend/
    │   ├── Dockerfile
    │   └── src/
    └── frontend/
        ├── Dockerfile
        └── src/

    기본 docker-compose.yml 작성

    version: '3.8'
    
    services:
      # 백엔드 API 서버
      backend:
        build:
          context: ./backend
          dockerfile: Dockerfile
        container_name: myapp-backend
        ports:
          - "3000:3000"
        environment:
          - NODE_ENV=development
          - DATABASE_URL=postgresql://myuser:mypassword@db:5432/mydb
          - REDIS_URL=redis://cache:6379
        volumes:
          - ./backend:/app          # 소스 코드 마운트 (핫 리로드 가능)
          - /app/node_modules       # node_modules는 컨테이너 것 사용
        depends_on:
          db:
            condition: service_healthy  # DB 헬스체크 통과 후 시작
          cache:
            condition: service_started
        networks:
          - app-network
        restart: unless-stopped
    
      # PostgreSQL 데이터베이스
      db:
        image: postgres:15-alpine
        container_name: myapp-db
        environment:
          - POSTGRES_USER=myuser
          - POSTGRES_PASSWORD=mypassword
          - POSTGRES_DB=mydb
        volumes:
          - postgres-data:/var/lib/postgresql/data  # 데이터 영속성 보장
          - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql  # 초기화 스크립트
        ports:
          - "5432:5432"   # 로컬에서 DB 클라이언트로 직접 접속 가능
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
          interval: 10s
          timeout: 5s
          retries: 5
        networks:
          - app-network
    
      # Redis 캐시 서버
      cache:
        image: redis:7-alpine
        container_name: myapp-redis
        ports:
          - "6379:6379"
        volumes:
          - redis-data:/data
        networks:
          - app-network
    
    # 볼륨(Volume) 정의: 컨테이너가 삭제돼도 데이터 유지
    volumes:
      postgres-data:
      redis-data:
    
    # 네트워크 정의: 서비스 간 내부 통신
    networks:
      app-network:
        driver: bridge

    여기서 중요한 포인트! depends_on을 쓸 때 단순히 서비스 이름만 쓰면 컨테이너가 시작된 것만 확인하고 실제로 준비가 됐는지는 모릅니다. condition: service_healthy와 healthcheck를 함께 써야 PostgreSQL이 실제로 쿼리를 받을 준비가 됐을 때 백엔드가 시작돼요. 이거 몰라서 처음에 백엔드가 DB 연결 못 한다고 에러 뜨는 삽질을 꽤 했었더라고요 ㅎㅎ.

    환경변수 파일(.env) 관리

    민감한 정보는 절대 docker-compose.yml에 직접 넣으면 안 됩니다. .env 파일을 따로 만들고 Git에는 올리지 마세요.

    # .env 파일
    POSTGRES_USER=myuser
    POSTGRES_PASSWORD=super_secret_password
    POSTGRES_DB=mydb
    NODE_ENV=development
    APP_PORT=3000
    # docker-compose.yml에서 .env 변수 참조
    services:
      db:
        environment:
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - POSTGRES_DB=${POSTGRES_DB}
    # .gitignore에 반드시 추가
    .env
    .env.local
    .env.production

    ▲ docker-compose.yml로 정의된 서비스들이 내부 네트워크(app-network)로 연결되고, 필요한 포트만 호스트에 노출되는 구조

    개발 환경 전용 오버라이드 파일

    이건 좀 꿀팁인데요. docker-compose.override.yml을 만들면 docker compose up할 때 자동으로 합쳐져서 적용됩니다. 로컬 개발에서만 필요한 설정을 분리할 수 있어서 정말 편하더라고요.

    # docker-compose.override.yml (로컬 개발 전용)
    version: '3.8'
    
    services:
      backend:
        # 개발 중엔 빌드 없이 소스 코드 직접 마운트
        command: npm run dev   # nodemon 등 핫 리로드 명령어
        environment:
          - DEBUG=true
          - LOG_LEVEL=debug
    
      # 개발 환경에서만 DB 관리 UI 추가
      adminer:
        image: adminer
        container_name: myapp-adminer
        ports:
          - "8080:8080"
        networks:
          - app-network

    자주 쓰는 Docker Compose 명령어 모음

    이제 실제로 실행해 봅시다. 제가 매일 쓰는 명령어들 위주로 정리했어요.

    # 전체 서비스 시작 (백그라운드 실행)
    docker compose up -d
    
    # 빌드 포함해서 시작 (코드 변경 후)
    docker compose up -d --build
    
    # 특정 서비스만 시작
    docker compose up -d backend
    
    # 전체 서비스 중지
    docker compose down
    
    # 중지 + 볼륨까지 삭제 (DB 초기화할 때)
    docker compose down -v
    
    # 실행 중인 서비스 상태 확인
    docker compose ps
    
    # 특정 서비스 로그 보기 (실시간)
    docker compose logs -f backend
    
    # 실행 중인 컨테이너에 접속
    docker compose exec backend sh
    
    # 데이터베이스 컨테이너에서 psql 실행
    docker compose exec db psql -U myuser -d mydb
    
    # 서비스 재시작
    docker compose restart backend

    ⚠️ 실제로 겪은 트러블슈팅 사례들

    이론은 깔끔한데, 실제로 쓰다 보면 별별 문제가 다 생기더라고요. 제가 겪었던 것들 공유합니다.

    문제 1: 포트가 이미 사용 중이라는 에러

    # 에러 메시지
    Error response from daemon: Ports are not available: 
    exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: 
    bind: address already in use

    로컬에 PostgreSQL이 이미 설치돼서 실행 중인 경우 자주 발생해요. 해결법은 두 가지예요:

    # 방법 1: 로컬 PostgreSQL 서비스 중지
    sudo systemctl stop postgresql   # Linux
    brew services stop postgresql    # macOS
    
    # 방법 2: docker-compose.yml에서 포트 변경
    ports:
      - "5433:5432"   # 호스트 포트를 5433으로 변경

    문제 2: 볼륨 마운트 후 node_modules 사라짐

    이거 처음 겪으면 진짜 당황스러워요. 소스 코드 볼륨 마운트하면 로컬의 node_modules(없는 경우)가 컨테이너 안의 것을 덮어씌워버리는 현상이거든요.

    # 해결법: node_modules를 별도 볼륨으로 분리
    services:
      backend:
        volumes:
          - ./backend:/app
          - /app/node_modules   # 이 한 줄이 핵심!
                                # 익명 볼륨으로 컨테이너 내부 것을 보호

    문제 3: 컨테이너 간 통신이 안 될 때

    백엔드에서 DB 접속할 때 localhost로 접속하려다가 실패하는 경우가 많아요. 컨테이너 안에서 localhost는 그 컨테이너 자신을 가리키거든요.

    # ❌ 잘못된 방법 (백엔드 컨테이너 안에서)
    DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydb
    
    # ✅ 올바른 방법 (서비스 이름을 호스트로 사용)
    DATABASE_URL=postgresql://myuser:mypassword@db:5432/mydb
    # 'db'는 docker-compose.yml에서 정의한 서비스 이름

    같은 네트워크에 묶인 컨테이너끼리는 서비스 이름이 곧 호스트명이 됩니다. Docker의 내장 DNS가 자동으로 처리해줘요. 이거 알고 나면 진짜 편해집니다.

    문제 4: M1/M2 Mac에서 이미지 아키텍처 오류

    # 에러 메시지
    WARNING: The requested image's platform (linux/amd64) does not match 
    the detected host platform (linux/arm64/v8)
    
    # 해결법: platform 명시
    services:
      db:
        image: postgres:15-alpine
        platform: linux/amd64   # 또는 linux/arm64/v8

    요즘 Apple Silicon Mac 쓰시는 분들 많은데, arm64를 지원하는 이미지를 쓰거나 platform을 명시해주면 해결돼요. 대부분의 공식 이미지들은 멀티 아키텍처를 지원하니까 크게 걱정 안 하셔도 됩니다.

    ✅ 결과 확인: 제대로 떴는지 검증하기

    드디어 됐다! 이제 제대로 동작하는지 확인해봅시다.

    # 전체 서비스 상태 확인
    docker compose ps
    
    # 예상 출력
    NAME              IMAGE                COMMAND                  SERVICE    CREATED        STATUS                    PORTS
    myapp-backend     myapp-backend        "docker-entrypoint.s…"   backend    2 minutes ago  Up 2 minutes              0.0.0.0:3000->3000/tcp
    myapp-db          postgres:15-alpine   "docker-entrypoint.s…"   db         2 minutes ago  Up 2 minutes (healthy)    0.0.0.0:5432->5432/tcp
    myapp-redis       redis:7-alpine       "docker-entrypoint.s…"   cache      2 minutes ago  Up 2 minutes              0.0.0.0:6379->6379/tcp

    STATUS 컬럼에서 Up이면 실행 중, (healthy)면 헬스체크까지 통과한 것입니다. 🎉

    # 네트워크 확인
    docker network ls
    docker network inspect myproject_app-network
    
    # 컨테이너 간 통신 테스트
    docker compose exec backend ping db
    docker compose exec backend ping cache
    
    # 백엔드 API 응답 확인
    curl http://localhost:3000/health

    ▲ docker compose ps 명령어로 확인한 서비스 상태 — 모든 서비스가 Up 상태이고 DB는 healthy 헬스체크까지 통과한 모습

    🎉 팀 협업에서 빛나는 Docker Compose의 진짜 가치

    제가 Docker Compose를 팀 프로젝트에 도입하고 나서 가장 크게 달라진 점은 온보딩 시간이었어요. 예전엔 새 팀원이 오면 환경 세팅하는 데 하루 이상 걸리는 경우도 있었거든요. 근데 이제는 이렇게 끝납니다:

    # 새 팀원 온보딩 전체 과정
    git clone https://github.com/myteam/myproject.git
    cd myproject
    cp .env.example .env   # 환경변수 파일 복사 후 값 채우기
    docker compose up -d   # 끝!

    이 세 줄이면 끝이에요. 진짜로요. OS가 다르든, 로컬에 뭐가 설치돼 있든 상관없이 동일한 환경이 뜹니다. 개발 생산성 측면에서 이게 얼마나 큰 차이인지는 직접 경험해보시면 바로 느끼실 거예요.

    Docker Compose 활용의 주요 이점

    • ✅ 환경 일관성: “내 컴퓨터에서는 되는데” 문제 완전 해결
    • ✅ 빠른 온보딩: 새 팀원도 몇 분 안에 개발 시작 가능
    • ✅ 격리된 환경: 프로젝트별로 독립된 환경, 충돌 없음
    • ✅ 버전 관리: 인프라 설정도 코드로 관리 (Infrastructure as Code)
    • ✅ 프로덕션 근접: 로컬과 운영 환경의 차이 최소화

    ▲ Docker Compose 도입 전후 로컬 개발 환경 비교 — 온보딩 시간, 환경 일관성, 협업 효율성 측면에서의 개선 효과

    자주 묻는 질문 (FAQ)

    Q. Docker Desktop 없이 Docker Compose만 쓸 수 있나요?

    네, Linux 환경에서는 Docker Engine을 설치하고 Compose 플러그인을 별도로 설치하면 돼요. macOS나 Windows라면 Docker Desktop이 가장 간편한 방법이더라고요.

    Q. docker-compose.yml 파일을 Git에 올려도 되나요?

    네, 올려야 합니다! 이게 바로 팀 환경 공유의 핵심이거든요. 단, .env 파일은 절대 올리면 안 됩니다. .env.example 파일을 만들어서 어떤 변수가 필요한지만 공유하세요.

    Q. 프로덕션 배포에도 Docker Compose를 쓰나요?

    소규모 서비스라면 쓸 수 있어요. 하지만 스케일링이나 고가용성이 필요하다면 Kubernetes(쿠버네티스) 같은 오케스트레이션 도구를 고려해야 합니다. 이 부분은 다음 글에서 다룰 예정이에요.

    Q. 컨테이너를 내렸다 올리면 데이터가 사라지나요?

    docker compose down만 하면 볼륨은 유지돼요. 데이터까지 지우려면 docker compose down -v를 써야 하니까 주의하세요!

    마무리: 이제 로컬 개발 환경 걱정은 끝

    오늘 다룬 내용을 정리해볼게요:

    1. Docker Compose의 기본 개념과 일반 Docker 대비 장점
    2. 실전 docker-compose.yml 작성법 (서비스, 볼륨, 네트워크)
    3. 환경변수 분리와 오버라이드 파일 활용
    4. 자주 쓰는 명령어와 실제 트러블슈팅 사례

    처음 Docker Compose를 접하면 yml 파일 문법이 좀 낯설게 느껴질 수 있어요. 저도 들여쓰기 하나 틀려서 에러 뜨는 걸 수십 번은 겪었으니까요. 근데 한 번 손에 익으면 이것 없이 개발하는 게 상상이 안 될 정도로 편해집니다.

    다음 글에서는 Docker Compose로 구성한 환경을 기반으로 CI/CD 파이프라인과 연동하는 방법을 다뤄볼 예정이에요. 로컬에서 테스트한 환경을 그대로 자동화 배포에 활용하는 내용인데, 꽤 실용적인 내용이 될 것 같습니다.

    궁금한 점이나 삽질 경험 있으시면 댓글로 편하게 남겨주세요. 저도 비슷한 거 겪어봤을 확률이 높거든요 😄

  • [Nas] TrueNAS SCALE: Docker 및 Kubernetes 앱 배포 및 관리 완벽 가이드

    [Nas] TrueNAS SCALE: Docker 및 Kubernetes 앱 배포 및 관리 완벽 가이드

    TrueNAS SCALE: Docker 및 Kubernetes 앱 배포 및 관리 완벽 가이드

    안녕하세요, 13년차의 서버실 주인장입니다. 홈랩(HomeLab)을 운영하다 보면 NAS에 이것저것 서비스를 올려보고 싶은 욕구가 스멀스멀 올라오잖아요? 저도 처음엔 단순히 파일 저장용으로 시작했는데, Plex(미디어 서버), Nextcloud(개인 클라우드), Home Assistant(스마트 홈 허브) 같은 다양한 앱들을 돌리고 싶어서 고민이 많았습니다.

    예전에는 일일이 가상머신(Virtual Machine)을 만들어서 설치하곤 했는데, 관리도 어렵고 자원도 많이 먹더라고요. 그러다 컨테이너(Container) 기술인 Docker(도커)와 Kubernetes(쿠버네티스)를 접하게 됐고, NAS에서 이걸 더 쉽게 쓸 방법이 뭘까 고민하던 차에 TrueNAS SCALE을 만나게 됐습니다. TrueNAS SCALE은 리눅스 기반이라 Docker와 Kubernetes를 네이티브(Native)하게 지원하거든요. 특히 TrueNAS SCALE Docker 환경에서 앱을 배포하고 관리하는 경험은 정말 신세계더라고요.

    오늘은 제가 직접 TrueNAS SCALE을 활용해서 Docker와 Kubernetes 앱을 배포하고 관리하면서 겪었던 삽질 경험과 해결 과정, 그리고 효율적인 관리 팁까지 완벽하게 풀어드리려고 합니다. 홈랩에 컨테이너 기반 앱을 올려보고 싶었던 분들이라면 이 글이 큰 도움이 될 거예요!

    TrueNAS SCALE 환경에서 Docker 및 Kubernetes 앱 배포의 전체적인 아키텍처를 보여주는 다이어그램입니다.

    TrueNAS SCALE, Docker, Kubernetes 핵심 개념 이해하기

    본격적인 실전에 들어가기 전에, 우리가 다룰 핵심 기술들이 무엇인지 쉽고 간단하게 짚고 넘어갈 수 있도록, 제가 처음 공부할 때 “이게 뭔 소리야?” 했던 개념들을 멘토처럼 알려드릴게요!

    TrueNAS SCALE: 리눅스 기반의 강력한 NAS 운영체제

    • TrueNAS SCALE은 오픈소스(Open Source) NAS 운영체제인 TrueNAS의 한 버전입니다. 기존 FreeBSD 기반의 TrueNAS CORE와는 다르게 Debian Linux(데비안 리눅스)를 기반으로 하고 있어요.
    • 이 덕분에 컨테이너(Container) 기술인 Docker와 오케스트레이션(Orchestration) 도구인 Kubernetes를 기본적으로 지원하고, 훨씬 더 넓은 범위의 앱 생태계를 활용할 수 있게 됐죠.
    • 강력한 파일 시스템인 ZFS(Z File System)를 기반으로 데이터 무결성(Data Integrity)과 유연한 스토리지 관리를 제공하는 건 기본입니다.

    Docker (도커): 앱을 컨테이너에 담아 쉽게 배포!

    • Docker(도커)는 애플리케이션(Application)과 그 실행에 필요한 모든 요소를 컨테이너라는 독립적인 환경에 패키징(Packaging)하여 배포하고 실행하는 기술입니다. 쉽게 말해, 앱을 하나의 깔끔한 상자에 담아 어디서든 똑같이 실행될 수 있도록 만들어주는 거죠.
    • 장점:
      • 이식성(Portability): 어떤 환경에서든 동일하게 작동합니다. “제 컴퓨터에선 되는데?” 하는 말을 들을 일이 줄어들어요.
      • 격리성(Isolation): 각 앱이 서로 영향을 주지 않고 독립적으로 실행됩니다.
      • 효율성(Efficiency): 가상머신보다 가볍고 빠릅니다.

    Kubernetes (쿠버네티스): 컨테이너 오케스트레이션의 지휘자

    • Kubernetes(쿠버네티스, 줄여서 K8s)는 컨테이너화된 워크로드(Workload)와 서비스를 자동으로 배포하고, 스케일링(Scaling)하며, 관리해주는 오픈소스 시스템입니다. Docker 컨테이너가 많아지면 이걸 효율적으로 관리하는 게 정말 어려워지거든요. 이때 K8s가 마치 지휘자처럼 여러 컨테이너를 조율해줍니다.
    • TrueNAS SCALE Kubernetes 환경에서는 TrueNAS의 ‘Apps’ 기능을 통해 Helm Chart(헬름 차트) 기반의 Kubernetes 앱을 쉽게 배포할 수 있어요.
    • NAS 앱 배포를 자동화하고 안정성을 높이는 데 아주 효과적이죠.

    Dockge (닥지): Docker Compose를 위한 웹 UI

    • TrueNAS SCALE의 내장 Apps 기능도 훌륭하지만, Docker Compose(도커 컴포즈) 파일을 직접 관리하는 데 익숙한 분들에게는 조금 답답할 수 있어요. 이때 Dockge(닥지)가 구원투수로 등장합니다!
    • Dockge는 Docker Compose 파일을 웹 UI(User Interface)를 통해 생성, 편집, 배포, 모니터링할 수 있게 해주는 경량 도구입니다. 제가 직접 써보니 Docker Compose를 활용한 컨테이너 관리가 훨씬 편하더라고요.

    TrueNAS SCALE에서 Docker 및 Kubernetes 앱 실전 배포

    자, 이제 이론은 충분히 봤으니 직접 한번 해봐야죠! 제가 실제로 홈랩에서 앱을 배포하는 과정을 보여드릴게요. TrueNAS SCALE의 ‘Apps’ 기능을 이용하는 방법과 Dockge를 활용하는 두 가지 방법을 모두 알려드리겠습니다.

    1. TrueNAS SCALE 내장 ‘Apps’ 기능 활용하기 (Kubernetes 기반)

    TrueNAS SCALE은 자체적으로 Kubernetes 클러스터를 내장하고 있어서 ‘Apps’ 메뉴를 통해 다양한 앱을 손쉽게 배포할 수 있어요. 주로 Helm Chart(헬름 차트) 기반의 앱들이 제공됩니다.

    1. Apps 기능 활성화 및 스토리지 풀 선택:
      • TrueNAS SCALE 웹 UI에 접속합니다.
      • 좌측 메뉴에서 ‘Apps’를 클릭합니다.
      • ‘Settings’ 탭으로 이동하여 ‘Choose Pool’에서 앱 데이터를 저장할 ZFS 스토리지 풀(Storage Pool)을 선택합니다. 저는 보통 ‘ix-applications’라는 데이터셋(Dataset)이 자동으로 생성되도록 합니다.
      • ‘Save’를 눌러 설정을 저장합니다.
    2. 앱 검색 및 설치:
      • ‘Available Applications’ 탭으로 돌아와 원하는 앱을 검색해요. 예를 들어 ‘Plex’를 검색해 볼까요?
      • Plex 앱을 선택하고 ‘Install’을 클릭합니다.
      • 설치 마법사(Wizard)가 나타나는데, 여기서 앱 이름, Persistent Volume(영구 볼륨), 네트워크 설정, 환경 변수(Environment Variables) 등을 설정할 수 있어요. 특히 볼륨 설정은 앱 데이터가 저장될 위치를 지정하는 중요한 부분이니 신중하게 설정해야 합니다.
      • 필요한 설정을 마친 후 ‘Install’을 클릭하면 앱 배포가 시작됩니다.
    3. 배포된 앱 확인:
      • ‘Installed Applications’ 탭에서 배포된 앱의 상태를 확인할 수 있어요. ‘Deploying’에서 ‘Active’로 바뀌면 정상적으로 실행 중인 것입니다.
      • 앱 옆의 ‘Web UI’ 버튼을 클릭하여 해당 앱의 웹 인터페이스에 접속할 수 있습니다.

    2. Dockge를 활용하여 Docker Compose 앱 배포하기

    TrueNAS SCALE의 Apps 기능도 좋지만, 저는 Docker Compose 파일로 직접 컨테이너 설정을 제어하는 걸 더 선호하는 편입니다. 이때 Dockge TrueNAS 설치가 정말 유용하더라고요. Dockge는 Docker Compose 파일을 웹 UI에서 쉽게 관리할 수 있게 해줍니다. 먼저 Dockge부터 설치해봅시다!

    2.1. Dockge 설치

    Dockge는 Docker 컨테이너로 실행되는데, TrueNAS SCALE의 Shell(쉘)을 통해 Docker 명령어를 직접 입력하여 설치할 수 있어요.

    1. TrueNAS SCALE Shell 접속:
      • TrueNAS SCALE 웹 UI에서 ‘System Settings’ > ‘Shell’로 이동합니다.
    2. Dockge 설치 스크립트 실행:

      다음 명령어를 입력하여 Dockge를 설치합니다. 이 명령어는 Docker Compose를 이용해 Dockge 컨테이너를 실행하고, 필요한 볼륨과 네트워크를 설정해줍니다. 저는 주로 /mnt/pool_name/appdata/dockge 경로에 데이터를 저장합니다.

      mkdir -p /mnt/pool_name/appdata/dockge
      cd /mnt/pool_name/appdata/dockge
      
      curl -L https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml -o compose.yaml
      
      docker compose up -d
      

      여기서 pool_name은 여러분의 ZFS 스토리지 풀 이름으로 바꿔주세요. 예를 들어 /mnt/tank/appdata/dockge 처럼요.

    3. Dockge 웹 UI 접속:

      설치가 완료되면 웹 브라우저에서 http://[TrueNAS_IP]:5001 (기본 포트)로 접속하여 Dockge 웹 UI를 확인할 수 있어요. 처음 접속 시 관리자 계정을 설정하게 됩니다.

    2.2. Dockge를 이용한 Docker Compose 앱 배포

    Dockge에 접속했다면 이제 원하는 Docker Compose 앱을 배포해봅시다. 저는 간단한 Nginx 웹 서버를 예시로 들어볼게요.

    1. 새로운 스택(Stack) 생성:
      • Dockge UI에서 ‘Stacks’ > ‘New Stack’을 클릭합니다.
      • 스택 이름을 입력하고, Docker Compose YAML 파일을 붙여넣어요.
    2. Docker Compose YAML 작성 예시 (Nginx):
      version: '3.8'
      services:
        nginx:
          image: nginx:latest
          container_name: my-nginx
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - /mnt/pool_name/appdata/nginx/html:/usr/share/nginx/html
            - /mnt/pool_name/appdata/nginx/conf:/etc/nginx/conf.d
      

      위 YAML 파일은 Nginx 컨테이너를 실행하고, 호스트의 80번 포트를 컨테이너의 80번 포트에 연결하며, 데이터를 저장할 볼륨을 설정합니다. 역시 pool_name은 여러분의 스토리지 풀 이름으로 바꿔주세요.

    3. 스택 배포:
      • YAML 파일을 붙여넣고 ‘Deploy’ 버튼을 클릭하면 Dockge가 Docker Compose 명령어를 실행하여 컨테이너를 배포해요.
      • 배포 상태와 로그를 실시간으로 확인할 수 있어서 문제 발생 시 디버깅(Debugging)하기 정말 편하더라고요.

    Dockge 웹 UI에서 Docker Compose 스택을 생성하고 설정하는 화면입니다. YAML 파일 편집과 배포가 한눈에 들어와서 편리하죠.

    ⚠️ 삽질 경험 & 트러블슈팅 가이드

    13년차 엔지니어 생활에서 느낀 건, 새로운 기술을 도입할 때 삽질은 숙명이라는 거예요. TrueNAS SCALE에서 컨테이너 앱을 배포하면서 저도 몇 번이나 “아, 이거 왜 안 되지?” 하면서 머리를 쥐어뜯었거든요. 그 경험을 바탕으로 여러분이 겪을 만한 문제와 해결책을 공유합니다.

    1. 스토리지 권한 문제 (Permissions Issue)

    이거 진짜 제일 많이 겪는 문제예요. 특히 Docker 컨테이너가 TrueNAS의 ZFS 데이터셋에 접근할 때 권한이 없어서 파일을 생성하거나 읽지 못하는 경우가 허다하거든요. 컨테이너 내부의 프로세스는 특정 사용자(User)와 그룹(Group)으로 실행되는데, 이 사용자에게 ZFS 데이터셋에 대한 쓰기 권한이 없어서 생기는 문제예요.

    • 해결책:
      1. ACL(Access Control List) 설정: TrueNAS 웹 UI에서 해당 데이터셋의 ‘Edit ACL’을 통해 ‘Default ACL’을 설정해주는 게 가장 깔끔합니다. ‘OPEN’ 프리셋을 적용하고, ‘Apply permissions recursively’를 체크하여 하위 폴더까지 적용해줘요.
      2. Shell에서 권한 변경: 급하게 테스트할 때는 Shell에서 chmod와 chown 명령어를 사용하기도 합니다.
        # 소유자를 root:wheel로 변경 (컨테이너가 보통 root로 실행될 때)
        sudo chown -R root:wheel /mnt/pool_name/appdata/your_app
        
        # 모든 사용자에게 읽기/쓰기/실행 권한 부여 (주의: 보안에 취약할 수 있음)
        sudo chmod -R 777 /mnt/pool_name/appdata/your_app
        

        하지만 chmod 777은 보안상 좋지 않으니, 컨테이너가 필요로 하는 최소한의 권한을 부여하는 것을 권장합니다. 보통 PUID/PGID(Process User ID/Group ID) 환경 변수를 통해 컨테이너 내부 사용자 ID를 지정하는 방식으로 해결하더라고요.

    2. 네트워크 설정 및 포트 충돌

    컨테이너 앱이 외부와 통신하려면 네트워크 설정이 중요한데, 특히 포트(Port) 충돌이 자주 발생해요.

    • 문제: 이미 TrueNAS 자체 서비스(예: SMB, SSH)나 다른 컨테이너가 사용 중인 포트를 앱이 사용하려고 할 때 생깁니다.
    • 해결책:
      • 사용 가능한 포트 확인: netstat -tulnp 명령어를 Shell에서 실행하여 현재 사용 중인 포트를 확인해요.
      • 포트 변경: 앱 설정이나 Docker Compose YAML 파일에서 호스트 포트를 다른 사용 가능한 포트로 변경합니다. 예를 들어 Nginx의 80번 포트가 충돌한다면 "8080:80"처럼 변경할 수 있어요.
      • Host Network 사용 시 주의: TrueNAS SCALE의 Apps에서는 ‘Host Network’ 옵션을 제공하는데, 이는 컨테이너가 호스트의 네트워크 스택을 직접 사용하게 하여 성능상 이점이 있지만, 포트 충돌 가능성이 더 높아집니다. 신중하게 사용해야 해요.

    3. 앱 업데이트 후 데이터 유실/오류

    컨테이너 앱을 업데이트하다가 데이터가 날아가거나 앱이 실행되지 않는 경험, 해보셨나요? 😭 저도 예전에 한번 겪고 식겁한 적이 있습니다.

    • 해결책:
      • 백업(Backup) 필수: 업데이트 전에는 항상 중요한 데이터를 백업해둬야 해요. ZFS 스냅샷(Snapshot) 기능을 활용하면 매우 편리하거든요.
      • 볼륨(Volume) 분리: 컨테이너 이미지와 데이터를 저장하는 볼륨을 분리하여 사용하면, 앱을 업데이트하거나 다시 배포해도 데이터는 안전하게 유지됩니다. Dockge의 Docker Compose YAML 예시에서도 볼륨을 명시적으로 분리했죠.
      • 업데이트 전 로그 확인: 새로운 버전의 변경 사항(Changelog)을 미리 확인하여 호환성 문제를 예측하고 대비해요.

    ✅ 배포된 앱 검증 및 결과 확인

    수많은 삽질 끝에 드디어 앱 배포에 성공했어요! 이제 앱이 제대로 작동하는지 확인해봐야죠. 저는 주로 다음 세 가지를 확인합니다.

    1. 웹 UI 접속 확인: 배포한 앱의 웹 인터페이스에 접속하여 정상적으로 화면이 뜨고 로그인, 기능 사용이 가능한지 확인해요. 예를 들어 Nginx라면 웹 브라우저에서 TrueNAS IP로 접속했을 때 기본 페이지가 보여야 하죠.
    2. 로그 확인: 앱이 제대로 작동하지 않을 때는 로그를 확인하는 게 가장 중요합니다.
      • TrueNAS SCALE Apps의 경우: ‘Installed Applications’에서 해당 앱을 선택하고 ‘Logs’ 탭을 확인해요.
      • Dockge를 통해 배포한 Docker Compose 앱의 경우: Dockge UI에서 해당 스택을 선택하면 실시간 로그를 확인할 수 있어요. 또는 TrueNAS Shell에서 docker logs [컨테이너_이름] 명령어를 사용합니다.
    3. 리소스 모니터링: TrueNAS SCALE 대시보드에서 CPU, RAM, 네트워크 사용량 등을 확인하여 앱이 과도하게 리소스를 소모하고 있지 않은지 점검해요. 특히 RAM 사용량은 컨테이너 앱이 많아질수록 중요해지거든요.

    성공적으로 배포된 Plex 미디어 서버의 대시보드 화면입니다. TrueNAS SCALE 위에서 컨테이너 앱들이 안정적으로 작동하는 것을 확인할 수 있습니다.

    🎉 마무리: TrueNAS SCALE로 홈랩을 더욱 강력하게!

    오늘은 TrueNAS SCALE에서 Docker와 Kubernetes 앱을 배포하고 관리하는 완벽 가이드를 함께 살펴봤습니다. 처음엔 좀 복잡하게 느껴질 수도 있지만, 한번 제대로 세팅해두면 정말 편리하고 강력한 홈랩 환경을 구축할 수 있어요.

    TrueNAS SCALE의 내장 ‘Apps’ 기능으로 Kubernetes 기반의 안정적인 앱 배포를 경험하고, Dockge TrueNAS 설치를 통해 Docker Compose 파일을 직접 제어하며 유연하게 컨테이너 관리를 하는 두 가지 방법을 모두 알려드렸는데요. 저는 개인적으로 Dockge를 통한 Docker Compose 관리가 훨씬 손에 익고, 제어권이 많아서 좋더라고요. 하지만 초보자분들이나 복잡한 설정 없이 바로 사용하고 싶다면 TrueNAS Apps도 훌륭한 선택지입니다.

    이런 삽질과 학습 과정을 통해 저의 NAS 앱 배포 경험치도 한 단계 올라간 것 같아요. 여러분도 저처럼 TrueNAS SCALE을 활용해서 나만의 강력한 서버실을 만들어보세요. 다음번에는 Ingress(인그레스, 외부 트래픽 진입점) 설정이나 Persistent Volume(영구 볼륨)의 고급 활용법에 대해 다뤄보면 어떨까 싶네요!

    TrueNAS SCALE에서 앱을 배포하는 두 가지 주요 방법, 내장 Apps와 Dockge를 통한 Docker Compose 활용법을 비교한 요약입니다.

  • [Nas] TrueNAS CORE vs SCALE: 홈랩 및 소규모 비즈니스 NAS 선택 가이드

    [Nas] TrueNAS CORE vs SCALE: 홈랩 및 소규모 비즈니스 NAS 선택 가이드

    안녕하세요, 13년차 서버실입니다.

    홈랩 운영하시는 분들이나 소규모 비즈니스를 위한 NAS를 고민하시는 분들이라면 한 번쯤 TrueNAS라는 이름을 들어보셨을 거예요. 저도 처음엔 단순히 ‘FreeNAS’ 시절부터 쭉 써왔던 터라 익숙한 이름이었는데, 어느새 TrueNAS CORE와 TrueNAS SCALE이라는 두 가지 버전으로 나뉘어 있더라고요. ‘도대체 뭘 선택해야 하지?’ 저도 꽤 고민하고 삽질 좀 했거든요. 그래서 오늘은 제가 직접 경험한 것을 바탕으로 TrueNAS CORE vs SCALE의 차이점과 여러분의 환경에 맞는 선택 가이드를 알려드릴게요. 이 글이 여러분의 현명한 TrueNAS 선택에 도움이 되길 바라요.

    TrueNAS, CORE와 SCALE 개념 이해하기

    TrueNAS는 FreeBSD 기반의 TrueNAS CORE와 Linux 기반의 TrueNAS SCALE로 나뉩니다. 둘 다 ZFS 파일 시스템을 기반으로 안정적인 데이터 저장과 관리 기능을 제공하는 NAS 운영체제(OS)죠. 쉽게 말해, 여러분의 하드웨어를 강력한 네트워크 스토리지 서버로 만들어주는 소프트웨어라고 생각하면 돼요. TrueNAS CORE는 전통적인 NAS 기능에 충실하고, TrueNAS SCALE은 여기에 컨테이너(Container)와 가상 머신(Virtual Machine, VM) 기능을 더해 확장성을 높인 버전이라고 보면 돼요. 사실상 NAS OS 비교의 핵심이죠.

    TrueNAS CORE 깊이 보기: 전통의 강자

    TrueNAS CORE는 오랫동안 FreeNAS라는 이름으로 사랑받아온 전통적인 버전입니다. FreeBSD 운영체제를 기반으로 하고 있죠.

    장점:

    • 안정성(Stability): FreeBSD 기반이라 굉장히 안정적이에요. 오랜 기간 검증된 만큼 데이터 안정성을 최우선으로 생각한다면 이만한 게 없어요. 제가 홈랩에서 10년 넘게 굴려봤는데, 정말 든든하더라고요.
    • 성숙한 기능(Mature Features): ZFS 파일 시스템, 다양한 프로토콜(SMB, NFS, iSCSI, FTP 등), 플러그인(Plugins) 기반의 추가 기능 등 NAS에 필요한 모든 기능이 완벽하게 구현되어 있어요.
    • 낮은 리소스 요구량(Lower Resource Footprint): SCALE에 비해 상대적으로 낮은 하드웨어 사양에서도 좋은 성능을 보여줘요. 특히 오래된 하드웨어로 NAS를 구축하려는 분들께는 아주 매력적인 선택지죠.

    단점:

    • 확장성 제한(Limited Extensibility): 플러그인 외에는 추가 기능을 확장하기가 쉽지 않아요. Docker 컨테이너나 가상 머신을 직접 구동하기 어렵다는 점이 가장 큰 단점이에요.
    • 상대적으로 적은 커뮤니티 자료(Smaller Community for Advanced Features): 전통적인 NAS 기능에는 자료가 많지만, 최신 개발 환경을 위한 자료는 SCALE에 비해 적은 편이에요.

    간단히 말해, ‘나는 그냥 튼튼한 데이터 저장소가 필요하고, 부가 기능은 크게 중요하지 않다!’ 하시는 분들께 CORE는 최고의 선택이 될 거예요. 제가 처음에 홈랩을 구성할 때도 CORE를 썼는데, 정말 별 탈 없이 잘 썼거든요. 안정성 하나는 끝내줍니다. ✅

    TrueNAS SCALE 깊이 보기: 미래 지향적인 올인원

    자, 다음은 요즘 핫한 TrueNAS SCALE입니다. CORE와 달리 Linux 기반(Debian)으로 만들어졌어요. 여기서 큰 차이가 발생하죠.

    장점:

    • 컨테이너 및 가상화 지원(Container & Virtualization Support): Docker 컨테이너와 Kubernetes(쿠버네티스)를 통한 앱 배포, KVM 기반의 가상 머신을 직접 구동할 수 있다는 점이 가장 큰 장점이에요. 홈랩에서 다양한 서비스를 한 번에 돌리고 싶을 때 정말 강력해요. 제가 Nextcloud, Plex, Home Assistant 등을 전부 SCALE 위에서 컨테이너로 돌리고 있는데, 관리도 편하고 성능도 아주 만족스러워요. 🎉
    • 확장성(Scalability): 기존 CORE보다 훨씬 유연하게 기능을 확장할 수 있어요. 특히 TrueCharts 같은 커뮤니티 앱 스토어를 통해 수많은 앱을 쉽게 설치하고 관리할 수 있죠.
    • 클러스터링(Clustering) 가능: 여러 TrueNAS SCALE 서버를 묶어 스케일-아웃(Scale-out) 스토리지를 구축할 수 있어요. 소규모 비즈니스 환경에서 나중에 확장을 고려한다면 이 기능이 정말 중요할 수 있죠.

    단점:

    • 상대적으로 높은 리소스 요구량(Higher Resource Footprint): Linux 커널과 컨테이너 환경 때문에 CORE보다 더 많은 RAM과 CPU 리소스가 필요해요. 오래된 하드웨어에서는 버벅일 수 있죠.
    • 새로운 기능의 안정성(New Features Stability): CORE에 비해 역사가 짧기 때문에, 새로운 기능들이 아직 완벽하게 안정화되지 않았을 가능성도 있어요. 물론 지금은 많이 안정화되었지만, 초기에는 잔버그도 좀 있었거든요. 삽질 좀 했습니다 ㅎㅎ
    • 복잡성(Complexity): 컨테이너, VM, Kubernetes 등 다룰 수 있는 기능이 많아지면서 CORE에 비해 학습 곡선이 가파를 수 있어요. 초보자에게는 좀 어렵게 느껴질 수도 있죠.

    SCALE은 ‘나는 NAS 기능뿐만 아니라, 홈 서버나 개발 서버 역할까지 한 번에 다 하고 싶다!’ 하시는 분들을 위한 올인원(All-in-one) 솔루션이라고 보면 돼요. 저도 결국 SCALE로 넘어왔는데, 정말 만족하면서 쓰고 있어요. 💡

    TrueNAS CORE와 SCALE의 핵심 차이점을 한눈에 볼 수 있는 아키텍처 비교 다이어그램입니다.

    홈랩 사용자를 위한 TrueNAS 선택 가이드

    이제 여러분의 상황에 맞춰 어떤 TrueNAS를 선택해야 할지 고민해볼 시간이에요. 먼저 홈랩(Homelab) 환경부터 살펴볼까요?

    TrueNAS CORE를 추천하는 경우:

    • 안정적인 파일 서버가 최우선: 오직 데이터 저장과 공유 기능만 필요하고, 안정성이 가장 중요하다고 생각한다면 CORE가 좋아요.
    • 하드웨어 리소스가 제한적: 오래된 PC나 저사양 서버를 쓸 계획이라면 CORE가 리소스를 덜 먹어서 효율적이에요.
    • NAS 기능 외의 복잡한 설정은 피하고 싶다: Docker나 VM에 대한 지식이 없거나, 굳이 배우고 싶지 않다면 CORE가 훨씬 직관적이에요.

    TrueNAS SCALE을 추천하는 경우:

    • NAS 외에 다양한 서비스를 한 서버에서 운영하고 싶다: Plex 미디어 서버, Nextcloud 개인 클라우드, Home Assistant 스마트 홈 허브 등 다양한 애플리케이션을 컨테이너로 돌리고 싶다면 SCALE이 압도적으로 유리해요.
    • 가상 머신(VM)을 활용할 계획: 윈도우나 리눅스 VM을 TrueNAS 위에서 구동하고 싶다면 KVM을 지원하는 SCALE이 유일한 선택지에요.
    • 새로운 기술과 확장성에 관심이 많다: Docker, Kubernetes 같은 최신 기술을 홈랩에서 직접 경험해보고 싶다면 SCALE이 제격이에요. 저도 이 점 때문에 SCALE로 넘어왔죠!

    홈랩에서 TrueNAS CORE와 SCALE을 어떻게 활용할 수 있는지 보여주는 인포그래픽입니다.

    소규모 비즈니스 사용자를 위한 TrueNAS 선택 가이드

    그럼 소규모 비즈니스(Small Business) 환경에서는 어떨까요? 여기서는 안정성과 확장성, 그리고 관리의 용이성이 더욱 중요해져요.

    TrueNAS CORE를 추천하는 경우:

    • 주요 목적이 파일 서버 및 백업: 직원 간 파일 공유, 중요 데이터 백업 등 기본적인 NAS 기능이 핵심이라면 CORE의 검증된 안정성이 큰 장점이에요.
    • IT 인력이 제한적: 복잡한 컨테이너 환경 관리 부담 없이, 안정적인 스토리지만 운영하고 싶을 때 CORE가 더 적합할 수 있어요.
    • 비용 효율성: 초기 하드웨어 투자 비용을 절감하고 싶을 때, CORE는 낮은 사양에서도 충분한 성능을 제공해요.

    TrueNAS SCALE을 추천하는 경우:

    • 내부 서비스(Internal Services) 확장 계획: 사내 Git 서버, 프로젝트 관리 툴, CI/CD 파이프라인 등 다양한 내부 서비스를 NAS 위에서 통합 운영하고 싶다면 SCALE이 효율적이에요.
    • 미래 확장성을 고려: 향후 데이터 증가나 서비스 확장에 대비하여 스케일-아웃(Scale-out) 클러스터링을 염두에 둔다면 SCALE이 유리해요.
    • 가상화 환경 통합: 기존에 운영 중인 가상화 환경(VMware, Proxmox 등)에 TrueNAS를 통합하거나, TrueNAS 자체에서 VM을 구동해야 한다면 SCALE이 답이에요.

    사실 소규모 비즈니스에서도 ‘무조건 CORE가 좋다’ 또는 ‘무조건 SCALE이 좋다’고 말하기는 어려워요. 비즈니스의 특성과 미래 계획에 따라 신중하게 선택해야 하거든요. 저도 컨설팅을 진행할 때 항상 고객사의 상황을 먼저 파악해요. ⚠️

    주의사항 및 삽질 경험 공유

    제가 직접 TrueNAS를 사용하면서 겪었던 몇 가지 삽질 경험과 주의사항을 공유해 드릴게요.

    1. 하드웨어 요구사항:
      특히 TrueNAS SCALE은 CORE보다 RAM과 CPU를 더 많이 써요. 제가 처음엔 CORE 쓰던 서버에 그냥 SCALE을 올렸다가 버벅이는 경험을 했거든요. 특히 Docker 컨테이너나 VM을 많이 돌릴 계획이라면 최소 16GB RAM (개인적으로는 32GB 이상 권장)과 멀티코어 CPU는 필수라고 생각해요. 저도 결국 RAM 업그레이드를 했더니 훨씬 쾌적해졌어요.
    2. 마이그레이션(Migration) 고려:
      만약 기존에 TrueNAS CORE를 쓰고 계시다가 SCALE로 넘어가고 싶으시다면, 데이터 백업은 필수에요. CORE에서 SCALE로의 직접적인 인플레이스(In-place) 업그레이드는 가능하지만, 항상 예기치 않은 문제가 발생할 수 있거든요. 저도 괜히 한번 믿었다가 데이터 날릴 뻔했어요… 😱 꼭 백업하시고, 가능하다면 새로운 하드웨어에 SCALE을 새로 설치하고 데이터를 옮기는 걸 추천해요.
    3. ZFS 설정의 중요성:
      TrueNAS의 핵심은 ZFS에요. 풀(Pool) 구성, 데이터셋(Dataset) 설정, 스냅샷(Snapshot) 주기 등을 처음부터 잘 계획해야 나중에 후회하지 않아요. 특히 스냅샷은 랜섬웨어(Ransomware) 같은 위협으로부터 데이터를 보호하는 데 정말 중요하니까요. 저도 예전에 한번 실수로 중요한 데이터를 지운 적이 있었는데, 스냅샷 덕분에 살린 경험이 있어요. 💡

    TrueNAS CORE에서 SCALE로 안전하게 마이그레이션하는 과정을 보여주는 흐름도입니다.

    두 버전 한눈에 비교하기

    두 버전을 한눈에 비교할 수 있도록 표로 정리해 봤어요.

    구분 TrueNAS CORE TrueNAS SCALE
    기반 OS FreeBSD Debian Linux
    주요 기능 안정적인 NAS (ZFS, SMB, NFS, iSCSI, 플러그인) NAS + 컨테이너 (Docker, Kubernetes) + 가상 머신 (KVM)
    주요 용도 순수 파일 서버, 데이터 백업, 고신뢰성 스토리지 올인원 홈 서버, 개발 환경, 클러스터링 스토리지
    하드웨어 요구사항 상대적으로 낮음 (8GB RAM 권장) 상대적으로 높음 (16GB RAM 이상 권장)
    확장성 플러그인 위주, 제한적 컨테이너 앱, VM, 클러스터링으로 유연하게 확장
    학습 곡선 쉬운 편 상대적으로 가파름

    TrueNAS CORE와 SCALE의 주요 특징을 비교한 표를 시각적으로 보여주는 차트입니다.

    마무리: 당신의 TrueNAS는?

    오늘은 TrueNAS CORE와 SCALE 중에서 어떤 것을 선택해야 할지, 제 13년차 인프라 엔지니어 경험을 바탕으로 이야기해 봤어요.

    결론적으로 말씀드리면, ‘정답은 없다!’ 이에요.

    • 안정적인 파일 저장 기능만 필요하고, 하드웨어 사양이 낮다면 TrueNAS CORE.
    • 다양한 컨테이너 앱이나 가상 머신을 돌리고 싶고, 충분한 하드웨어 리소스가 있다면 TrueNAS SCALE.

    이렇게 정리할 수 있을 것 같아요.

    어떤 버전을 선택하시든, TrueNAS는 강력한 NAS 솔루션임에는 틀림없어요. 여러분의 환경과 목적에 맞는 최적의 선택을 하시길 바라면서, 궁금한 점이 있다면 언제든지 댓글로 남겨주세요! 다음번에는 TrueNAS SCALE에서 Docker 컨테이너를 활용하는 방법에 대해 더 자세히 다뤄볼까 합니다. 기대해주세요! 😄