개요
Vaultwarden은 Rust로 작성된 비공식 Bitwarden 호환 서버입니다. 공식 Bitwarden 서버보다 훨씬 가볍고(RAM 50MB 미만), 모든 공식 Bitwarden 클라이언트(웹, 모바일, 데스크톱, 브라우저 확장)와 완벽하게 호환됩니다. Raspberry Pi에서도 원활하게 실행됩니다.
| 항목 | 내용 |
|---|---|
| GitHub | https://github.com/dani-garcia/vaultwarden |
| Docker Hub | https://hub.docker.com/r/vaultwarden/server |
| Wiki | https://github.com/dani-garcia/vaultwarden/wiki |
| 라이선스 | AGPL-3.0 |
| GitHub Stars | 40K+ |
Vaultwarden vs Bitwarden
왜 Vaultwarden인가?
| 구분 | Vaultwarden | Bitwarden (공식) |
|---|---|---|
| 언어 | Rust | .NET |
| RAM 사용 | <50MB | 1GB+ |
| 설치 | 단일 컨테이너 | 다중 컨테이너 |
| 데이터베이스 | SQLite/PostgreSQL/MySQL | MSSQL |
| 무료 기능 | 모든 기능 무료 | 일부 유료 (Organizations 등) |
| 지원 | 커뮤니티 | 공식 |
| Raspberry Pi | ✅ 가능 | ❌ 불가 |
Vaultwarden의 장점
✅ 리소스 효율: RAM 50MB 미만, Raspberry Pi/저사양 NAS 가능
✅ 무료 기능: Organizations, 2FA, Send 등 모든 기능 무료
✅ 단순 설치: 단일 Docker 컨테이너
✅ 완전 호환: 모든 공식 Bitwarden 클라이언트 사용 가능
✅ 활발한 커뮤니티: 빠른 업데이트, 보안 패치
주의 사항
⚠️ 비공식 구현: Bitwarden 팀 공식 지원 없음
⚠️ 최신 유지 필수: Bitwarden API 변경 시 업데이트 필요
⚠️ 셀프호스팅 책임: 백업, 보안, 유지보수 직접 관리
주요 기능
비밀번호 관리
| 기능 | 설명 |
|---|---|
| 비밀번호 저장 | 로그인 정보, 카드, 신원, 보안 노트 |
| 비밀번호 생성 | 강력한 무작위 비밀번호 생성 |
| 자동 완성 | 브라우저 확장, 모바일 앱 |
| 동기화 | 모든 기기에서 실시간 동기화 |
| 검색 | 빠른 검색 및 필터링 |
공유 및 조직
| 기능 | 설명 |
|---|---|
| Organizations | 팀/가족 비밀번호 공유 |
| Collections | 비밀번호 그룹화 |
| Member Roles | 소유자, 관리자, 사용자, 커스텀 |
| Groups | 사용자 그룹 관리 |
| Policies | 조직 정책 (2FA 필수, 비밀번호 정책 등) |
보안
| 기능 | 설명 |
|---|---|
| 2FA | TOTP, YubiKey, FIDO2/WebAuthn, Duo, 이메일 |
| Emergency Access | 비상 접근 (신뢰할 수 있는 연락처) |
| Master Password | AES-256 암호화 |
| Zero Knowledge | 서버에서 평문 데이터 없음 |
추가 기능
| 기능 | 설명 |
|---|---|
| Send | 암호화된 텍스트/파일 공유 |
| Attachments | 파일 첨부 |
| Password History | 비밀번호 변경 이력 |
| Event Logs | 조직 활동 로그 |
| Admin Reset | 관리자 비밀번호 재설정 |
동기화 방식
| 방식 | 대상 | 설명 |
|---|---|---|
| WebSocket | 브라우저, 데스크톱, 확장 | 실시간 동기화 (기본 활성화) |
| Push Notifications | 모바일 (Android/iOS) | FCM/APNs 사용 (설정 필요) |
대안 비교
| 기능 | Vaultwarden | Bitwarden Cloud | KeePassXC | Passbolt |
|---|---|---|---|---|
| 셀프호스팅 | ✅ | ❌ | ✅ (로컬) | ✅ |
| 클라우드 동기화 | ✅ | ✅ | ❌ | ✅ |
| 모바일 앱 | ✅ | ✅ | 제한적 | ✅ |
| 브라우저 확장 | ✅ | ✅ | ✅ | ✅ |
| 무료 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 4Docker 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 알림 설정:
- https://bitwarden.com/host/ 접속
- 이메일 입력 후 Installation ID/Key 발급
- 환경 변수에 추가
- 모바일 앱에서 로그아웃 후 다시 로그인
방법 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_HOST | SMTP 서버 |
SMTP_PORT | SMTP 포트 (587/465) |
SMTP_SECURITY | 보안 (starttls/force_tls/off) |
SMTP_FROM | 발신자 주소 |
SMTP_USERNAME | 사용자명 |
SMTP_PASSWORD | 비밀번호 |
Push 알림 (모바일)
| 변수 | 설명 |
|---|---|
PUSH_ENABLED | Push 알림 활성화 |
PUSH_INSTALLATION_ID | Bitwarden Installation ID |
PUSH_INSTALLATION_KEY | Bitwarden Installation Key |
PUSH_RELAY_URI | Push 릴레이 URI (EU: api.bitwarden.eu) |
PUSH_IDENTITY_URI | Push 인증 URI (EU: identity.bitwarden.eu) |
2FA
| 변수 | 설명 |
|---|---|
YUBICO_CLIENT_ID | YubiKey 클라이언트 ID |
YUBICO_SECRET_KEY | YubiKey 시크릿 키 |
DUO_IKEY | Duo Integration Key |
DUO_SKEY | Duo Secret Key |
DUO_HOST | Duo API 호스트 |
데이터베이스
| 변수 | 설명 | 기본값 |
|---|---|---|
DATABASE_URL | DB 연결 문자열 | 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_WEBSOCKET | WebSocket 활성화 | true |
SENDS_ALLOWED | Send 기능 허용 | true |
EMERGENCY_ACCESS_ALLOWED | Emergency 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 설정 (강력 권장)
- 웹 볼트 로그인
- Settings → Security → Two-step login
- Authenticator app 선택 (Google Authenticator, Authy 등)
- QR 코드 스캔 후 활성화
클라이언트 설정
공식 Bitwarden 클라이언트
모든 공식 Bitwarden 클라이언트를 사용할 수 있습니다:
| 클라이언트 | 다운로드 |
|---|---|
| 웹 볼트 | https://vault.example.com |
| 브라우저 확장 | Chrome, Firefox, Safari, Edge |
| 데스크톱 | Windows, macOS, Linux |
| 모바일 | iOS, Android |
| CLI | npm, 바이너리 |
서버 URL 변경
- Bitwarden 앱 설치
- 로그인 전 “Self-hosted” 또는 설정 아이콘 클릭
- Server URL:
https://vault.example.com - 저장 후 로그인
브라우저 확장 설정
- 확장 프로그램 설치
- 설정 → Self-hosted 환경
- Server URL 입력
- 로그인
백업 및 복원
데이터 구조
./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 알림 작동 안 함
확인 사항:
PUSH_ENABLED=true설정- Installation ID/Key 올바른지 확인
- 앱 스토어 공식 앱 사용 (F-Droid 앱은 미지원)
- 앱 재설치 후 다시 로그인
관리자 페이지 접속 안 됨
확인 사항:
ADMIN_TOKEN설정 확인- Argon2 해시 사용 시
$$이스케이프 확인 /admin경로로 접속
이메일 발송 실패
확인 사항:
- SMTP 설정 확인 (호스트, 포트, 보안)
- 앱 비밀번호 사용 (Gmail 등)
- 관리자 페이지에서 테스트 이메일 발송
활용 사례
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나 저사양 서버를 활용하고 싶은 분