Install Docker
# curl -sSL https://get.docker.com | sh
Add user(s) to the docker group. The default user would be pi. However, I highly recommend deactivating the default user.
# usermod -aG docker pi
Reboot and then test docker
$ docker run hello-world
Install more dependencies
# apt-get install -y libffi-dev libssl-dev # apt-get install -y python3 python3-pip # apt-get remove python-configparser # pip3 -v install docker-compose
Fight With SSL
This is the most annoying part of the story. You can either choose to use letsencrypt or a self-signed openssl-cert. Letsencrypt will only work, if your service will be exposed publicly. Also, letsencrypt is fairly easy to setup, so I will focus on a self-signed openssl-solution.
First, we’ll need a “virtual” certificate authority (CA) that will actually sign our certificate later. If you already have a CA, you can skip this. The first command creates a private key, the second command creates the root certificate of our CA.
$ openssl genrsa -out myCA.key 2048 $ openssl req -x509 -new -nodes -sha256 -days 3650 -key myCA.key -out myCA.crt
Now, we’ll need to create a “client” key and a certificate signing request, which will then be “sent” to our CA.
$ openssl genpkey -algorithm RSA -out bitwarden.key -outform PEM -pkeyopt rsa_keygen_bits:2048 $ openssl req -new -key bitwarden.key -out bitwarden.csr
For the actual signing, we’ll also need an extension file. I ran into problems with OSX and iOS without adding the used extensions during signing. Neither OSX, iOS nor Google Chrome accepted the certificate without those extensions. Create a file openssl.cnf
[v3_ca] basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment subjectAltName = DNS:<hostname>, IP:127.0.0.1, IP:<ip>
Replace <hostname> and <ip> with your actual values.
Finally, the actual signing:
$ openssl x509 -req -in bitwarden.csr -CA myCA.crt -CAkey myCA.key -CAcreateserial -out bitwarden.crt -days 365 -sha256 -extfile openssl.cnf
The certificate you’ll need to deploy on your devices is the root certificate. Yes, this will also work on iOS.
Install/Configure Bitwarden
We’ll use the bitwarden_rs docker container. It uses sqlite instead of MSSQL, which is not available for ARM.
$ docker pull bitwardenrs/server:raspberry
If docker successfully downloaded the image, you can run it as follows. I simply created a small bash script.
$ docker run -d --name bitwarden \ -e ROCKET_TLS='{certs="/ssl/bitwarden.crt",key="/ssl/bitwarden.key"}' \ -v /path/to/certs/:/ssl/ \ -v /path/to/bw-data/:/data/ \ -v bitwarden:/config \ -p 443:80 \ --restart always \ bitwardenrs/server:raspberry
The ROCKET_TLS argument tells bitwarden, where it can find its key and certificate. The values describe paths within the docker container. For these paths to work, we’ll need to supply a volume mapping (-v). The additional volume mapping bw-data is a volume for bitwarden to store its actual sqlite “database” in. Internally, bitwarden will bind to port 80. Since we know/hope it’ll run SSL, we can map internal port 80 to 443.
If everything works, you can reach your bitwarden vaults on https://<hostname>
You’ll most likely run into SSL problems. Good luck.
Backup
Read this article.
Debugging/FAQ
Show running docker containers
$ docker ps
Logs and events
$ docker logs <container> $ docker events
Run command within a docker container
$ docker exec -it <container> /bin/bash
Netstat (works w/o actual netstat binary in container. Cool, eh!?)
$ docker inspect -f '{{.State.Pid}}' <container> # nsenter -t <pid> -n netstat
A word on IPv6. Initially, when bitwarden didn’t work during my first attempts, I was confused by the output of netstat. It showed, that the destination socket for https was only bound to tcp6. This shouldn’t be a problem, though, because bitwarden also sets up a couple of iptables rules (# iptables -L). However, if you think it might be a problem on your machine, try the following things in your /etc/sysctl.conf
net.ipv6.bindv6only = 0 net.ipv6.conf.all.forwarding = 1 net.ipv4.conf.all.forwarding = 1
At one point, I even completely disabled IPv6 via the kernel command line. However, that introduced even more problems.