본문 바로가기
카테고리 없음

Vaultwarden — 내 비밀번호는 내 서버에 (NAT 루프백 해결) — 홈랩 입문 11편

by DDlabx 2026. 7. 10.

Vaultwarden은 비밀번호를 남의 클라우드가 아니라 내 서버에 저장하는 셀프호스팅 비밀번호 관리자입니다. 컨테이너 하나로 돌아가면서 유료 기능까지 모두 쓸 수 있어 홈랩에서 가장 인기 있는 앱 중 하나죠. 이 글에서는 Vaultwarden 설치와 도메인 연결, 그리고 집 안에서만 접속이 안 되는 'NAT 루프백' 문제를 앞서 설치한 AdGuard로 해결한 과정을 정리합니다.

이 글은 10편(Immich 사진 백업)에서 이어집니다. 8편(SSL)의 https 환경과 9편(AdGuard Home)이 준비돼 있어야 이번 편을 그대로 따라올 수 있습니다.

Bitwarden과 Vaultwarden의 관계, 그리고 설치

먼저 이름부터 정리하면, Bitwarden은 원조 비밀번호 관리 서비스이고 Vaultwarden은 그 서버를 가볍게 다시 만든 비공식 구현체입니다. 공식 Bitwarden 서버는 무거운 반면 Vaultwarden은 컨테이너 하나로 동작하면서 유료 기능까지 제공하므로, 홈랩에서는 대부분 Vaultwarden을 씁니다. 중요한 점은 서버만 Vaultwarden이고, 접속에 쓰는 앱과 브라우저 확장은 공식 Bitwarden 클라이언트를 그대로 사용한다는 것입니다.

한 가지 전제가 있습니다. Vaultwarden은 비밀번호를 다루기 때문에 브라우저가 보안 컨텍스트(https)를 요구하며, http 환경에서는 기능이 제대로 동작하지 않습니다. 그래서 8편에서 만든 SSL 인프라가 필수입니다. 설치는 작업 폴더를 만들고 docker-compose.yml을 작성하는 것으로 시작합니다.

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vault.ddlabx-home.duckdns.org"
      SIGNUPS_ALLOWED: "true"
    volumes:
      - ./data:/data
    ports:
      - "8222:80"

DOMAIN에는 실제로 접속할 https 주소를 정확히 넣어야 이후 기능이 정상 동작합니다. 포트를 8222:80으로 매핑한 이유는 컨테이너 내부는 80번을 쓰지만 호스트의 80번은 이미 리버스 프록시(NPM)가 점유하고 있기 때문입니다. SIGNUPS_ALLOWED는 최초 계정 생성을 위해 일단 true로 두지만, 계정을 만든 직후 반드시 false로 바꿔야 합니다. 비밀번호 금고 주소가 노출됐을 때 아무나 가입하는 것을 막기 위해서입니다. docker compose up -d로 실행한 뒤, NPM에서 프록시 호스트를 추가합니다. Domain Names에 vault.ddlabx-home.duckdns.org, Scheme은 http, Forward Hostname/IP는 서버 내부 IP, Forward Port는 8222를 넣고 Websockets Support를 켠 다음, SSL 탭에서 인증서를 발급받으면 됩니다.

 

집에서만 접속이 안 된다 — NAT 루프백 문제

설정을 마치고 집 PC 브라우저에서 https://vault.ddlabx-home.duckdns.org에 접속했는데, 화면에 ERR_CONNECTION_TIMED_OUT이 뜨며 연결이 되지 않았습니다. 서버가 잘못된 줄 알았지만, 하나씩 확인해보니 서버 쪽은 완벽하게 정상이었습니다.

먼저 docker ps | grep vaultwarden으로 컨테이너가 healthy 상태이고 0.0.0.0:8222->80으로 포트가 열린 것을 확인했습니다. 이어서 서버 내부에서 curl -I http://172.30.1.51:8222를 실행하니 HTTP/1.1 200 OK가 돌아왔습니다. NPM의 Proxy Hosts 목록에서도 해당 호스트가 SSL(Let's Encrypt)까지 발급된 채 'Online' 상태였습니다. 결정적인 단서는 휴대폰 데이터(5G)로 접속하니 정상적으로 화면이 떴다는 것입니다.

원인은 'NAT 루프백(헤어핀 NAT) 미지원'이었습니다. 집 안에서 도메인을 입력하면 DNS는 우리 집 공인 IP를 알려주고, PC는 그 공인 IP로 나갔다가 다시 집으로 돌아와야 합니다. 그런데 상당수 가정용 공유기는 이 '나갔다 되돌아오는' 경로를 지원하지 않아 요청이 그대로 버려집니다. 즉 밖(5G)에서는 되고 안(집 와이파이)에서는 안 되는 현상이 발생합니다. 서버 문제가 아니므로 서버를 아무리 뒤져도 원인을 못 찾는 것이죠.

 

AdGuard의 DNS 변경으로 우아하게 해결하기

해결책은 '집 안에서 물어볼 때만 내부 IP를 알려주기'입니다. 여러 방법이 있지만, 우리는 이미 9편에서 AdGuard Home을 DNS 서버로 구축해뒀으므로 여기서 한 번만 설정하면 그 DNS를 쓰는 모든 기기에 자동으로 적용됩니다. 앞 편에서 만든 도구가 다음 편의 문제를 푸는 셈입니다.

AdGuard 관리 화면에서 상단 메뉴 필터 → DNS 변경으로 들어갑니다. 영문 자료에는 'DNS rewrites'로 나오는 메뉴가 한글판에서는 'DNS 변경'으로 번역돼 있어, 메뉴를 못 찾는 경우가 많으니 참고하세요. 여기서 규칙을 추가합니다.

  • 도메인: *.ddlabx-home.duckdns.org
  • IP 주소: 172.30.1.51

와일드카드(*)를 쓰면 vault., photo., portainer. 등 모든 서브도메인이 한 번에 처리됩니다. 서브도메인 없는 루트 주소도 쓸 예정이라면 ddlabx-home.duckdns.org도 같은 IP로 추가해두면 됩니다. 설정 후 윈도우 PC에서 확인합니다. 이때 명령은 서버(SSH 창)가 아니라 윈도우 PowerShell에서 실행해야 합니다. ipconfig는 윈도우 명령이라 우분투에서는 동작하지 않습니다.

ipconfig /flushdns
nslookup vault.ddlabx-home.duckdns.org

nslookup 결과의 Address가 공인 IP가 아니라 **172.30.1.51(내부 IP)**로 나오면 성공입니다. 이후 집 PC에서도 https://vault.ddlabx-home.duckdns.org가 정상적으로 열렸고, 계정 생성까지 마쳤습니다. 내부 IP로 연결되더라도 인증서는 도메인 이름을 기준으로 검증되므로 https 자물쇠는 그대로 유효합니다. 다만 주의할 점은, 이 방식은 AdGuard를 DNS로 지정한 기기에서만 작동한다는 것과, 서버가 꺼지면 해당 기기의 DNS 조회 자체가 막힌다는 것입니다.

 

계정 생성 후 반드시 할 일 — 가입 차단

계정을 만들었다면 지체 없이 가입을 막아야 합니다. SIGNUPS_ALLOWED가 true인 상태에서는 주소를 아는 누구나 계정을 만들 수 있는데, 비밀번호 금고에서 이는 심각한 위험입니다. docker-compose.yml을 열어 값을 바꾸고 다시 올리면 됩니다.

SIGNUPS_ALLOWED: "false"

수정 후 docker compose up -d를 실행하면 새 설정으로 컨테이너가 재기동되며, 기존 계정은 그대로 로그인할 수 있습니다. 시크릿 창으로 접속해 가입 버튼이 사라졌는지 확인하면 확실합니다.

마지막으로 가장 중요한 경고입니다. Vaultwarden의 마스터 비밀번호는 복구가 불가능합니다. 잊어버리면 저장된 모든 비밀번호를 영원히 열 수 없으며, 서버 관리자인 본인조차 풀 수 없습니다. 이는 결함이 아니라 '서버조차 내용을 모른다'는 이 서비스의 보안 설계 그 자체입니다. 반드시 안전한 곳에 따로 기록해두세요. 이렇게 내 비밀번호를 내 서버에 두게 됐으니, 이제 이 데이터를 어떻게 지킬지가 중요해집니다.

다음 편에서는 집 안의 여러 기기를 하나로 묶는 스마트홈 허브를 구축해봅니다. → 12편. Home Assistant로 시작하는 스마트홈 허브


소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 블로그 이름