Deploying Vaultwarden on Raspberry Pi

Vaultwarden (formerly Bitwarden_RS) is a lightweight, self-hosted Bitwarden-compatible password management server written in Rust. It has low resource consumption, is suitable for single-machine deployment, and is ideal for individuals or small teams.

I mainly use it to fill in the gaps that KeePassXC cannot cover. Its multi-device synchronization function is perfect for local area networks. For example, if you save a password on your home computer, you can synchronize it to your phone or tablet on the same Wi-Fi network through Vaultwarden, without having to go through the public internet.

Frankly, for password management tools, I don't trust any solutions that can be accessed via the public internet. Therefore, deploying Vaultwarden privately on a Raspberry Pi is very reasonable.

Device Information:

1mephisto@raspberrypi:~ $ cat /proc/cpuinfo | grep Model
2Model		: Raspberry Pi 2 Model B Rev 1.1
3mephisto@raspberrypi:~ $ uname -m
4armv7l

I've already run many services on it

 1systemd─┬─ModemManager───2*[{ModemManager}]
 2        ├─NetworkManager───2*[{NetworkManager}]
 3        ├─2*[agetty]
 4        ├─avahi-daemon───avahi-daemon
 5        ├─cron
 6        ├─dbus-daemon
 7        ├─frpc───6*[{frpc}]
 8        ├─navidrome───12*[{navidrome}]
 9        ├─nginx───4*[nginx]
10        ├─polkitd───2*[{polkitd}]
11        ├─prometheus───10*[{prometheus}]
12        ├─sing-box───10*[{sing-box}]
13        ├─sshd───sshd───sshd───bash───pstree
14        ├─sudo───sudo───vim───{vim}
15        ├─systemd───(sd-pam)
16        ├─systemd-journal
17        ├─systemd-logind
18        ├─systemd-timesyn───{systemd-timesyn}
19        ├─systemd-udevd
20        ├─thd
21        └─vaultwarden───12*[{vaultwarden}]

Currently running: frpc, navidrome, sing-box, prometheus. Yesterday, I added vaultwarden. These are all lightweight services I'm using for personal projects. CPU is mostly idle, memory usage is less than 1/3, and only disk space is running low.

Enough of the digression, let's get started. The difficulties lie in two areas:

  • Cross-compiling a 32-bit ARMv7l binary program on the computer;
  • Configuring certificates to make the Bitwarden client available on iPhone and iPad.

Both are challenging, mainly due to the limited availability of relevant information online.

1. Cross-compiling the 32-bit ARM version of vaultwarden on the computer

Searching online, private deployments of vaultwarden all seem to use Docker. But why should I, with a low-spec Raspberry Pi, need to install Docker separately? Wouldn't a direct binary deployment be better?

Of course, for high-spec machines or those who don't want the hassle, running Docker saves time.

The official release page doesn't provide a pre-compiled version for ARMv7; you have to cross-compile it yourself on an Arch Linux host. This is the best way to get the latest version, security updates, and ARMv7 support.

Avoid this pitfall: Do not use paru -S arm-linux-gnueabihf-gcc for cross-compilation. arm-linux-gnueabihf-gcc in the AUR will download many extra environment packages, several gigabytes in size. Compiling these packages alone can take hours and could lead to errors—a disaster! Try it and see.

At this point, it's truly remarkable! The gcc-arm-linux-gnueabihf package is included by default in Debian distribution repositories, eliminating the need for manual compilation. It's a powerful feature; Arch doesn't have it, and that's the difference.

First, switch to the Vaultwarden source code directory, and then start compiling.

Compilation Method:

 1docker run --rm -v "$(pwd)":/build -w /build \
 2  debian:bookworm \
 3  bash -c "
 4    apt update && apt install -y \
 5      curl build-essential gcc-arm-linux-gnueabihf pkg-config
 6
 7    dpkg --add-architecture armhf
 8    apt update
 9    apt install -y libssl-dev:armhf libsqlite3-dev:armhf
10
11    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
12    source /root/.cargo/env
13
14    mkdir -p .cargo
15    cat > .cargo/config.toml <<EOF
16[target.armv7-unknown-linux-gnueabihf]
17linker = \"arm-linux-gnueabihf-gcc\"
18runner = \"qemu-arm -L /usr/arm-linux-gnueabihf\"
19EOF
20
21    export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig
22    export PKG_CONFIG_SYSROOT_DIR=/
23
24    rustup target add armv7-unknown-linux-gnueabihf
25    cargo build --release --target=armv7-unknown-linux-gnueabihf --features sqlite
26  "

The above means using a Docker image This was compiled using debian:bookworm, within a container, and took several hours of trial and error.

For example, enabling multiarch support, addressing missing libssl-dev:armhf and libsqlite3-dev:armhf, and configuring the --features sqlite compilation parameter are all things that anyone who's done the coding will know. However, with AI assistance, it's a bit easier.

Readers can directly use the compilation statements above, saving approximately 2 hours. Compilation takes time, depending on your computer's configuration, so please be patient!

View compilation results

1➜ vaultwarden git:(main) file target/armv7-unknown-linux-gnueabihf/release/vaultwarden
2target/armv7-unknown-linux-gnueabihf/release/vaultwarden: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=e8a6e119d65a23dc6b2833d59aa669bb36bdce38, for GNU/Linux 3.2.0, not stripped

Confirmed to be 32-bit Archv7. Just copy it to the Raspberry Pi and it will run.

2. Install Web Vault, etc.

Running vaultwarden on the Raspberry Pi will prompt you to install Web Vault.

 1# 1. Enter the Vaultwarden installation directory
 2cd /opt/vaultwarden
 3
 4# 2. Create the web-vault directory
 5sudo mkdir -p web-vault
 6
 7# 3. Enter the web-vault directory
 8cd /opt/vaultwarden/web-vault
 9
10# 4. Download
11sudo wget https://github.com/dani-garcia/bw_web_builds/releases/download/v2025.12.2/bw_web_v2025.12.2.tar.gz
12
13# Extract to the current directory (Note: tar.gz usually contains a top-level directory; we need to extract the contents)
14sudo tar -xzf bw_web_v2025.12.2.tar.gz --strip-components=1
15
16# Clean up the compressed file
17sudo rm bw_web_v2025.12.2.tar.gz
18
19# Permission handling
20sudo chown -R vaultwarden:vaultwarden /opt/vaultwarden/web-vault

Other configuration information

 1mephisto@raspberrypi:~ $ systemctl cat vaultwarden.service
 2# /etc/systemd/system/vaultwarden.service
 3[Unit]
 4Description=Vaultwarden Password Manager (Raspberry Pi)
 5After=network.target
 6
 7[Service]
 8User=vaultwarden
 9Group=vaultwarden
10WorkingDirectory=/opt/vaultwarden
11EnvironmentFile=/etc/default/vaultwarden
12ExecStart=/opt/vaultwarden/vaultwarden
13Restart=always
14RestartSec=10
15
16[Install]
17WantedBy=multi-user.target
18mephisto@raspberrypi:~ $ cat /etc/default/vaultwarden
19DOMAIN=http://192.168.1.5
20ADMIN_TOKEN='your token'
21WEBSOCKET_ENABLED=true
22DATA_FOLDER=/opt/vaultwarden/data
23ROCKET_ADDRESS=127.0.0.1
24ROCKET_PORT=8080

The ADMIN_TOKEN is generated by sudo -u vaultwarden /opt/vaultwarden/vaultwarden hash. If it doesn't meet the requirements, check the startup logs for troubleshooting.

After starting sudo systemctl start vaultwarden, confirm the process is running normally:

1mephisto@raspberrypi:~ $ sudo ss -lntp |grep vault
2LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:\* users:(("vaultwarden",pid=16926,fd=22))

3. Nginx Configuration

No one wants to access the site via port 8080, and the mobile version of Bitwarden requires HTTPS, so it needs to be proxied through Nginx.

 1mephisto@raspberrypi:~ $ cat /etc/nginx/sites-enabled/vaultwarden
 2server {
 3    listen 443 ssl;
 4    server_name _;
 5
 6    ssl_certificate /etc/nginx/ssl/my.pem;
 7    ssl_certificate_key /etc/nginx/ssl/my.key;
 8
 9    location / {
10        proxy_pass http://127.0.0.1:8080;
11        proxy_set_header Host  $host;
12        proxy_set_header X-Real-IP  $remote_addr;
13        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
14        proxy_set_header X-Forwarded-Proto  $scheme;
15    }
16
17    location /notifications/hub {
18        proxy_pass http://127.0.0.1:8080;
19        proxy_http_version 1.1;
20        proxy_set_header Upgrade  $http_upgrade;
21        proxy_set_header Connection "upgrade";
22    }
23}

The above configuration is simple. After starting and running Nginx, you can access https://192.168.1.5 through a computer browser to use it normally (trusting the certificate is still necessary).

The certificate part requires special explanation, see the next section.

4. Mobile Certificate Handling

Trap: On iPhone and iPad, certificates generated using methods like the following are unusable ❌, due to Bitwarden limitations, please note!

1sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/ssl/vaultwarden.key -out /etc/nginx/ssl/vaultwarden.crt -subj "/CN=192.168.1.5"

You need to use mkcert to generate the certificate on your computer!`

 1➜  ~ sudo pacman -S mkcert
 2➜  ~ mkcert 192.168.1.5
 3Created a new local CA 💥
 4Note: the local CA is not installed in the system trust store.
 5Run "mkcert -install" for certificates to be trusted automatically ⚠️
 6
 7Created a new certificate valid for the following names 📜
 8 - "192.168.1.5"
 9
10The certificate is at "./192.168.1.5.pem" and the key at "./192.168.1.5-key.pem"11
12It will expire on 25 April 2028 🗓

Replace ssl_certificate and ssl_certificate_key in Nginx with the above certificate and key respectively. I think you understand.

In addition, you need to import the root certificaterootCA.pem to the mobile device.

1➜ ~ mkcert -CAROOT
2/home/mephisto/.local/share/mkcert
3➜ ~ ls /home/mephisto/.local/share/mkcert/rootCA.pem
4/home/mephisto/.local/share/mkcert/rootCA.pem

For detailed instructions, please refer to this document: https://github.com/FiloSottile/mkcert?tab=readme-ov-file#mobile-devices

After transferring it to your phone, follow the instructions above to set up and trust the certificate. Otherwise, your Bitwarden will not work and will display errors, the error messages of which are unclear!

Only after trusting the certificate and no longer encountering errors when creating an account can you say you've successfully completed the process.

Why does the certificate generated by openssl fail while the one generated by mkcert works? I really don't understand. Perhaps this is just the Apple ecosystem. I don't have an Android phone, so I haven't done any testing. After all these years of experimentation, I've come to the strong feeling that web standards are still the best—the true internet.

5. Other

Finally, here are some usage experiences: On a PC browser, I use it in conjunction with the Bitwarden browser extension.

On iPhone and iPad:

  • Autofill, can coexist with Password
  • Enable refresh synchronization for easy multi-device synchronization
  • Enable Face ID, Touch ID, etc. I think nobody likes entering a strong master password.

As for how to use it, you'll figure it out with a little exploration; it's very convenient.

In addition, I keep my core personal passwords in KeePassXC. I personally prefer an offline encryption solution where I have complete control over my passwords. It's only because KeePassXC lacks multi-device capabilities that I also enable Bitwarden, suitable for some less important mobile login scenarios, serving as a supplement to KeePassXC. I find it very convenient and secure. If you trust Bitwarden, with cross-device synchronization and even public network access enabled, it can completely replace other password managers, such as the system's built-in Password Manager.

Lastmod: Monday, January 26, 2026

See Also:

Translations: