Vaultwarden Docker 설치 가이드: 셀프호스팅 비밀번호 관리자




개요

Vaultwarden은 Rust로 작성된 비공식 Bitwarden 호환 서버입니다. 공식 Bitwarden 서버보다 훨씬 가볍고(RAM 50MB 미만), 모든 공식 Bitwarden 클라이언트(웹, 모바일, 데스크톱, 브라우저 확장)와 완벽하게 호환됩니다. Raspberry Pi에서도 원활하게 실행됩니다.

항목내용
GitHubhttps://github.com/dani-garcia/vaultwarden
Docker Hubhttps://hub.docker.com/r/vaultwarden/server
Wikihttps://github.com/dani-garcia/vaultwarden/wiki
라이선스AGPL-3.0
GitHub Stars40K+

Vaultwarden vs Bitwarden

왜 Vaultwarden인가?

구분VaultwardenBitwarden (공식)
언어Rust.NET
RAM 사용<50MB1GB+
설치단일 컨테이너다중 컨테이너
데이터베이스SQLite/PostgreSQL/MySQLMSSQL
무료 기능모든 기능 무료일부 유료 (Organizations 등)
지원커뮤니티공식
Raspberry Pi✅ 가능❌ 불가

Vaultwarden의 장점

✅ 리소스 효율: RAM 50MB 미만, Raspberry Pi/저사양 NAS 가능
✅ 무료 기능: Organizations, 2FA, Send 등 모든 기능 무료
✅ 단순 설치: 단일 Docker 컨테이너
✅ 완전 호환: 모든 공식 Bitwarden 클라이언트 사용 가능
✅ 활발한 커뮤니티: 빠른 업데이트, 보안 패치

주의 사항

⚠️ 비공식 구현: Bitwarden 팀 공식 지원 없음
⚠️ 최신 유지 필수: Bitwarden API 변경 시 업데이트 필요
⚠️ 셀프호스팅 책임: 백업, 보안, 유지보수 직접 관리

주요 기능

비밀번호 관리

기능설명
비밀번호 저장로그인 정보, 카드, 신원, 보안 노트
비밀번호 생성강력한 무작위 비밀번호 생성
자동 완성브라우저 확장, 모바일 앱
동기화모든 기기에서 실시간 동기화
검색빠른 검색 및 필터링

공유 및 조직

기능설명
Organizations팀/가족 비밀번호 공유
Collections비밀번호 그룹화
Member Roles소유자, 관리자, 사용자, 커스텀
Groups사용자 그룹 관리
Policies조직 정책 (2FA 필수, 비밀번호 정책 등)

보안

기능설명
2FATOTP, YubiKey, FIDO2/WebAuthn, Duo, 이메일
Emergency Access비상 접근 (신뢰할 수 있는 연락처)
Master PasswordAES-256 암호화
Zero Knowledge서버에서 평문 데이터 없음

추가 기능

기능설명
Send암호화된 텍스트/파일 공유
Attachments파일 첨부
Password History비밀번호 변경 이력
Event Logs조직 활동 로그
Admin Reset관리자 비밀번호 재설정

동기화 방식

방식대상설명
WebSocket브라우저, 데스크톱, 확장실시간 동기화 (기본 활성화)
Push Notifications모바일 (Android/iOS)FCM/APNs 사용 (설정 필요)

대안 비교

기능VaultwardenBitwarden CloudKeePassXCPassbolt
셀프호스팅✅ (로컬)
클라우드 동기화
모바일 앱제한적
브라우저 확장
무료 Organizations❌ ($)N/A❌ ($)
오프라인 사용
리소스 사용매우 낮음N/A없음중간
설치 난이도쉬움N/A쉬움중간

선택 가이드

용도추천
개인/가족 셀프호스팅Vaultwarden
클라우드 서비스 원함Bitwarden Cloud
완전 오프라인/로컬KeePassXC
팀 협업 (엔터프라이즈)Passbolt / Bitwarden

시스템 요구 사항

항목요구 사양
CPU최소 사양
RAM<50MB (유휴 시)
저장소데이터 크기에 따라
포트80 (기본)
HTTPS필수 (Web Crypto API)

⚠️ 중요: Vaultwarden은 HTTPS가 필수입니다. 브라우저의 Web Crypto API는 보안 컨텍스트(HTTPS 또는 localhost)에서만 작동합니다.


Docker 설치

방법 1: 기본 설치 (SQLite)

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul

실행:

mkdir -p ~/vaultwarden && cd ~/vaultwarden

# docker-compose.yml 생성 후
docker compose up -d

접속: http://localhost:8080 (개발용) 또는 HTTPS 리버스 프록시 필요

방법 2: 관리자 페이지 활성화

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      # Argon2 해시 토큰 (권장)
      # 생성: echo -n "YourAdminPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...

💡 관리자 토큰 생성:

# Argon2 해시 생성 (권장)
echo -n "YourSecretPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4

Docker Compose에서는 $$$로 이스케이프해야 합니다.

방법 3: 회원가입 비활성화 (운영용)

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      # 회원가입 비활성화
      - SIGNUPS_ALLOWED=false
      # 초대만 허용
      - INVITATIONS_ALLOWED=true

방법 4: SMTP 이메일 설정

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      - SIGNUPS_ALLOWED=false
      # SMTP 설정
      - SMTP_HOST=smtp.gmail.com
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - SMTP_FROM=vault@example.com
      - SMTP_USERNAME=your-email@gmail.com
      - SMTP_PASSWORD=your-app-password

방법 5: 모바일 Push 알림

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      - SIGNUPS_ALLOWED=false
      # Push 알림 (https://bitwarden.com/host/ 에서 발급)
      - PUSH_ENABLED=true
      - PUSH_INSTALLATION_ID=your-installation-id
      - PUSH_INSTALLATION_KEY=your-installation-key

💡 Push 알림 설정:

  1. https://bitwarden.com/host/ 접속
  2. 이메일 입력 후 Installation ID/Key 발급
  3. 환경 변수에 추가
  4. 모바일 앱에서 로그아웃 후 다시 로그인

방법 6: Traefik + HTTPS

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      - SIGNUPS_ALLOWED=false
      - SMTP_HOST=smtp.gmail.com
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - SMTP_FROM=vault@example.com
      - SMTP_USERNAME=your-email@gmail.com
      - SMTP_PASSWORD=your-app-password
    networks:
      - traefik_network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.rule=Host(`vault.example.com`)"
      - "traefik.http.routers.vaultwarden.entrypoints=websecure"
      - "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=80"

networks:
  traefik_network:
    external: true

방법 7: Caddy + 자동 HTTPS

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      - SIGNUPS_ALLOWED=false
    networks:
      - internal

  caddy:
    image: caddy:alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy-data:/data
      - caddy-config:/config
    networks:
      - internal

networks:
  internal:
    driver: bridge

volumes:
  caddy-data:
  caddy-config:

Caddyfile:

vault.example.com {
    reverse_proxy vaultwarden:80
}

방법 8: PostgreSQL 백엔드

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:80"
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com
      - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$...해시값...
      - SIGNUPS_ALLOWED=false
      # PostgreSQL 연결
      - DATABASE_URL=postgresql://vaultwarden:vaultwardenpass@db:5432/vaultwarden

  db:
    image: postgres:16-alpine
    container_name: vaultwarden-db
    restart: unless-stopped
    volumes:
      - ./db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=vaultwarden
      - POSTGRES_USER=vaultwarden
      - POSTGRES_PASSWORD=vaultwardenpass
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "vaultwarden"]
      interval: 10s
      timeout: 5s
      retries: 5

환경 변수

필수/권장

변수설명기본값
DOMAIN서버 도메인 (HTTPS)
ADMIN_TOKEN관리자 페이지 토큰 (Argon2 해시)
TZ타임존UTC

회원가입/초대

변수설명기본값
SIGNUPS_ALLOWED회원가입 허용true
SIGNUPS_VERIFY이메일 인증 필요false
SIGNUPS_DOMAINS_WHITELIST허용 도메인 (쉼표 구분)
INVITATIONS_ALLOWED초대 허용true

이메일 (SMTP)

변수설명
SMTP_HOSTSMTP 서버
SMTP_PORTSMTP 포트 (587/465)
SMTP_SECURITY보안 (starttls/force_tls/off)
SMTP_FROM발신자 주소
SMTP_USERNAME사용자명
SMTP_PASSWORD비밀번호

Push 알림 (모바일)

변수설명
PUSH_ENABLEDPush 알림 활성화
PUSH_INSTALLATION_IDBitwarden Installation ID
PUSH_INSTALLATION_KEYBitwarden Installation Key
PUSH_RELAY_URIPush 릴레이 URI (EU: api.bitwarden.eu)
PUSH_IDENTITY_URIPush 인증 URI (EU: identity.bitwarden.eu)

2FA

변수설명
YUBICO_CLIENT_IDYubiKey 클라이언트 ID
YUBICO_SECRET_KEYYubiKey 시크릿 키
DUO_IKEYDuo Integration Key
DUO_SKEYDuo Secret Key
DUO_HOSTDuo API 호스트

데이터베이스

변수설명기본값
DATABASE_URLDB 연결 문자열SQLite

형식:

  • SQLite: data/db.sqlite3 (기본)
  • PostgreSQL: postgresql://user:pass@host:5432/dbname
  • MySQL: mysql://user:pass@host:3306/dbname

로깅

변수설명기본값
LOG_LEVEL로그 레벨 (trace/debug/info/warn/error)info
LOG_FILE로그 파일 경로

기타

변수설명기본값
ENABLE_WEBSOCKETWebSocket 활성화true
SENDS_ALLOWEDSend 기능 허용true
EMERGENCY_ACCESS_ALLOWEDEmergency Access 허용true
SHOW_PASSWORD_HINT비밀번호 힌트 표시false
WEB_VAULT_ENABLED웹 볼트 활성화true

초기 설정

1) 첫 접속 및 계정 생성

URL: https://vault.example.com
→ Create Account 클릭
→ 이메일, 마스터 비밀번호 입력

⚠️ 마스터 비밀번호는 복구할 수 없습니다. 강력하고 기억할 수 있는 비밀번호를 사용하세요.

2) 회원가입 비활성화 (권장)

계정 생성 후:

environment:
  - SIGNUPS_ALLOWED=false
docker compose down
docker compose up -d

3) 관리자 페이지 접속

URL: https://vault.example.com/admin
비밀번호: ADMIN_TOKEN 생성 시 사용한 원본 비밀번호

관리자 페이지에서:

  • 회원가입 설정
  • SMTP 설정
  • 사용자 관리
  • 2FA 관리
  • 조직 관리

4) 2FA 설정 (강력 권장)

  1. 웹 볼트 로그인
  2. Settings → Security → Two-step login
  3. Authenticator app 선택 (Google Authenticator, Authy 등)
  4. QR 코드 스캔 후 활성화

클라이언트 설정

공식 Bitwarden 클라이언트

모든 공식 Bitwarden 클라이언트를 사용할 수 있습니다:

클라이언트다운로드
웹 볼트https://vault.example.com
브라우저 확장Chrome, Firefox, Safari, Edge
데스크톱Windows, macOS, Linux
모바일iOS, Android
CLInpm, 바이너리

서버 URL 변경

  1. Bitwarden 앱 설치
  2. 로그인 전 “Self-hosted” 또는 설정 아이콘 클릭
  3. Server URL: https://vault.example.com
  4. 저장 후 로그인

브라우저 확장 설정

  1. 확장 프로그램 설치
  2. 설정 → Self-hosted 환경
  3. Server URL 입력
  4. 로그인

백업 및 복원

데이터 구조

./vw-data/
├── db.sqlite3          # SQLite 데이터베이스 (필수)
├── db.sqlite3-wal      # WAL 파일 (있으면 포함)
├── attachments/        # 첨부파일
├── sends/              # Send 파일
├── config.json         # 설정 (관리자 페이지에서 변경 시)
├── rsa_key.pem         # RSA 키
└── rsa_key.pub.pem     # RSA 공개키

SQLite 백업 (권장)

# 안전한 백업 (Online Backup API 사용)
sqlite3 ./vw-data/db.sqlite3 ".backup './backup/vaultwarden-$(date +%Y%m%d).db'"

# 또는 덤프
sqlite3 ./vw-data/db.sqlite3 ".dump" > ./backup/vaultwarden-$(date +%Y%m%d).sql

전체 백업

# 컨테이너 정지 후 백업 (가장 안전)
docker compose down
tar -czvf vaultwarden-backup-$(date +%Y%m%d).tar.gz vw-data/
docker compose up -d

# 또는 실행 중 SQLite 백업 + 파일 복사
sqlite3 ./vw-data/db.sqlite3 ".backup './vw-data/db-backup.sqlite3'"
tar -czvf vaultwarden-backup-$(date +%Y%m%d).tar.gz vw-data/

자동 백업 (ttionya/vaultwarden-backup)

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - ./vw-data:/data
    environment:
      - TZ=Asia/Seoul
      - DOMAIN=https://vault.example.com

  backup:
    image: ttionya/vaultwarden-backup:latest
    container_name: vaultwarden-backup
    restart: unless-stopped
    volumes:
      - ./vw-data:/data
      - ./backup:/backup
      # Rclone 설정 (선택)
      # - vaultwarden-rclone:/config
    environment:
      - TZ=Asia/Seoul
      - CRON=0 2 * * *  # 매일 새벽 2시
      - ZIP_ENABLE=true
      - ZIP_PASSWORD=your-backup-password
      - BACKUP_KEEP_DAYS=30

복원

# 백업 해제
tar -xzvf vaultwarden-backup.tar.gz

# 컨테이너 시작
docker compose up -d

업데이트

cd ~/vaultwarden

# 백업 먼저!
sqlite3 ./vw-data/db.sqlite3 ".backup './vw-data/db-backup.sqlite3'"
tar -czvf vaultwarden-backup-$(date +%Y%m%d).tar.gz vw-data/

# 최신 이미지
docker compose pull

# 재시작
docker compose down
docker compose up -d

# 로그 확인
docker compose logs -f vaultwarden

⚠️ Bitwarden API 변경 시 클라이언트 동기화 오류가 발생할 수 있습니다. Vaultwarden을 최신 버전으로 유지하세요.


보안 강화

Fail2Ban 설정

/etc/fail2ban/filter.d/vaultwarden.conf:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =

/etc/fail2ban/jail.d/vaultwarden.conf:

[vaultwarden]
enabled = true
port = 80,443
filter = vaultwarden
logpath = /path/to/vw-data/vaultwarden.log
maxretry = 5
bantime = 3600
findtime = 600

Vaultwarden 환경 변수:

environment:
  - LOG_FILE=/data/vaultwarden.log
  - LOG_LEVEL=warn

VPN 뒤에서 운영

외부 노출 대신 VPN (WireGuard, Tailscale) 뒤에서 운영하면 보안이 크게 향상됩니다.

HTTPS 필수

  • Let’s Encrypt + Caddy/Traefik
  • 리버스 프록시 사용
  • 자체 서명 인증서 (개발용)

트러블슈팅

“Cannot read property ‘importKey'” 오류

원인: HTTPS 없이 접속 해결: HTTPS 설정 또는 http://localhost 사용

클라이언트 동기화 실패

원인: Vaultwarden 버전 오래됨 해결:

docker compose pull
docker compose up -d

Push 알림 작동 안 함

확인 사항:

  1. PUSH_ENABLED=true 설정
  2. Installation ID/Key 올바른지 확인
  3. 앱 스토어 공식 앱 사용 (F-Droid 앱은 미지원)
  4. 앱 재설치 후 다시 로그인

관리자 페이지 접속 안 됨

확인 사항:

  1. ADMIN_TOKEN 설정 확인
  2. Argon2 해시 사용 시 $$ 이스케이프 확인
  3. /admin 경로로 접속

이메일 발송 실패

확인 사항:

  1. SMTP 설정 확인 (호스트, 포트, 보안)
  2. 앱 비밀번호 사용 (Gmail 등)
  3. 관리자 페이지에서 테스트 이메일 발송

활용 사례

1. 개인 비밀번호 관리

목적: 모든 비밀번호를 하나로 관리

  • 강력한 고유 비밀번호 생성
  • 모든 기기에서 동기화
  • 브라우저 자동 완성
  • 2FA로 보안 강화

2. 가족 공유

목적: 가족 구성원과 비밀번호 공유

  • Organization 생성
  • Collection으로 분류 (Netflix, 은행, 보험 등)
  • 가족 구성원 초대
  • 필요한 비밀번호만 공유

3. 소규모 팀

목적: 팀 자격 증명 관리

  • 팀 Organization 생성
  • 역할별 권한 설정
  • 프로젝트별 Collection
  • 입/퇴사 시 권한 관리

4. 보안 노트 및 파일

목적: 민감한 정보 저장

  • 보안 노트 (SSH 키, 라이선스, API 키)
  • 파일 첨부 (인증서, 문서)
  • Send로 일회성 공유

마무리

Vaultwarden은 셀프호스팅 비밀번호 관리의 최고 선택입니다. Bitwarden의 모든 기능을 무료로 사용하면서, 50MB 미만의 메모리로 Raspberry Pi에서도 실행할 수 있습니다.

핵심 장점

장점설명
경량<50MB RAM, Raspberry Pi 가능
무료Organizations, 2FA, Send 등 모든 기능
호환모든 공식 Bitwarden 클라이언트
동기화WebSocket + Push 알림
보안AES-256, Zero Knowledge
유연SQLite/PostgreSQL/MySQL

이런 분께 추천

모든 비밀번호를 하나로 관리하고 싶은 분
가족/팀과 비밀번호를 안전하게 공유하고 싶은 분
클라우드 서비스 대신 데이터를 직접 관리하고 싶은 분
LastPass, 1Password 등 유료 서비스 대안을 찾는 분
Raspberry Pi나 저사양 서버를 활용하고 싶은 분



댓글 남기기