Simple 5-minute Vaultwarden setup with Traefik & MySQL using docker-compose

Note: This post is a variant of Simple 5-minute MySQL Vaultwarden setup using docker-compose, adapted for setups where Traefik is used as a reverse proxy (with automatic TLS certificates) instead of exposing ports directly.

In order to setup Vaultwarden in a docker-compose & MySQL (MariaDB) based configuration behind Traefik, first we need to create a directory. I recommend using /opt/vaultwarden.

Run all the following commands and place all the following files in the /opt/vaultwarden directory!

First, we’ll create a .env file with random passwords (I recommend using pwgen 30). Not using unique, random passwords here is a huge security risk since it will allow full admin access to Vaultwarden!

.env
ADMIN_TOKEN=iqueingufo3LohshoohoG3tha2zou6
MARIADB_PASSWORD=ahhoogie7eequ0Ierooth5xeenoo
MARIADB_ROOT_PASSWORD=eih2ahSahthahhohdeefeix5eeph

Now place your docker-compose.yml:

docker-compose.yml
services:
  mariadb:
    image: mariadb:latest
    environment:
      - MYSQL_DATABASE=vaultwarden
      - MYSQL_USER=vaultwarden
      - MYSQL_PASSWORD=${MARIADB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
      - MARIADB_AUTO_UPGRADE=1
    volumes:
      - ./mariadb_data:/var/lib/mysql
    command: --default-storage-engine innodb
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mariadb", "-u", "root", "--password=${MARIADB_ROOT_PASSWORD}", "-e", "SELECT 1;"]
      interval: 1s
      timeout: 5s
      retries: 300
      start_period: 5s

  vaultwarden:
    image: vaultwarden/server:latest
    depends_on:
      mariadb:
        condition: service_healthy
    restart: unless-stopped
    environment:
      - ADMIN_TOKEN=${ADMIN_TOKEN}
      - DATABASE_URL=mysql://vaultwarden:${MARIADB_PASSWORD}@mariadb/vaultwarden
      - WEBSOCKET_ENABLED=true
    volumes:
      - ./vw_data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.mydomain.com`)"
      - "traefik.http.routers.vaultwarden.entrypoints=websecure"
      - "traefik.http.routers.vaultwarden.tls.certresolver=myresolver"
      - "traefik.http.routers.vaultwarden.tls.domains[0].main=mydomain.com"
      - "traefik.http.routers.vaultwarden.tls.domains[0].sans=*.mydomain.com"

Replace vaultwarden.mydomain.com, mydomain.com, myresolver and the router name vaultwarden in the labels with your own domain, certificate resolver and router name.

Note that the vaultwarden service does not expose any ports - Traefik will route traffic to it based on the Host() rule. This requires both Traefik and Vaultwarden to be attached to a common docker network. If Traefik runs in a separate docker-compose project, add an external network to the vaultwarden service, e.g.:

docker-compose.yml
  vaultwarden:
    networks:
      - traefik

networks:
  traefik:
    external: true

Next, we’ll create a systemd service to autostart docker-compose:

create_vaultwarden_service.sh
curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin

This will automatically start vaultwarden.

Since Traefik handles TLS termination, Vaultwarden will be available via https://vaultwarden.mydomain.com immediately - no separate reverse proxy configuration is required. You need to use https, http won’t work due to some browser limitations.

Now we need to configure vaultwarden using the admin interface.

Go to https://vaultwarden.mydomain.com/admin and enter the ADMIN_TOKEN from .env.

There are two things that you need to configure here:

  • The Domain Name under General settings
  • The email server settings under SMTP email settings

With these settings configured, Vaultwarden should be up and running and you can access it using https://vaultwarden.mydomain.com .

After the first user has been setup and tested, you can uncheck the Allow new signups in General settings in the admin interface. This is recommended since everyone who will be able to guess your domain name would be able to create a Vaultwarden account otherwise.


Check out similar posts by category: Container Docker