How to run Vaultwarden server on linux
I’ve been using Bitwarden’s premium service for two years, and am really satisfied with it.
I’ve also heard of Vaultwarden, but I didn’t bother to run it myself, until yesterday.
This is a footage of building and running Vaultwarden on linux, without docker.
A. Build
Following instructions are from this page.
a. Build vaultwarden binary
I created a working directory for vaultwarden:
$ mkdir vaultwarden
cloned the vaultwarden’s source repository in it:
$ cd vaultwarden
# now in the working directory,
$ git clone https://github.com/dani-garcia/vaultwarden.git ./src
then built the binary with cargo
:
$ cd src
# now in the cloned source directory,
$ cargo build --features sqlite --release
b. Download web-vault
The web UI needs to be downloaded or built separately.
I downloaded the latest gzip file from the release page:
$ cd ..
# got back to 'vaultwarden' directory,
$ wget https://github.com/dani-garcia/bw_web_builds/releases/download/v2023.1.1/bw_web_v2023.1.1.tar.gz
$ tar xzvf bw_web_v2023.1.1.tar.gz
c. Run
I symlinked the binary, created data
directory, and checked if the binary runs ok:
# now in the working directory,
$ ln -sf src/target/release/vaultwarden ./vaultwarden
$ mkdir data
$ ./vaultwarden
If you can see messages like this:
/--------------------------------------------------------------------\
| Starting Vaultwarden |
| Version 1.27.0-1ba8275d |
|--------------------------------------------------------------------|
| This is an *unofficial* Bitwarden implementation, DO NOT use the |
| official channels to report bugs/features, regardless of client. |
| Send usage/configuration questions or feature requests to: |
| https://vaultwarden.discourse.group/ |
| Report suspected bugs/issues in the software itself at: |
| https://github.com/dani-garcia/vaultwarden/issues/new |
\--------------------------------------------------------------------/
[2023-02-15 11:13:15.048][start][INFO] Rocket has launched from http://127.0.0.1:8000
it is working!
Then I pressed [ctrl+c] to stop it, and began configuration.
B. Configure a reverse proxy
For using the web UI, we need to configure a reverse proxy with this guide.
I issued a SSL certificate with certbot, and added a reverse proxy site file for nginx:
# /etc/nginx/sites-enabled/MY_SITE_DOMAIN
#
# for Web UI of Vaultwarden
# The `upstream` directives ensure that you have a http/1.1 connection
# This enables the keepalive option and better performance
#
# Define the server IP and ports here.
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8000;
keepalive 2;
}
upstream vaultwarden-ws {
zone vaultwarden-ws 64k;
server 127.0.0.1:3012;
keepalive 2;
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name MY_SITE_DOMAIN;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name MY_SITE_DOMAIN;
ssl_certificate /etc/letsencrypt/live/MY_SITE_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/MY_SITE_DOMAIN/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/MY_SITE_DOMAIN/fullchain.pem;
client_max_body_size 128M;
location / {
proxy_http_version 1.1;
proxy_set_header "Connection" "";
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_pass http://vaultwarden-default;
}
location /notifications/hub/negotiate {
proxy_http_version 1.1;
proxy_set_header "Connection" "";
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_pass http://vaultwarden-default;
}
location /notifications/hub {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Forwarded $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://vaultwarden-ws;
}
# Optionally add extra authentication besides the ADMIN_TOKEN
# Remove the comments below `#` and create the htpasswd_file to have it active
#
#location /admin {
# # See: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
# auth_basic "Private";
# auth_basic_user_file /path/to/htpasswd_file;
#
# proxy_http_version 1.1;
# proxy_set_header "Connection" "";
#
# 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_pass http://vaultwarden-default;
#}
}
I could see my vault page by restarting nginx and running vaultwarden
,
but before that, I had to do some more configuration.
C. Configure things
Duplicated the .env.template
file and edited it:
# now in the working directory,
$ cp src/.env.template ./.env
$ vi ./.env
a. Enable admin page
There is a guide for enabling admin page.
Created a randomly generated string with:
$ openssl rand -base64 48
and then set ADMIN_TOKEN=xyz0123456789abcdefghijklmnopqrstuvw
.
b. Disable registrations
It is advised to disable registration of (unwanted) new users.
I could do it by just setting SIGNUPS_ALLOWED=false
.
c. Setup SMTP
A little more efforts were needed on SMTP configuration.
SMTP is essential for sending various emails, eg. welcome messages and validation emails.
There are several options of SMTP server/relay services, so choose wisely.
In my case, I created a SendGrid account for it, setting following values:
SMTP_HOST=smtp.sendgrid.net
SMTP_FROM=MY_VERIFIED_EMAIL_ADDRESS
SMTP_FROM_NAME=Vaultwarden
SMTP_SECURITY=starttls
SMTP_PORT=587
SMTP_USERNAME=apikey
SMTP_PASSWORD=SG.0123456_abcdefghijk.XYZ-abcd-ABCD1234
SMTP_AUTH_MECHANISM="Login"
z. Save configurations
Finally, restarted nginx and ran vaultwarden
.
Then I could access the admin page at url: YOUR_SERVER_URL/admin.
Signed in with my ADMIN_TOKEN
, checked things up,
and then pressed the blue Save
button on the bottom left:
Vaultwarden became ready for service!
D. Make it start automatically
For some more convenience, I created a systemd service with this guide,
so it could be launched automatically on reboots.
[Unit]
Description=Vaultwarden
Documentation=https://github.com/dani-garcia/vaultwarden
# Only sqlite
After=network.target
[Service]
# The user/group vaultwarden is run under. the working directory (see below) should allow write and read access to this user/group
User=ubuntu
Group=ubuntu
# Use an environment file for configuration.
EnvironmentFile=MY_WORKING_DIR/.env
# The location of the compiled binary
ExecStart=MY_WORKING_DIR/vaultwarden
# Set reasonable connection and process limits
LimitNOFILE=1048576
LimitNPROC=64
# Isolate vaultwarden from the rest of the system
PrivateTmp=true
PrivateDevices=true
#ProtectHome=true
ProtectSystem=strict
# Only allow writes to the following directory and set it to the working directory (user and password data are stored here)
WorkingDirectory=MY_WORKING_DIR
ReadWriteDirectories=MY_WORKING_DIR
[Install]
WantedBy=multi-user.target
I had to comment out line: ProtectHome=true
because my working directory was inside my home directory.
E. Make it more secure
a. Setup for Fail2ban
See the guide here.
I created filter and jail files for fail2ban:
Files for web vault:
/etc/fail2ban/filter.d/vaultwarden.local
:
# /etc/fail2ban/filter.d/vaultwarden.local
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =
/etc/fail2ban/jail.d/vaultwarden.local
:
# /etc/fail2ban/jail.d/vaultwarden.local
[vaultwarden]
enabled = true
port = 80,443,8081
filter = vaultwarden
banaction = %(banaction_allports)s
#logpath = /path/to/vaultwarden.log
logpath = /var/log/syslog
maxretry = 3
bantime = 14400
findtime = 14400
Files for admin page:
/etc/fail2ban/filter.d/vaultwarden-admin.local
:
# /etc/fail2ban/filter.d/vaultwarden-admin.local
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*Invalid admin token\. IP: <ADDR>.*$
ignoreregex =
/etc/fail2ban/jail.d/vaultwarden-admin.local
:
# /etc/fail2ban/jail.d/vaultwarden-admin.local
[vaultwarden-admin]
enabled = true
port = 80,443
filter = vaultwarden-admin
banaction = %(banaction_allports)s
#logpath = /path/to/vaultwarden.log
logpath = /var/log/syslog
maxretry = 3
bantime = 14400
findtime = 14400
then
$ sudo systemctl reload fail2ban
to make the changes work.
These settings will block abusive/malicious attackers from brute-forcing into the vault.
b. Disable registration, invitations, and/or password hints
See following guides: this one and that one.
Z. Connect Bitwarden app with my Vaultwarden server
I wanted to add my Vaultwarden account in my Android app.
By pressing the ‘gear shaped’ button on the top right,
I could see the screen for entering my own Vaultwarden server url:
After signing in with my account info, I could use the app just like my premium Bitwarden account!
Wrap-Up
Maintaining a server with critical information is quite stressful.
So if I had a choice between keeping my secrets on my own server, and keeping them in a paid service, I would choose the latter, Bitwarden’s premium service.
Nevertheless, building and running a service manually is fun, so it was worth trying :-)