There are many password managers on the market today. Most are vendor-hosted, such as LastPass, which puts you in the position of trusting the vendor’s security (on both the client and storage side). Some offer self-hosted options, but generally require Dropbox or other cloud storage. There are also standalone apps where you engineer any synchronization yourself, but not all provide the creature comforts of cross-device synchronization and browser fillers.
In this tutorial, we’ll look at Bitwarden, a password manager that offer self-hosted options, and walk through setting it up.
First, take note of the somewhat steep hosting requirements: 4G of RAM. You may be able to cheat a little if you’re the only user, but you’re not going to host this on a 128MB system.
Also, note that Bitwarden is docker-based, which has implications for those wanting to host on OpenVZ. But really, it’s 2020, folks.
Before you begin, head over to https://bitwarden.com/host/ and enter your email address. This will provision you an installation ID and installation key, which you’ll need to install BitWarden
With those out of the way, let’s get down to typing commands. Install some prereqs:
apt install -y apt-transport-https ca-certificates wget gnupg2 software-properties-common curl
Now we’ll add the docker repo:
wget -O - https://download.docker.com/linux/debian/gpg | apt-key add
echo "deb (arch=amd64) https://download.docker.com/linux/debian buster stable" > /etc/apt/sources.list.d/docker.list
apt install -y docker-ce docker-ce-cli containerd.io
Bitwarden wants a later/greater docker-compose than is in the repo as of this time of writing, so I’ll manually download it:
curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod 755 /usr/local/bin/docker-compose
Now you can start and enable docker:
cd systemctl start docker
systemctl enable docker
Let’s make sure docker works:
root@bitwarden:~# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
One final step is to install the mail system of your choice. If you don’t have a choice, postfix is easy to use.
apt install postfix
Select “Internet Site” and enter the FQDN of your server (in this case, bitwarden.lowend.party).
I host in /bitwarden, but you can put your install anywhere you like.
curl -Lso bitwarden.sh https://go.btwrdn.co/bw-sh && chmod +x bitwarden.sh
There’s a lot out output and status messages. You will need to answer some questions:
(!) Enter the domain name for your Bitwarden instance (ex. bitwarden.example.com): bitwarden.lowend.party
(!) Do you want to use Let's Encrypt to generate a free SSL certificate? (y/n): y
(!) Enter your email address (Let's Encrypt will send you certificate expiration reminders): firstname.lastname@example.org
(!) Enter your installation id (get at https://bitwarden.com/host): (you got this above)
(!) Enter your installation key: (you got this above)
We need to configure mail parameters before we start Bitwarden. To do this, edit /bitwarden/bwdata/env/global.override.env and change as follows:
This assumes you’re running a stock postfix configuration. You can also configure to use a different mail host, use SSL, login with a username/password, etc.
Once this step is complete, you’re ready to run Bitwarden. Let’s do it through systemd, so that if our VM restarts for any way, Bitwarden will start on boot.
Place the following in /etc/systemd/system/bitwarden.service:
Now enable and start Bitwarden:
systemctl enable bitwarden
systemctl start bitwarden
Bitwarden can take a minute or two to startup because it has to pull docker images, etc. BTW, yes, that’s Microsoft SQL Server (Express Edition) running under the covers.
Before we login, we want to configure postfix to accept mail from Bitwarden. Because Bitwarden is running via docker, when we tell it to send email to localhost, it’s not the same localhost Postfix is thinking of. Let’s see where it’s running.
# docker network ls
NETWORK ID NAME DRIVER SCOPE
d9cc1f3a6b10 bridge bridge local
f98a474288df docker_default bridge local
87cb796a4769 docker_public bridge local
13f31967b4d1 host host local
c15a9550aee7 none null local
If you were to look in /bitwarden/bwdata/docker/docker-compose.yml, you’d see that the ‘api’ container uses the ‘default’ and ‘public’ networks. After issuing
docker network inspect 87cb796a4769
I see that the docker API container is running on 172.19.0.3.
Edit /etc/postfix/main.cf to add the part in bold:
mynetworks = 127.0.0.0/8 (::ffff:127.0.0.0)/104 (::1)/128 172.19.0.0/16
Once Bitwarden is up and running, browse to your hostname. In this case, https://bitwarden.lowend.party.
Click Create Account.
Fill out the form. Note that you’re not creating an account on bitwarden.com but rather on your server.
Now login to your account.
You can click Verify Email and an email verification will be sent to you.
Let’s add an item. Click Add Item.
Click Save and it’s now ready for synchronization everywhere.
Configuring Your Client Devices
I’m going to walk through setting up the Chrome extension.
Once setup, click on the Bitwarden icon and the setup screen will drop down.
If you attempt to login there, you’ll be logging into Bitwarden.com. Instead, click the gears icon.
Enter your server URL. Then save and login with your credentials.
Your synchronized vault will appear.
The setup on phones, etc. is virtually identical as it’s the same panels and forms. Remember click the gear icon to enter your custom server URL.
Let’s use this login. I browse to the world’s greatest web site and click Sign In. When the Sign In box pops up, I hit control-shift-L (command-shift-L on Mac) and my credentials are autofilled.
Right now, anyone who comes across your Bitwarden install can click Create Account and set themselves up. They won’t have access to your logins (unless they know your login and master password) but you don’t want people setting up accounts.
To prevent this, edit /bitwarden/bwdata/env/global.override.env and set disableUserRegistration to true:
This toggles account to creation to false. Note that the button will still appear in the GUI but people won’t be able to create accounts.
To backup Bitwarden, you should
- Shutdown Bitwarden to ensure the database is consistent
- Backup /bitwarden/bwdata
- Restart Bitwarden
Should you need to restore a backup, follow this Bitwarden doc.