Reverse Proxy to bitwardenrs


Although I’ve been able to follow the wiki instructions and have got bitwardenrs and caddy working together using Using Docker Compose · dani-garcia/bitwarden_rs Wiki · GitHub, I’m still at a loss as to how the networking aspects are running behind the scenes.

When I run: docker ps -a

CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS                    PORTS                                                NAMES
c086f294b8ec   bitwardenrs/server:latest   "/usr/bin/dumb-init …"   18 minutes ago   Up 18 minutes (healthy)   80/tcp, 3012/tcp                                     bitwarden
9fbb70db95bc   caddy:2                     "caddy run --config …"   18 minutes ago   Up 18 minutes   >80/tcp,>443/tcp, 2019/tcp   caddy

General network:

											Ubuntu 20.04LTS on rPi4
							|													|
/-------------------\		|	/---------------\			/---------------\	|
|	 	 PC			|		|	|	  caddy		|			|	bitwarden	|	|
|					|		|	| Reverse Proxy	|			|				|	|
|	browse to:		|		|	|				|			|				|	|
|	|		|	|	80			|<--------->|	80			|	|
|					|		|	|  443			|			| 3012			|	|
|					|		|	| 2019			|			|				|	|
\-------------------/		|	\---------------/			\---------------/	|			|													|
			^				\---------------------------------------------------/
			|	/-------------------\				  ^
			|	|	 				|				  |
			|	|					|				  |
			\-->|	   Router		|<----------------/
				|					|
				|					|

I used the following command as advised here Starting a Container · dani-garcia/bitwarden_rs Wiki · GitHub

docker run -d --name bitwarden -v /bw-data/:/data/ -p 80:80 bitwardenrs/server:latest

bitwardenrs becomes available from my PC using the non-https i.e.

However, the bitwardenrs wiki Enabling HTTPS · dani-garcia/bitwarden_rs Wiki · GitHub states that for proper operation HTTPS is required.

Further, Enabling HTTPS · dani-garcia/bitwarden_rs Wiki · GitHub states: “If you aren’t familiar with reverse proxies and have no preference, consider Caddy first, since it has built-in support for obtaining Let’s Encrypt certs”.

I therefore followed the advice and installed caddy, and am currently trying this Caddyfile: {
  log {
	level INFO
	  output file /var/log/caddy {
		 roll_size 10MB
		 roll_keep 10
  reverse_proxy localhost:3012

I then start caddy with:
sudo systemctl start caddy

And review its status:
sudo systemctl status caddy

Which shows it has failed:

run: loading initial config: loading new config: http app module: start: tcp: listening on :80: listen tcp :80: bind: address already in use
systemd[1]: caddy.service: Main process exited, code=exited, status=1/FAILURE

The result being that I still can’t access bitwarden via the desired

I’ve tried various ports in the Caddyfile, but to no avail and I don’t know what else to try here.

I appreciate I can just use the (working) docker-compose implementation, but I’d really like to understand what’s going on and to be able to run it without docker-compose.

As it’s been said “if you can’t explain it simply, you don’t understand it well enough” and I really don’t understand it well enough. Help!

I’d really appreciate it if someone could explain it simply to me.


Caddy fails because it needs to bind to port 80 (the HTTP port) for automatic https. By default it probably binds to all interfaces on the docker host.

listen tcp :80: bind: address already in use

Looking at the error message, your bitwarden container presumably already listens on port 80. In the docker-compose.yml example there are no published ports on the bitwarden container because docker-compose would automatically create a default network and add all services to this network. The caddy container can talk to the bitwarden container because they are on the same network. It works in that case because only the caddy container will have a published port 80 on the docker host.

So you can either recreate the docker-compose.yml manually or simply use a port mapping to the docker host for the port 80 of the container. E.g.

docker run -d --name bitwarden -v /bw-data/:/data/ -p  bitwardenrs/server:latest

So you publish the port 80 of the container on the loopback interface on port 8080 on the localhost. Then you can reverse_proxy to localhost:8080 and it should just work and no one (except other processes on the docker host) can access your bitwarden on port 80 directly.

If you want to enable websockets you could do the same for port 3012 (e.g. publish a different, unused port with -p

I hope this clears it up.

Just to add a little bit more than what was above – Port 80 and 443 need to be bound by Caddy. Your first setup had bitwarden_rs binding port 80, hence the reason Caddy was unable to start. Only one application can listen on each port at once.

One thing you might need to consider, since it depends on how you want to use your Bitwarden_RS image.

If you need to access the bitwarden container not going through the reverse proxy, do as stated above – link host port 8080 to the container’s port 80.

If you do not to directly access the bitwarden container to the container (all communication flows from the host through the reverse proxy), there is a terms within docker known as “expose” rather. Expose makes the containers port number only to other containers within docker. You can use either the ports command or the expose command.

Just to add a little bit more :slight_smile:

Since you probably expect to use Bitwarden from your mobile when being on Internet, you will have to forward port 80 and 443 on your router, to the internal IP that hosts caddy (in your case - the RPi).

This way, you will be able to retrieve the certs (there are other ways but this sone will be the simplest one) - LE will connect to your port 80 (ultimately handled by caddy), do its magic and then there will be automatic redirection from port 80 to 443.

Caddy is a godsend, this is truly an extraordinary web server.

Thanks for all your helpful replies.

I tried @stefan0xC feedback, which thankfully now allows both bitwardenrs and caddy to run at the same time but unfortunately, I ended up with just a blank screen when navigating to bitwarden in the browser.

@kevdog thanks for the tip re “expose”. I’ll read up on that.

@WpJ thanks, I’ve setup port farwarding. Just trying to get my head around caddy, as I only heard of it a couple of days ago, but am really liking it despite my current challenges.

I also think my various trial and errors over the past few days may be compounding the issue, so I’m going to start with a fresh install and apply the above.


Caddy is by far the simplest web server I used, while still having really great features (this is from someone who managed Apache and Nginx based servers for 20+ years (Nginx is younger of course)).

The community is great and a lot is very intuitive and simple to configure.

If you copy-paste the Caddy 2 example from Proxy examples · dani-garcia/vaultwarden Wiki · GitHub you will be fine.

Do not hesitate to ask for help here, someone has already suffered to fix it :slight_smile:

The advantage of using docker is that restarting from scratch is easy.


I did another fresh build of the system but still couldn’t get Bitwardenrs working with Caddy as a reverse proxy, as I kept getting SSL, 502, or just blank screen errors.

Seeing Bitwardenrs was running fine, I focussed on Caddy and decided to go back to basics and start “from scratch” following the various steps of

Trying various configs, and then running the following commands returned these errors:

ubuntu@ubuntu:/etc/caddy$ curl -I
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

ubuntu@ubuntu:/etc/caddy$ curl https://localhost
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

ubuntu@ubuntu:~$ curl https://localhost
curl: (7) Failed to connect to localhost port 443: Connection refused

ubuntu@ubuntu:~$ curl https://localhost:443
curl: (7) Failed to connect to localhost port 443: Connection refused

ubuntu@ubuntu:/etc/caddy$ curl -I localhost
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://localhost/
Server: Caddy
Date: Tue, 16 Mar 2021 06:52:22 GMT

After yet another config change I noticed:

ubuntu@ubuntu:/etc/caddy$ caddy run
2021/03/16 06:54:18.307 INFO    using adjacent Caddyfile
2021/03/16 06:54:18.311 INFO    admin   admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", ""]}
2021/03/16 06:54:18.312 INFO    tls.cache.maintenance started background certificate maintenance      {"cache": "0x4000362b60"}
2021/03/16 06:54:18.312 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2021/03/16 06:54:18.312 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2021/03/16 06:54:18.313 INFO    tls     cleaned up storage units
run: loading initial config: loading new config: http app module: start: tcp: listening on :443: listen tcp :443: bind: permission denied

Aha! that was it: “bind: permission denied” and after much researching I found that I needed to:

sudo setcap 'cap_net_bind_service=+ep' /usr/bin/caddy

Rebooted and It works!

I’m guessing its because I’m (being stubborn and) using Ubuntu server LTS on my rPi4, that I ran into this problem. So just in case anyone runs into a similar issue, I hope this might help.

Anyway, all good learning points for me and glad I (eventually) getting it working.