SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-27

VPS에 Vaultwarden 설치하여 비밀번호 관리자 직접 호스팅하기

Docker와 Vaultwarden을 사용하여 VPS에 Bitwarden 호환 비밀번호 관리자를 구축하는 방법을 안내합니다. HTTPS 설정, 관리자 토큰 구성, Fail2ban 보안 적용 및 데이터 백업 전략을 포함하며 100MB 이하의 RAM으로 안정적인 운영이 가능합니다.

구축할 시스템

사용자가 완전히 소유하는 비밀번호 관리자입니다. HTTPS를 종료하는 리버스 프록시 뒤에서 소형 컨테이너로 실행되는 Vaultwarden을 구축하고, 휴대폰, 노트북, 브라우저에 설치된 공식 Bitwarden 앱을 이 서버에 연결합니다. Vaultwarden은 Rust로 Bitwarden 서버 API를 재구현하여 bitwarden.com과 동일한 프로토콜을 사용합니다. 따라서 모든 공식 클라이언트를 수정 없이 그대로 사용할 수 있으며, 공식 스택이 여러 컨테이너를 사용하는 것과 달리 약 100 MB의 RAM만으로 구동됩니다.

설치 과정은 12줄 정도의 Compose 파일로 이루어집니다. 실제로 중요하며 문제가 발생하기 쉬운 세 가지 사항은 다음과 같습니다. 웹 볼트를 로드하기 전에 반드시 TLS가 설정되어 있어야 하며, 본인 계정을 생성한 즉시 공개 가입 기능을 닫아야 합니다. 또한, 해당 디렉터리에 모든 비밀번호가 저장되므로 데이터 볼륨을 반드시 백업하고 복구 테스트를 수행해야 합니다.

사전 요구 사항 및 주의 사항

  • Docker Engine과 Compose 플러그인이 설치된 Ubuntu 24.04 KVM 기반의 VPS가 필요하며, root 또는 sudo 권한이 있어야 합니다. 512 MB RAM으로도 충분히 운영 가능하며, 1 GB라면 여유롭습니다. 이 서비스는 가장 가벼운 서비스 중 하나로, 직접 호스팅할 가치가 있는 서비스 목록 상단에 위치합니다. 다만, 다른 서비스를 함께 운영한다면 그에 맞춰 서버 사양을 결정하십시오. PhotoPrism이나 Immich와 같은 사진 라이브러리를 같은 VPS에 올리면 RAM 사용량이 기가바이트 단위로 늘어나지만, Vaultwarden은 거의 영향을 주지 않습니다. 나중에 추가할 미디어 프론트엔드도 마찬가지입니다. Jellyfin 라이브러리를 90년대 비디오 대여점처럼 꾸미는 것은 상시 가동되는 컨테이너를 하나 더 추가하는 것이며, 트랜스코딩을 위한 여유 자원도 고려해야 합니다.
  • VPS를 가리키는 A 레코드(IPv6를 사용한다면 AAAA 레코드)가 설정된 도메인이 필요합니다. vault.example.com TLS 인증서는 해당 도메인 이름으로 발급되므로, 시작하기 전에 DNS 설정이 완료되어야 합니다.
  • 80번과 443번 포트는 인터넷에 개방되어야 하며, 반드시 리버스 프록시에서 종료되어야 합니다. Vaultwarden이 직접 처리하게 해서는 안 됩니다. 80번 포트는 ACME 인증서 챌린지와 HTTP를 HTTPS로 리다이렉트하는 용도로만 사용됩니다.
  • 가장 중요한 주의 사항: Bitwarden 클라이언트는 HTTPS가 아닌 서버와는 통신하지 않습니다. "먼저 HTTP로 테스트"하는 방법은 없으며, 그 이유는 다음 섹션에서 다루는 구체적인 사유 때문입니다.

공식 Bitwarden 스택 대신 Vaultwarden을 사용하는 이유

동일한 클라이언트를 사용하면서 훨씬 가벼운 리소스를 점유합니다. 공식 Bitwarden 셀프 호스팅 버전은 여러 컨테이너(MSSQL, Nginx, Identity, Api, Admin 등)의 묶음으로 배포되며 약 2 GB의 RAM을 요구합니다. 반면 Vaultwarden은 기본적으로 SQLite 데이터베이스를 사용하는 단일 바이너리로 동작하며, 유휴 상태에서 수십 MB 정도의 메모리만 사용합니다. 개인, 가족 또는 소규모 팀에게는 명확한 선택지이며, Bitwarden API를 충실히 구현했기 때문에 데이터는 Vaultwarden과 bitwarden.com 사이에서 자유롭게 이동할 수 있습니다.

포기해야 할 부분은 대부분 엔터프라이즈 기능입니다. SCIM 프로비저닝은 지원하지 않으며(1.35.0 버전에서 실험적인 OpenID Connect SSO가 추가되기는 했습니다), 운영자가 직접 패치, HTTPS 설정, 백업을 수행해야 합니다. 이 가이드는 바로 그 세 가지 작업에 관한 내용입니다.

HTTPS가 선택 사항이 아닌 이유

Bitwarden 웹 볼트와 브라우저 확장 프로그램은 Web Crypto API(window.crypto.subtle)를 사용하여 브라우저에서 암호화 키를 생성합니다. 브라우저는 crypto.subtle보안 컨텍스트(secure context), 즉 HTTPS나 http://localhost인 특수한 경우에만 제공합니다. 일반 http://vault.example.com 연결에서는 undefined 상태가 되므로, 앱이 키를 생성하는 즉시 오류가 발생하며 콘솔에는 다음과 같이 표시됩니다.

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'importKey')

페이지가 응답하지 않거나 일반적인 암호화 오류가 나타나며, 로그인이 되지 않습니다. 데스크톱, 모바일 및 브라우저 클라이언트는 자체 호스팅된 URL을 대상으로 검사를 수행하며, http 엔드포인트(또는 연결할 수 없는 엔드포인트)에 대해서는 다음과 같은 오류를 반환하며 거부합니다.

This is not a recognized Bitwarden server. You may need to check with your provider or update your server.

두 경우 모두 원인은 동일합니다. 유효한 HTTPS가 없기 때문입니다. 따라서 먼저 TLS를 설정해야 하며, 잠시 확인하는 용도라도 http를 통해 볼트를 여는 일은 절대 없어야 합니다.

1단계, DNS 및 리버스 프록시 (TLS 우선)

레코드를 VPS로 지정하고 올바른 주소로 해석되는지 확인합니다.

dig +short vault.example.com

출력되는 줄은 반드시 VPS IP여야 합니다. 비어 있거나 잘못된 경우 DNS를 수정하고 TTL이 만료될 때까지 기다려야 합니다. 이름이 해석되지 않으면 인증서 발급이 실패합니다.

HTTPS 프런트엔드를 위해 이 가이드에서는 Traefik을 사용합니다. Traefik은 Let's Encrypt 인증서를 자동으로 발급 및 갱신하며 Compose에 바로 통합됩니다. 아직 실행 중이 아니라면 먼저 Traefik 리버스 프록시 및 자동 TLS 설정을 따르십시오. 이 과정에서 외부 Docker 네트워크(아래 proxy)와 ACME 리졸버(letsencrypt)가 생성되며, Vaultwarden 서비스가 여기에 연결됩니다. 수동으로 발급받은 인증서를 사용하는 일반 nginx도 Vaultwarden 측면에서는 동일하게 작동합니다.

Traefik 대신 nginx와 Certbot을 선호하십니까? Vaultwarden을 127.0.0.1:8080에 배치하고(서비스에 ports: ["127.0.0.1:8080:80"]을 추가하고 Traefik 레이블을 제거), 인증서를 발급받아 프록시를 설정하십시오. 인증서 관련 내용은 Certbot과 nginx를 이용한 Let's Encrypt 인증서 발급에서 다룹니다. 중요한 추가 사항은 알림 경로에 대한 WebSocket 업그레이드입니다.

server {
    listen 443 ssl;
    server_name vault.example.com;

    client_max_body_size 525M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

X-Real-IP 줄에 유의하십시오. 이 설정 덕분에 나중에 Fail2ban이 127.0.0.1 대신 실제 공격자를 식별할 수 있습니다. 이 가이드의 나머지 모든 내용은 Traefik이나 nginx 중 무엇을 앞에 두더라도 동일합니다.

2단계: Compose 파일

먼저 프로젝트 디렉터리를 생성합니다. 이 가이드에서는 /opt/vaultwarden를 사용합니다. 이 명령은 Compose 프로젝트 이름을 지정하며, 결과적으로 데이터 볼륨 이름인 vaultwarden_vw-data을 예측 가능하게 만듭니다. 아래의 Fail2ban 및 백업 단계는 이 정확한 이름에 의존합니다.

sudo mkdir -p /opt/vaultwarden
cd /opt/vaultwarden

해당 디렉터리에 관리자 비밀번호를 위한 .env과 Compose 파일을 생성합니다.

# .env
ADMIN_TOKEN=paste-a-strong-token-here

openssl rand -base64 48를 사용하여 토큰을 생성하고 붙여넣습니다. (더 강력한 해시 형태는 다음 단계에서 다룹니다. 시작 단계에서는 긴 무작위 문자열이면 충분합니다.)

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vault.example.com"
      SIGNUPS_ALLOWED: "true"          # closed in Step 4, keep true just to register
      ADMIN_TOKEN: "${ADMIN_TOKEN}"
      IP_HEADER: "X-Forwarded-For"     # X-Real-IP if your proxy sends that instead
      LOG_FILE: "/data/vaultwarden.log"
      LOG_LEVEL: "warn"
    volumes:
      - vw-data:/data
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vw.rule=Host(`vault.example.com`)"
      - "traefik.http.routers.vw.entrypoints=websecure"
      - "traefik.http.routers.vw.tls.certresolver=letsencrypt"
      - "traefik.http.services.vw.loadbalancer.server.port=80"

volumes:
  vw-data:

networks:
  proxy:
    external: true

이 파일의 두 가지 요소가 전체 설계를 결정합니다. ports: 매핑이 없으므로, Vaultwarden은 Traefik과 그 TLS를 통해서만 접근할 수 있습니다. 호스트에서 포트를 공개하는 것은 사용자가 실수로 HTTP를 통해 볼트를 서비스하게 만드는 원인이 됩니다. 또한 DOMAIN는 반드시 전체 공개 HTTPS URL이어야 합니다. 이 값은 첨부 파일 링크, WebAuthn 2FA, 알림 엔드포인트에 포함됩니다. 따라서 잘못된 값이나 http 값을 사용하면 사이트가 로드되더라도 해당 기능들이 작동하지 않습니다. latest 태그는 일반적으로 권장되는 '절대 latest하지 마라'는 규칙의 의도적인 예외입니다. Vaultwarden은 안정적인 릴리스를 단일 롤링 이미지로 배포하며, :testing은 별도의 사전 릴리스 채널입니다. 따라서 의도적으로 업데이트를 수행하고 이미지를 가져오기(pull) 전에 릴리스 노트를 훑어보아야 합니다. 하지만 이 예외는 제한적입니다. 대부분의 장기 실행 컨테이너는 정확한 태그로 고정하는 것이 좋습니다. 그래야 동일한 VPS에서 호스팅되는 상시 가동 에이전트가 재부팅이나 이미지 업데이트 시에도 예측 가능하게 유지됩니다.

서비스를 시작하고 로그를 확인합니다.

docker compose up -d
docker compose logs -f vaultwarden

정상적으로 시작되면 Rocket has launched from http://0.0.0.0:80과 같은 줄로 끝납니다. Traefik이 인증서를 가져올 때까지 몇 초간 기다린 후 https://vault.example.com에 접속합니다. 유효한 자물쇠 아이콘이 표시되고 인증서 경고 없이 Bitwarden 웹 볼트가 나타나야 합니다.

3단계: 강력한 ADMIN_TOKEN 설정 및 $$ 함정 주의

ADMIN_TOKEN은 인스턴스의 모든 사용자와 설정을 읽을 수 있는 제어판인 /admin을 보호하므로, root 비밀번호와 동일하게 취급해야 합니다. 두 가지 방식이 있습니다.

간단한 방식은 이미 openssl rand -base64 48로 생성한 무작위 문자열을 사용하는 것입니다. base64에는 $이 포함되지 않으므로, 이스케이프 처리 없이 .env에 바로 입력할 수 있습니다.

강화된 방식은 Argon2 PHC 해시를 사용하는 것이며, 이를 통해 일반 텍스트 형태의 토큰이 디스크에 저장되지 않도록 합니다. 동일한 이미지에서 해시를 생성하십시오.

docker run --rm -it vaultwarden/server /vaultwarden hash --preset owasp

두 번 입력을 요구하며 $argon2id$v=19$...로 시작하는 문자열이 출력됩니다. 여기서 많은 사용자가 한 시간씩 허비하는 함정이 있습니다. Docker Compose는 $을 변수 보간(interpolation)으로 처리하므로, 해시를 Compose 파일에 붙여넣을 때는 모든 $$$로 두 번씩 입력해야 합니다. .env을 거치지 말고 environment: 바로 아래에 배치하며, 따옴표로 감싸지 마십시오.

    environment:
      ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$c29tZXNhbHQ$$RdescudvJCsgt3ub+b+dWRWJTmaaJObG

단일 $ 기호를 그대로 두면 Compose는 The "argon2id" variable is not set 경고를 출력하고 토큰을 비워버리며, 결과적으로 /admin은 올바른 비밀번호를 입력해도 거부합니다. docker compose up -d를 실행하고, 프롬프트에 입력했던 일반 텍스트 비밀번호는 본인의 비밀번호 관리자에 따로 보관하십시오.

4단계, 계정 등록 및 출입문 잠금

SIGNUPS_ALLOWED: "true"를 사용하여 https://vault.example.com을 열고 Create account를 클릭한 뒤, 이메일과 강력한 마스터 비밀번호로 계정을 등록합니다. 이 마스터 비밀번호는 복구할 수 없으며 재설정 기능도 없으므로, 먼저 안전하고 영구적인 곳에 보관하십시오.

이제 출입문을 잠급니다. Compose 파일을 편집하여 회원가입 기능을 끕니다.

      SIGNUPS_ALLOWED: "false"

docker compose up -d을 사용하여 설정을 다시 적용합니다. 이는 미룰 수 없는 보안 강화 작업입니다. 회원가입 기능을 열어두면 URL을 찾아낸 누구나(크롤러 포함) 서버에 계정을 생성할 수 있습니다. 이들이 사용자의 볼트를 읽을 수는 없지만, 서버 자원을 소모하게 되며 개인 인스턴스가 공개 서비스로 변질됩니다. 회원가입 기능을 끄지 않았다는 신호는 /admin 명령을 실행했을 때 본인이 생성하지 않은 계정들이 목록에 나타나는 것으로 확인할 수 있습니다.

나중에 가족이나 팀원을 추가하려면 공개 회원가입을 다시 열지 말고 /adminInvite User 버튼을 사용하십시오. 해당 기능을 사용하려면 초대받는 사람이 링크를 받을 수 있도록 SMTP 설정이 필요합니다.

5단계, /admin 접속

https://vault.example.com/admin로 이동하여 일반 텍스트 관리자 토큰(무작위 문자열 또는 해시 처리한 비밀번호, 해시 값 자체가 아님)을 입력합니다. 관리자 페이지에서는 사용자 목록 확인, 설정 조정, 테스트 이메일 발송, 데이터베이스 스냅샷 생성이 가능합니다.

페이지에서 404 Not Found 오류가 반환된다면 ADMIN_TOKEN가 비어 있거나 설정되지 않은 상태입니다. 이 경우 관리자 패널이 완전히 비활성화되며, 패널을 사용할 필요가 없다면 이는 유효한 선택입니다. 페이지는 로드되지만 토큰을 거부한다면 아래 실패 목록의 $$ 이스케이프 관련 문제를 확인하십시오. 토큰을 잊어버렸습니까? 복구 프롬프트는 제공되지 않습니다. .env 또는 Compose 파일을 편집하여 새로운 토큰을 설정한 뒤 docker compose up -d를 수행하십시오.

6단계, Bitwarden 클라이언트 연결

모든 공식 클라이언트는 자체 호스팅 서버를 가리키도록 설정할 수 있습니다. 일반 앱 스토어에서 Bitwarden 데스크톱, 모바일 또는 브라우저 클라이언트를 설치하십시오. 별도의 Vaultwarden 빌드는 필요하지 않습니다.

로그인하기 전에 로그인 화면의 설정 톱니바퀴 아이콘(Self-hosted 또는 Region → Self-hosted로 표시됨)을 열고, Server URLhttps://vault.example.com으로 설정한 뒤 저장하십시오. 그 후 등록한 이메일과 마스터 비밀번호로 로그인하면 클라이언트가 즉시 연결되어 자격 증명을 채우거나 저장할지 묻습니다.

클라이언트에 This is not a recognized Bitwarden server. You may need to check with your provider or update your server. 오류가 표시된다면 URL이 잘못되었거나, http를 사용 중이거나, 인증서를 신뢰할 수 없는 경우입니다. 먼저 https://vault.example.com이 브라우저에서 정상적으로 로드되는지 다시 확인하십시오. 다른 기기에서의 업데이트가 느린 것은 WebSocket 푸시 문제이며, 아래에서 다룹니다.

7단계: 로그인 엔드포인트를 위한 Fail2ban jail 설정

Vaultwarden은 모든 로그인 실패 기록을 LOG_FILE에 설정된 파일에 남기며, 이는 무차별 대입 공격 방어에 정확히 필요한 기능입니다. Fail2ban을 아직 사용하지 않는다면 Fail2ban SSH 보안 가이드에서 설치 및 기본 설정을 확인하십시오. 여기서는 Vault를 위한 jail을 하나 추가합니다.

먼저 Fail2ban이 로그를 읽을 수 있도록 호스트에서 명명된 볼륨(named volume)의 위치를 찾습니다.

docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}'

이 명령은 /var/lib/docker/volumes/vaultwarden_vw-data/_data와 같은 경로를 출력하며, 로그 파일은 그 내부의 vaultwarden.log에 위치합니다. 필터를 생성합니다.

# /etc/fail2ban/filter.d/vaultwarden.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

그리고 jail을 생성합니다.

# /etc/fail2ban/jail.d/vaultwarden.local
[vaultwarden]
enabled   = true
filter    = vaultwarden
logpath   = /var/lib/docker/volumes/vaultwarden_vw-data/_data/vaultwarden.log
banaction = iptables-allports
chain     = DOCKER-USER
maxretry  = 5
findtime  = 600
bantime   = 3600

sudo systemctl restart fail2ban로 설정을 다시 불러오고 sudo fail2ban-client status vaultwarden로 확인합니다.

이 설정이 제대로 작동하는지는 세 가지 Docker 관련 세부 사항에 달려 있습니다. 첫째, 로그에 모든 실패 시도마다 IP: 127.0.0.1나 프록시 주소가 기록된다면 Vaultwarden이 프록시를 차단하고 있는 것입니다. IP_HEADER를 프록시가 실제로 전달하는 헤더로 설정하십시오(Traefik은 X-Forwarded-For, 위에서 설정한 nginx 블록은 X-Real-IP, Cloudflare 뒤에 있다면 CF-Connecting-IP). 둘째, 올바른 iptables 체인은 프록시에 따라 다릅니다. Traefik을 포트가 노출된 컨테이너로 실행 중이라면 트래픽이 Docker의 FORWARD 경로를 통과하므로 위와 같이 DOCKER-USER에 차단 규칙을 두어야 합니다. 하지만 1단계에서 호스트 nginx 옵션을 선택했다면 연결이 호스트의 INPUT 체인에서 nginx로 종료되므로 DOCKER-USER 차단 규칙은 이를 감지하지 못합니다. 이 경우 chain = DOCKER-USER 줄을 삭제하여 Fail2ban이 기본값인 INPUT 체인을 사용하게 하십시오. 셋째, 포트 기반의 기본값 대신 banaction = iptables-allports를 사용하십시오. 이 jail은 포트를 정의하지 않으며, DOCKER-USER에서 모든 포트를 차단하면 해당 서버의 모든 공개 서비스에서 공격자를 확실하게 차단할 수 있습니다.

8단계: 볼트 백업 및 실제 복구 수행

vw-data 볼륨은 곧 비밀번호 관리자 그 자체입니다. 이 볼륨에는 db.sqlite3(모든 항목), attachments/sends/ 디렉터리, 로그인 세션을 서명하는 rsa_key.* 파일, 관리자 패널의 config.json가 포함되어 있습니다. 이 중 하나라도 누락된 백업은 정작 필요할 때 사용할 수 없습니다.

Vaultwarden이 데이터를 쓰는 도중에 db.sqlite3를 복사하면 파일이 절반만 기록되거나 손상될 수 있습니다. 따라서 몇 초간의 서비스 중단을 감수하고 콜드 스냅샷을 생성하십시오.

#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F)
DEST=/root/vw-backups
VOL=$(docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}')
mkdir -p "$DEST"
docker compose -f /opt/vaultwarden/docker-compose.yml stop vaultwarden
tar czf "$DEST/vw-$STAMP.tgz" -C "$VOL" .
docker compose -f /opt/vaultwarden/docker-compose.yml start vaultwarden

이 작업을 cron에 등록하여 매일 밤 실행하고, .tgz를 서버 외부로 복사하십시오. 보호 대상 서버에만 존재하는 백업은 진정한 의미의 백업이 아닙니다. 데이터를 안전하게 전송하는 가장 깔끔한 방법은 다른 서버나 오브젝트 스토리지로 매일 restic 백업을 수행하는 것입니다. 이 방식은 아카이브를 암호화하고 중복된 스냅샷을 제거합니다. 관리자 패널의 Backup Database 버튼은 SQLite 파일만 포함하는 간편한 핫 스냅샷 기능이지만, 첨부 파일과 키는 포함하지 않습니다.

이제 백업이 단순한 희망 사항이 아닌 실제 복구 가능한 상태인지 확인하는 절차를 진행합니다.

mkdir -p /tmp/vw-restore
tar xzf /root/vw-backups/vw-2026-07-15.tgz -C /tmp/vw-restore
docker run --rm -p 127.0.0.1:8888:80 -v /tmp/vw-restore:/data vaultwarden/server

노트북에서 ssh -L 8888:127.0.0.1:8888 you@your-vps를 사용하여 터널링을 설정하고 http://localhost:8888에 접속하십시오. localhost은 보안 컨텍스트이므로 crypto.subtle을 사용할 수 있으며, 예외적으로 허용된 이 환경에서 볼트는 일반 HTTP를 통해 복호화됩니다. 마스터 비밀번호로 로그인하여 항목들이 존재하는지 확인하십시오. 데이터베이스, RSA 키, 마스터 비밀번호가 모두 정상적으로 복구된다면, 새로운 VPS에서도 몇 분 안에 서비스를 재구축할 수 있습니다. Ctrl-C를 눌러 컨테이너를 중지하고 /tmp/vw-restore를 삭제하십시오. 인터넷에 직접 노출해서는 안 되는 서버 내 다른 관리자 UI에 접근할 때도 이 터널링 방식을 사용하십시오. 포트 5173에서 실행되는 자체 호스팅 open-kritt 보안 스캐너에 접근할 때도 동일한 방법을 적용할 수 있습니다.

실패 유형 및 확인되는 메시지

브라우저 콘솔에 Cannot read properties of undefined (reading 'importKey') 발생. 볼트가 http로 로드되어 crypto.subtle이(가) 정의되지 않았습니다. https://를 통해서만 접근하고 프록시에서 HTTP-to-HTTPS 리다이렉트를 추가하십시오.

클라이언트에 This is not a recognized Bitwarden server... 발생. 서버 URL이 http이거나 오타가 있거나, 인증서를 신뢰할 수 없습니다. https://vault.example.com에서 유효한 자물쇠 아이콘이 표시되는지 확인한 뒤, 클라이언트의 자체 호스팅 설정에 다시 입력하십시오.

/admin에서 올바른 비밀번호를 거부함. Argon2 해시의 이스케이프 처리가 누락되었습니다. Compose 파일에서 모든 $은(는) $$이어야 합니다. 또는 평문 대신 해시 값을 직접 입력했을 가능성이 있습니다.

기기 간 동기화가 느리고 콘솔에 WebSocket connection to 'wss://vault.example.com/notifications/hub' failed 표시. 프록시가 Upgrade/Connection 헤더를 전달하지 않고 있습니다. Traefik은 이를 자동으로 처리하지만, nginx는 1단계에서 언급한 두 개의 upgrade 라인이 필요합니다. 볼트는 정상 작동하지만 앱을 열 때만 동기화가 수행됩니다. v1.31.0부터 기존의 전용 포트 3012가 제거되었으므로 별도의 WebSocket 경로는 필요하지 않습니다.

Fail2ban이 차단을 보고하지만 공격자가 계속 연결됨. IP_HEADER 설정이 잘못되어 127.0.0.1을(를) 차단하고 있거나, 차단 규칙이 잘못된 iptables 체인에 위치한 경우입니다. chain = DOCKER-USERbanaction = iptables-allports를 설정하십시오.

업그레이드

새 이미지를 가져와 컨테이너를 다시 생성합니다. 명명된 볼륨과 모든 데이터는 유지됩니다.

docker compose pull
docker compose up -d

Vaultwarden은 잦은 주기로 릴리스됩니다. 특정 패치 버전을 고정하기보다는 프로젝트 릴리스 노트를 주기적으로 확인하십시오. 일부 릴리스에는 마이그레이션 관련 주의 사항이 포함되어 있기 때문입니다. 메이저 버전 업데이트 전에는 반드시 최신 백업을 수행하십시오. 문제가 발생하면 tarball을 새 볼륨에 복원하여 이전 상태로 되돌릴 수 있습니다.

FAQ

Vaultwarden은 Bitwarden과 동일한가요?

공식 서버가 아닌 호환 가능한 독립 서버입니다. Vaultwarden은 Rust로 Bitwarden 서버 API를 재구현했으므로, 공식 데스크톱, 모바일, 브라우저 및 CLI 클라이언트가 모두 정상적으로 작동하며 공식 스택보다 훨씬 적은 리소스를 사용합니다. 볼트 형식은 동일하므로 내보내기 및 가져오기를 통해 양방향으로 마이그레이션할 수 있습니다.

정말 HTTPS가 필요한가요, 아니면 LAN에서 http로 실행해도 되나요?

localhost 테스트를 제외한 모든 환경에는 HTTPS가 필요합니다. Bitwarden 웹 볼트와 확장 프로그램은 브라우저의 Web Crypto API를 사용하는데, 이는 보안 컨텍스트에서만 제공됩니다. 따라서 일반 http를 사용하면 클라이언트에서 Cannot read properties of undefined 오류가 발생하며 로그인할 수 없습니다. 작동하는 유일한 http 주소는 http://localhost뿐이며, 이것이 8단계의 복구 테스트에서 SSH 터널을 사용하는 이유입니다.

서버에 낯선 사람이 등록하지 못하게 하려면 어떻게 해야 하나요?

본인의 계정을 생성한 직후 Compose 파일에서 SIGNUPS_ALLOWED: "false"을 설정하고 docker compose up -d를 실행하십시오. 그 이후부터는 /admin사용자 초대(Invite User) 버튼을 통해 새로운 사람을 추가하십시오. 이 기능을 사용하려면 초대 링크를 받을 수 있도록 SMTP 설정이 필요합니다. 예상치 못한 계정이 생성되지 않았는지 관리자 사용자 목록을 주기적으로 확인하십시오.

Vaultwarden 볼트는 어떻게 백업하나요?

컨테이너를 잠시 중지하고 vw-data 볼륨 전체, db.sqlite3, attachments/, sends/, config.jsonrsa_key.* 파일을 아카이브로 만듭니다. 그 후 아카이브를 서버 외부로 복사하십시오. 매일 밤 cron 작업을 통해 수행하는 것이 좋습니다. 서버가 실행 중일 때 SQLite 파일을 복사하면 스냅샷이 손상될 위험이 있으므로 반드시 중지된 상태에서 백업하십시오. 가장 중요한 것은, 백업을 실제로 신뢰하기 전에 테스트용 컨테이너에 복구하여 로그인이 정상적으로 되는지 확인하는 것입니다.

비밀번호를 직접 호스팅하는 것이 실제로 안전한가요?

이 가이드에서 다루는 세 가지 사항인 올바른 HTTPS 적용, 회원가입 차단 및 강력한 관리자 토큰 설정, 그리고 검증된 백업을 수행한다면 안전합니다. 볼트는 마스터 비밀번호를 사용하여 클라이언트 측에서 암호화되므로 서버조차도 비밀번호를 평문으로 볼 수 없으며, db.sqlite3을 탈취하더라도 마스터 비밀번호 없이는 아무런 소용이 없습니다. 다만 패치와 백업을 직접 관리해야 한다는 책임이 따르며, 이것이 Fail2ban과 복구 절차를 선택 사항이 아닌 필수 사항으로 다루는 이유입니다. 이러한 조치가 완료되었다면, 자체 호스팅 볼트의 공격 지점에 대한 상세 분석을 확인하는 것이 다음 단계로 유용합니다. 클라이언트에서 항목 자체가 암호화되므로, 이제 방어해야 할 대상은 관리자 토큰과 백업 아카이브뿐이기 때문입니다.