Valutwarden 구축하기

Bitwarden의 호환 Backend인 Vaultwarden을 Docker로 구축하는 방법을 소개합니다.

Valutwarden 구축하기
Vaultwarden Logo

Vaultwarden은 Bitwarden의 API를 Rust를 통해 구현한 것이다. 공식 Bitwarden Self-hosted의 경우 .NET으로 구현되어 있고, DB도 MSSQL을 사용해야했다. 그래서 나 혼자 쓸건데 서버 자원만 낭비되는게 아닌가 싶어서 Vaultwarden을 통해서 구축해보고자 한다.

Vaultwarden은 공식 배포 프로그램이 아니고 개인이 오픈 소스 프로젝트로서 개발한 것이기 때문에 어떠한 작동 보증이 없다. 또한 극단적으로 말하면 백도어를 설치했을 수도 있을 일이므로 이걸 이용해서 구축하고자 할 때는 본인에게 모든 리스크가 있음을 양지하기 바란다.

준비물

  • Docker가 설치된 서버
  • SSL 인증서 (권장)

Vaultwarden의 경우 Docker를 통해 쉽게 구축할 수 있다. 아래는 구성 샘플이다.

services:
  caddy:
    image: caddy:2
    container_name: caddy
    restart: always
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-config:/config
      - ./caddy-data:/data
    environment:
      DOMAIN: <DOMAIN>
      EMAIL: <LET'S ENCRYPT EMAIL ADDRESS>
      LOG_FILE: "/data/access.log"
    networks:
      - vaultwarden-net
  vaultwarden:
    image: vaultwarden/server:1.32.6
    container_name: vaultwarden
    restart: unless-stopped
    user: 1000:1000
    environment:
      DOMAIN: <DOMAIN>
      SIGNUPS_ALLOWED: "false"
      ADMIN_TOKEN: <ADMIN TOKEN>
      SHOW_PASSWORD_HINT: "false"
      LOG_FILE: "/data/vaultwarden.log"
      DATABASE_URL: "<DB Type>://<DB USER>:<DB PASSWORD>@<DB_HOST>/<DB NAME>"
      # Bitwarden Installation ID and Key
      PUSH_INSTALLATION_ID: <Bitwarden Installation ID>
      PUSH_INSTALLATION_KEY: <Bitwarden Installation KEY>
      SMTP_HOST: <SMTP HOST>
      SMTP_PORT: <SMTP PORT>
      SMTP_SECURITY: <SMTP SSL Type>
      SMTP_FROM: <SMTP Mail Address>
      SMTP_USERNAME: <SMTP Username>
      SMTP_PASSWORD: <SMTP Password>
      TZ: Asia/Seoul
    volumes:
      - ./data/vw-data/:/data/
    expose:
      - 80
    networks:
      - vaultwarden-internal
      - vaultwarden-net
    depends_on:
      - vaultwarden_db
    logging:
      driver: "json-file"
      options:
        max-size: "200k"
        max-file: "10"
  vaultwarden_db:
    image: mysql:lts
    container_name: valutwarden-mysql
    restart: unless-stopped
    expose:
      - 3306
    volumes:
      - ./data/mysql/:/var/lib/mysql
    environment:
      MYSQL_DATABASE: <MYSQL DATABASE>
      MYSQL_USER: <MYSQL USERNAME>
      MYSQL_PASSWORD: <MYSQL PASSWORD>
      MYSQL_ROOT_PASSWORD: <ROOT PASSWORD>
      TZ: Asia/Seoul
    networks:
      - vaultwarden-internal
    logging:
      driver: "json-file"
      options:
        max-size: "200k"
        max-file: "10"

networks:
  vaultwarden-net:
    external: true
  vaultwarden-internal:
    driver: bridge

위 구성은 Valutwarden의 Github Wiki에서 소개하는 설정 중 일부를 추려서 구성한 것이다.

Database 관련

DB의 경우 별도로 정의하지 않으면, Vaultwarden 내에 있는 SQLite를 DB 대신 사용한다. 하지만, 곧 SQLite 지원이 중단되는 것도 있고 외부 DB를 설정하는 것을 추천하고 있다. 지원하는 DB는 mariaDB와 PostgreSQL이다. mariaDB는 MySQL과 호환되기에 샘플에는 MySQL로 기재했다.

그리고 Vaultwarden 서비스 환경변수에 mariaDB(MySQL) Database 접속 정보를 넣을 때 암호에 특수 문자가 들어가는 경우 여기를 참고해서 퍼센트 인코딩 문자로 대체 해야한다.

Caddy는 뭐예요?

Vaultwarden과 MySQL은 보시면 어떤 용도인지 바로 아시겠으나 Caddy가 생소하실 것 같은데, 이게 Nginx 같이 웹 서버의 역할을 하는데 Certbot 필요 없이 SSL 인증서를 발급해준다. 대신 Caddyfile이라고 구성 파일을 사전에 만들어줘야하는데 아래 예시를 참고하자.

{$DOMAIN} {
  log {
    level INFO
    output file {$LOG_FILE} {
      roll_size 10MB
      roll_keep 10
    }
  }

  # Use the ACME DNS-01 challenge to get a cert for the configured domain.
  tls {
    dns duckdns {$DUCKDNS_TOKEN}
  }

  # This setting may have compatibility issues with some browsers
  # (e.g., attachment downloading on Firefox). Try disabling this
  # if you encounter issues.
  encode zstd gzip

  # Proxy everything to Rocket
  reverse_proxy vaultwarden:80
}

만일, 본인이 사용하는 웹 서버가 따로 있다면 이거는 삭제해도 된다. 나도 별도 웹 서버가 있어서 삭제했다.

SMTP 설정

SMTP 서버는 로그인 알림 등에 쓰이는데, 본인이 사용하는 메일 서버의 정보를 넣으면 되시겠다. iCloud+를 구독 중인 경우 본인의 도메인을 메일로 사용할 수 있으니 여기를 참고하여 설정하기 바란다.

환경변수 소개

Vaultwarden에서 사용하는 환경 변수를 일부 소개한다.

DOMAIN: 사이트 주소 (메일 등에서 쓰임)
SIGNUPS_ALLOWED: 회원가입 가능 여부 (Boolean)
ADMIN_TOKEN: /admin 에 접속 했을 때 비밀번호 (String)
SHOW_PASSWORD_HINT: 회원가입시, 구성하는 Master 비밀번호 힌트를 표시할 것인지 (Boolean)
PUSH_ENABLED: 모바일 앱의 푸시 알림 활성화 여부
LOG_FILE: 로그 파일 위치 (컨테이너 내부)
DATABASE_URL: Database URL
# Bitwarden Installation ID and Key
PUSH_INSTALLATION_ID: 모바일 앱 푸시 활성화를 한 경우 입력 (하단 내용 참조)
PUSH_INSTALLATION_KEY: 모바일 앱 푸시 활성화를 한 경우 입력 (하단 내용 참조)
# 메일 알림을 위한 설정
SMTP_HOST
SMTP_PORT
SMTP_SECURITY: "forcetls", "startls"
SMTP_FROM:
SMTP_USERNAME:
SMTP_PASSWORD:
TZ: Asia/Seoul

Push 활성화를 위해선

모바일 앱 Push 알림 활성화를 위해선 Bitwarden에서 Self-hosted Installation ID와 Key를 발급 받아야한다. 여기에서 발급 받을 수 있다.

Bitwarden Self-hosted Id & Key 발급 화면

접속한 뒤에 관리자 이메일 주소를 입력하고 Data Region을 선택하면 발급이 되는데, Data Region의 경우 US와 EU가 있다. 둘의 차이는 규제 때문에 발생하는 것으로 보이는데, 운영하고자 하는 곳이 EU의 규제를 받지 않는다면 US가 맞을 것으로 보인다.

만일, EU로 선택하였다면 여기를 참고해서 PUSH_RELAY_URI, PUSH_IDENTITY_URI 환경 변수를 추가로 설정해야한다.

배포

배포는 간단하다. docker-compose up -d 명령어로 배포하면 된다.

마치며

이번 글에서는 간단하게 Vaultwarden을 배포하는 docker-compose.yaml 샘플을 공유했다. 사이트가 좀 중요하다보니 보안도 중요한데 Wiki에서는 Fail2ban을 기준으로 설명하고 있다. 나도 이 내용을 적용했는데 이 내용에 대해서도 글을 적어보도록 하겠다.