Self-Hosted Password Manager with Dokku
Tags: docker, tutorial, dokku, devops
Published: 2023-04-19 05:46:07

## Why?
I relied on 1Password for the last few years, it is robust, and very user-friendly. However, these types of services are prime targets for attacks, one popular example is the [Lastpass]( https://www.forbes.com/sites/daveywinder/2023/03/03/why-you-should-stop-using-lastpass-after-new-hack-method-update/?sh=70d57e3d28fc) case. It is definitely not cool to have your sensitive info spread in another data breach. Also, privacy is precious nowadays, whoever has the data, has the power.

While exploring Open Source alternatives, I found [vaultwarden](https://github.com/dani-garcia/vaultwarden), an unofficial Bitwarden-compatible server written in Rust.

Migrating data manually is a tedious process, so I first checked how it would be like with Bitwarden. Surprise, surprise, they have it all! You don't have to do it by hand, it already supports the most popular password managers.

*Web - Import Data Page*
![Bitwarden Import Data Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7tn5l91lm52b0qkg8fh.png)

PS: It was a relief to discover a well-done user interface, here's a spoiler:

*macOS app*
![macos App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hgjgb2boxexkqrwxhfwr.png)

To make it cost effective, I decided to use my current Dokku setup, hosted on Google Cloud and powered by Ubuntu 20.04. If you haven't heard of Dokku, this is your chance to try it out https://dokku.com/docs/getting-started/installation/.

So, having in mind the advantages and the infra required, here's how I did it.

## Prerequisites

Before we get started, check that you already have the following:
- A server with Dokku installed.
- A domain name (letsencrypt will check it).
- Local machine with Docker, Git and any SSH client.

## Step by Step

**1. Create Dokku App**

Set your app name and link to the domain (the Dokku Proxy plugin is built in since version 0.5.0)
```bash
dokku apps:create bitwarden

# example: dokku domains:set bitwarden mypasswords.sjdonado.de
dokku domains:set bitwarden yourdomain.com
```

**2. Set up TLS certificates**

The Let's Encrypt plugin automates the generation and renewal of our certificates
```bash

# plugin installation requires root, hence the user change
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

dokku letsencrypt:enable bitwarden
# enable the automatic renewal of certificates 
dokku letsencrypt:cron-job --add

# replace proxy port, default: 5000
dokku config:set bitwarden DOKKU_PROXY_PORT_MAP="http:80:80 https:443:80"
```

**3. Set up database**

We'll use the PostgreSQL plugin
```bash
# setup plugin
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git

# create a new database for our app
dokku postgres:create bitwarden

# link the postgres service to the app, DATABASE_URL will be attached to the ENV variables automatically. 
dokku postgres:link bitwarden bitwarden
```

**4. Set up persistent storage**

We can use the built-in Dokku storage plugin
```bash
dokku storage:ensure-directory bitwarden

dokku storage:mount bitwarden /var/lib/dokku/data/storage/bitwarden:/data
```

**5. Set up ENV variables**

By default, Bitwarden is open to public signups, although we can restrict it to invitation-only by setting `SIGNUPS_ALLOWED` to false and providing a valid `ADMIN_TOKEN`.

We're gonna use `argon2` to generate a PHC string for the `ADMIN_TOKEN` ENV variable

```bash
# skip this line if you are a linux user
docker run --rm -it ubuntu

$ apt update && apt install openssl argon2
$ echo -n "MySecretPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4
# output: $argon2id$v=19$m=65540,t=3,p=4$bXBGMENBZUVzT3VUSFErTzQzK25Jck1BN2Z0amFuWjdSdVlIQVZqYzAzYz0$T9m73OdD2mz9+aJKLuOAdbvoARdaKxtOZ+jZcSL9/N0
```

For the `SMTP_` variables, feel free to use your own SMTP server or comercial solutions with free-tier such as [sendgrid](https://sendgrid.com/)

```bash
dokku config:set bitwarden \
  DOMAIN=https://mypasswords.sjdonado.de \
  SIGNUPS_ALLOWED=false \
  ADMIN_TOKEN='$argon2id...' \
  SMTP_HOST=smtp.sjdonado.de \
  SMTP_FROM=vaultwarden@sjdonado.de \
  SMTP_PORT=587 \
  SMTP_SECURITY=starttls \
  SMTP_USERNAME= \
  SMTP_PASSWORD=
```

**6. Create the Dockerfile**

Let's create a new folder for the project, the Dockerfile and initialise git

```bash
mkdir yourfolder && cd yourfolder
git init
touch Dockerfile
```

`yourfolder/Dockerfile`
```dockerfile
FROM vaultwarden/server:latest

EXPOSE 80

ENV DB=postgresql
```

**7. Deploy**

We are almost there! Before to push the changes, we have to set the dokku remote url

```bash
git remote add dokku-bitwarden dokku@yourdomain.com:bitwarden
```

And finally

```
git add -A && git commit -m "My bitwarden Dockerfile"
git push dokku master

# output:
git push using:  dokku master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 551 bytes | 551.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
-----> Cleaning up...
-----> Building bitwarden from Dockerfile
remote: #1 [internal] load build definition from Dockerfile
remote: #1 transferring dockerfile: 65B done
remote: #1 DONE 0.0s
remote: 
remote: #2 [internal] load .dockerignore
remote: #2 transferring context: 2B done
remote: #2 DONE 0.1s
...
```

**8. That's it**

Now you can access the admin panel via https://yourdomain.com/admin with your `MySecretPassword` (from step 5) and send invitations by email 😎.

![Admin Portal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h421y9wu4ap1kgd8m8ta.png)

**NOTE:** Be sure to add your domain when installing the official Bitwarden apps/extensions.

*Chrome Extension*
![Chrome Extension example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3txh5xhfjsk82f8ocs8f.png)

## Wrapping up

We've explored the process of setting up a self-hosted password manager using Dokku. This can be easily replicated on any IaaS provider.

Now, you can have peace of mind knowing that your passwords are securely stored and easily accessible whenever and wherever you need them.

![gif](https://media.giphy.com/media/EJMyMO22UxP68/giphy.gif)

Source code available on [Github](https://github.com/sjdonado/dokku-self-hosted-services).

---

Go check my website [https://sjdonado.de](https://sjdonado.de), drop me a line. Suggestions are more than welcome in the comments box.

Happy hacking!