Lobsters

My self-hosted infrastructure with Incus OS

Incus OS로 구축한 셀프호스팅 인프라

저자는 가정용 노트북 한 대에서 Incus OS와 약 20개의 시스템 컨테이너를 운영하며 서비스를 자동으로 배포하고 관리합니다. 기본 거부 네트워크, 인스턴스별 시크릿 암호화, 자동 업데이트와 백업을 결합했지만, 단일 장비라 장애 시 전체 서비스가 중단됩니다.

에디터 노트

이 구성의 강점은 셀프호스팅에서 흔히 수작업으로 남는 설정을 Git 선언과 재생성 절차로 묶었다는 점입니다. 인스턴스를 통째로 재구축하고 통신을 기본 차단하며 시크릿을 서비스별 키로 분리하는 방식은 침해 이후의 잔존과 내부 확산을 줄이는 데 직접 대응합니다. 반면 이 자동화는 서비스 변경 때 1~2분의 중단을 감수하며, 단일 노트북과 회선에 의존하는 가용성 한계는 그대로 둡니다. Lobsters 댓글은 Incus 학습 경험과 incus-compose 활용 사례를 보태고, NixOS 구성은 작업량이 적어 보인다는 비교도 제기합니다. 이는 서로 다른 도구의 우열을 입증하기보다 운영 방식의 선택이 다름을 보여줍니다. 저자도 이 구성이 대부분에게 과하다고 밝히며, 이번 설계의 성과는 고가용성보다 재현 가능한 개인 운영 환경과 보안 경계에 있습니다.

AI 요약

저자는 7개월 동안 가정용 셀프호스팅 환경을 다시 구축했습니다. 목표는 보안을 강화하고 운영을 자동화하며 문제가 생기면 처음부터 재구축하는 것이었습니다. SecNumCloud와 ISO 27001 환경에서 얻은 아이디어를 적용했지만, 일반 가정용 서버에는 과할 수 있다고 설명합니다. 서버는 RAM 16GB 노트북 한 대이며, 운영체제는 Incus만 실행하는 불변 시스템인 Incus OS입니다.

구성과 배포

약 20개의 Ubuntu 시스템 컨테이너가 서비스별로 동작하고, 민감한 작업에는 가상 머신 2대를 씁니다. 각 시스템 컨테이너 안에서는 Podman 컨테이너를 실행하며, Quadlet 파일로 systemd 서비스를 정의합니다. Nextcloud, Forgejo, Immich, PeerTube, Vaultwarden, 모니터링 도구 등을 운영합니다. 구성은 OpenTofu와 cloud-init으로 Git 저장소에 선언합니다.

각 컨테이너는 Ubuntu cloud image에서 새로 만듭니다. cloud-init이 첫 부팅 때 시스템 업데이트, Podman 설치, 서비스 설정, 시크릿 복호화와 실행을 맡습니다. 설정이 바뀌면 OpenTofu가 인스턴스를 삭제하고 다시 만듭니다. 애플리케이션 데이터와 Podman 저장소 등만 별도 Incus 볼륨에 남깁니다. 변경 중 서비스가 1~2분 중단되지만, 수동 설정이 누적되는 구성 드리프트를 막고 재부팅 뒤에도 선언한 상태로 돌아오는 방식입니다.

접근 통제와 네트워크

시스템 컨테이너는 권한 없는(unprivileged) 형태로 실행합니다. 내부 브리지의 Incus ACL은 기본적으로 모든 통신을 양방향에서 차단합니다. 필요한 연결만 OpenTofu에 목적과 함께 선언합니다. 인터넷으로 나가는 트래픽도 대부분 차단하고, 허용 도메인을 관리하는 HTTP 프록시와 패키지·컨테이너 이미지 캐시를 거치게 합니다. 예외 연결은 ACL에 명시합니다.

인터넷 트래픽은 물리 네트워크에 연결된 HAProxy 가상 머신을 거쳐 공개용 Caddy로 전달됩니다. HAProxy는 원본 IP를 PROXY protocol로 전달하지만 TLS를 종료하지 않고 인증서도 보관하지 않습니다. CrowdSec은 Loki에 모인 Caddy, Forgejo, Nextcloud 로그와 커뮤니티 차단 목록을 활용해 악성 IP를 nftables에서 차단합니다. VPN 전용 Caddy를 공개용과 분리해 관리 도구를 외부에 노출하지 않습니다. Immich는 공개 연결에서 공유 링크만 제공하고 사진 탐색과 업로드는 VPN으로 제한합니다.

시크릿, 업데이트와 복구

시크릿은 SOPS와 age로 암호화해 코드와 함께 보관합니다. 각 인스턴스의 age 개인 키는 해당 인스턴스 볼륨에 두며, 서비스 시크릿은 그 인스턴스와 운영자의 워크스테이션 키만 복호화할 수 있습니다. 부팅 시 시크릿을 일회성 시스템 디스크에 복호화하고, gitleaks를 실행하는 사전 커밋 훅으로 저장소에 시크릿이 들어오는 일을 막습니다.

Incus OS는 Secure Boot와 A/B 업데이트를 지원하며, TPM 기반 디스크 암호화로 자동 재부팅을 구성합니다. Ubuntu는 unattended-upgrades를 사용하고, Podman auto-update가 컨테이너 이미지를 갱신합니다. 이미지 태그는 주 버전에 고정해 주요 버전 변경은 Git에서 직접 처리합니다. 데이터는 Incus의 ZFS 스냅샷으로 2주간 보관하고, restic으로 매일 암호화해 S3에 백업합니다. S3 버전 관리로 삭제된 백업을 일정 기간 복구할 수 있도록 했습니다.

Prometheus는 인스턴스와 프록시 등의 지표를 수집하고, Vector가 systemd 로그를 Loki로 보냅니다. Alertmanager는 서비스 장애를 알립니다. 저자는 가장 큰 가용성 한계가 단일 장비와 가정용 인터넷 회선이라고 밝힙니다. 장비나 회선이 끊기면 전체 서비스가 중단되며, 공개 프록시를 재구축하는 동안에도 1~2분가량 접속이 끊깁니다. Incus 클러스터 기능은 현재 규모에는 필요하지 않다고 판단했습니다.

어려웠던 점과 남은 작업

cloud-init에서 SOPS를 실행하려고 SOPS 자체를 Podman 컨테이너로 구동했습니다. 양방향 기본 차단 ACL에서는 두 인스턴스 간 연결을 양쪽 규칙에 모두 허용해야 했고, OpenTofu 리소스 실행 순서도 프록시와 이미지 미러의 준비 상태에 맞춰야 했습니다. CrowdSec 구성과 여러 역방향 프록시를 지나는 원본 IP 및 HTTP 헤더 처리도 까다로웠습니다. 저자는 로그 필터링, CrowdSec 시나리오 확장, Alertmanager 개선, Ubuntu 인스턴스의 전체 재구축 방식 업데이트를 후속 과제로 꼽습니다.

Lobsters 반응

  • @metasyn — 최근 IncusOS를 배우기 시작했는데 전반적으로 정말 즐겁습니다. 배우면서 Incus 관련 자료 목록도 만들었습니다. 특히 incus-compose를 즐겨 쓰는데, 바인드 마운트용 파일을 미리 넣는 등 편의 기능이 좋고, 여기저기서 구한 Docker Compose 소프트웨어와도 호환성이 높습니다. 각각을 Incus 프로젝트에 넣어 쉽게 정리하거나 재시작할 수 있습니다. 작성자가 모든 걸 과하게 구성했다고 말하지만 배우는 과정 자체가 재미있기도 합니다. 전반적으로 영감을 주는 글입니다.
    • @veqq — IncusOS를 어디에 쓰시나요? 클라우드를 잘 모르는 사람으로서 문서를 읽어도 무슨 말인지 잘 모르겠지만, 이름에 'OS'가 들어가는 건 마음에 듭니다.
    • @metasyn — 각각을 별도 incus-compose 스택으로 씁니다. bandcamp-sync는 cron 일정에 따라 Bandcamp 구매 음악을 공유 볼륨에 내려받습니다. slskd로 사람들과 파일을 공유하고 다른 볼륨에 다운로드합니다. beets가 slskd와 Bandcamp의 음악을 정리된 볼륨으로 가져온 뒤 slskd에서 다시 공유합니다. restic은 전체를 Backblaze에 백업하고, SSH 컨테이너는 제가 *arr와 Navidrome을 운영하는 다른 VPS로 동기화합니다. 요약하면 음악을 정리하고 다운로드하고 공유하고 스트리밍하고 백업합니다. 주로 배우는 중이지만 언젠가는 클라우드 VPS 하나를 로컬 장비로 대체하고 싶습니다. Incus 클러스터도 배우고 싶은데 NUC가 하나 더 필요합니다.
  • @zie — Incus를 한동안 써왔고 Incus OS 발표 때 관심이 생겼지만 아직 사용해 볼 기회는 없었습니다. 직접 써보고 글까지 써줘서 반갑습니다. 한 번 시험해 볼 만해 보입니다.
  • @msangi — 정말 멋진 구성입니다. 다만 제가 NixOS로 구성한 것보다 일이 훨씬 많아 보입니다.

원문: Solène / 번역·요약: Trawling