Setting up Bitwarden on reverse proxy

Hi,

I’m new to self-hosting, and I’m trying to get things set up. I’m not an IT employee or anything, I’m not deploying stuff to multiple users, and I don’t need to manage tons of accounts. I’m just a nerd with a server in my apartment and I want to learn how to host things on the internet.

That being said: I’ve installed Bitwarden on my Debian server. I followed all the instructions on Install and Deploy - Linux | Bitwarden Help Center. This included buying a domain name (From Namecheap), associating its DNS record to my IP address, etc. I now have a working installation, and I’m happy about that!

Now, if I go to my domain example.com, I am greeted with the Bitwarden main login page. The next thing I’d like to do is put the Bitwarden page in a subdomain. I want example.com to go to my personal website (which I’m writing myself in pure HTML/CSS, rather than using Wordpress or similar - I think it’s fun to learn to do things myself). Then, to access my Bitwarden instance, I would use bw.example.com. I stress that I am running this all on a single Debian server. This creates a conflict, since Bitwarden wants to use port 80 to serve everything, but I want to also host my generic webpage, which would also use port 80. My understanding is that this is where a reverse proxy comes in. Traffic for bw.example.com would be directed to the Bitwarden Docker container, while example.com would go to the main web page. I found that Nginx Proxy Manager is an option people often use (and, from my understanding, the main Bitwarden already uses Nginx?). What I’m struggling with is configuring this. My understanding is that the idea would be for Nginx to be the only thing operating on the main 80 and 443 ports, and it would direct traffic to Bitwarden on a different port, but only if that traffic is looking for bw.example.com. So I went into Bitwarden’s bwdata/config.yml and changed http_port to 800, and https_port to 444. Then I ran bitwarden.sh rebuild, to make it pull in those changes. My next step was to figure out how to get Nginx to associate to those ports.

However, after rebuilding I went to do bitwarden.sh start and I get:

Open source password management solutions
Copyright 2015-2022, 8bit Solutions LLC
https://bitwarden.com, https://github.com/bitwarden

===================================================

bitwarden.sh version 1.47.1
Docker version 20.10.14, build a224086
docker-compose version 1.29.2, build 5becea4c

Pulling mssql         ... done
Pulling web           ... done
Pulling attachments   ... done
Pulling api           ... done
Pulling identity      ... done
Pulling sso           ... done
Pulling admin         ... done
Pulling icons         ... done
Pulling notifications ... done
Pulling events        ... done
Pulling nginx         ... done
Using default tag: latest
latest: Pulling from certbot/certbot
Digest: sha256:d13d98ebf10c37e864da33f89585dfc712185fca0b6740d956106f64d467ee6a
Status: Image is up to date for certbot/certbot:latest
docker.io/certbot/certbot:latest
docker: Error response from daemon: driver failed programming external connectivity on endpoint certbot (e7ad08a13667cf96d3dd2823ea9c7e089020e3c16e79c8514c91d89680e41f2e): Bind for 0.0.0.0:443 failed: port is already allocated.

So what I see is that it’s still trying to bind 443, even though I changed https_port to 444 instead. This means I can’t properly launch Bitwarden. I might be totally going about this the wrong way - but I’d really appreciate anyone who can steer me in the right direction. Thanks!

Your description sounds like it should work, at least it’s very similar to the things I did when setting this up (quite a while ago, though).

Try to take a look at the ports in the nginx section of bwdata/docker/docker-compose.yml. Do you see the changed ports there?

Here’s the nginx portion of bwdata/docker/docker-compose.yml:

  nginx:
    image: bitwarden/nginx:1.47.1
    container_name: bitwarden-nginx
    restart: always
    depends_on:
      - web
      - admin
      - api
      - identity
    ports:
      - '800:8080'
      - '444:8443'
    volumes:
      - ../nginx:/etc/bitwarden/nginx
      - ../letsencrypt:/etc/letsencrypt
      - ../ssl:/etc/ssl
      - ../logs/nginx:/var/log/nginx
    env_file:
      - ../env/uid.env
    networks:
      - default
      - public

Looks like it took my 800 and 444.

I also started setting up nginx separately, before realizing Bitwarden has an nginx instance built in… I followed this guide: Nginx Proxy Manager

So maybe I’m duplicating work. Not sure. In any case, Bitwarden shouldn’t still be trying to use 443…

Sounds as though Bitwarden is not taking port 443 but certbot. That is to say Bitwarden’s Nginx reverse proxy is not, and have been remapped with the ports 800 & 444 as you mentioned, but Bitwarden’s certbot service is still attempting to bind to port 443.
Most likely during the install script you selected to have Bitwarden generate a valid certificate for you.

You will want to either use a self-signed cert, which can then be used with a valid cert in the front end “main” Nginx on the Debian host, or if you already have a valid cert from this Nginx proxy the same cert can also be used for Bitwarden.

Yes, I chose to have Bitwarden generate a valid certificate for me, since I do not already have a valid certificate.

Are you sure I want a self-signed cert? The page you linked says:
"You may alternatively opt to use a self-signed certificate, however this is only recommended for testing.

Self-signed certificates will not be trusted by Bitwarden client applications by default."

That sounds like I shouldn’t want to do this.

If you are using another Nginx instance as the front-end reverse proxy then that should be where the valid certificate whould live as that would ultimately be where your client applications terminate.

As you mentioned

This is exactly how the flow of traffic should go. Either Nginx would have multiple certificates for bw.example.com & example.com, a single cert with multiple hostnames (though I do believe this can cause some issues with the Bitwarden client if the bw.example.com is secondary), or a simple wildcard certificate for *.example.com

From the front-end main Nginx this can be set to forward traffic to the Bitwarden docker on the appropriate ports, the connection between Nginx to Bitwarden can connect using the self-signed certificate without issue.
Since the certificate would also live on the same Debian host as your Bitwarden docker, you could pass the valid cert on the main Nginx proxy into the Bitwarden containers and also use the same certificate.

I’m getting a little lost here on what the actual solution is.

What certificate goes where and how do I set that up? Especially, you said “Since the certificate would also live on the same Debian host as your Bitwarden docker, you could pass the valid cert on the main Nginx proxy into the Bitwarden containers and also use the same certificate.”

But I don’t know what I actually invoke in order to do this.

I imagine setting up Bitwarden as a non-exclusive hosted process (allowing other things to be hosted on the same machine) is not a novel concept. Is there a Bitwarden setup guide, similar to the one I linked originally, for getting it set up with the reverse proxy? I’m not “married” to any particular approach. If the Bitwarden-included Nginx can be configured to only host Bitwarden at bw.example.com, that would absolutely solve things for me.

Sorry for the confusion, it can be a bit much to wrap your head around initially as there are quite a few moving parts. With technology and especially in your case there are several avenues you can take to achieve your desired end goal to host Bitwarden on the same Debian machine as your webserver.

Bitwarden when installed, runs multiple separate docker containers.
The parts of the service you would mostly be concerned about would be:

  • The “main” Bitwarden service itself
  • The Bitwarden Nginx service, which would listen on ports 80 and 443 by default for a standard install
  • Certbot service for generating valid trusted LetsEncrypt Certificates.

Certbot listens on port 443 to generate valid LetsEncrypt certificates for the Bitwarden service to use. This cert is used by the Bitwarden Nginx container to route traffic to the appropriate endpoints, and validate the client termination to the proper self-hosted server.
In your case you would want to not have Bitwarden generate a valid certificate, and this should prevent the Certbot container from binding to your host machine port 443.

You have two options as you would be using an Nginx reverse proxy on the main Debian host, you will want to have some way to generate a valid certificate on that machine’s Nginx.

  1. Either with generating a free ACME cert with something such as Certbot.

  2. Purchasing a valid SSL certificate from a trusted vendor
    i.e Namecheap, DigiCert, Comodo, etc.

The easiest option would be to use a wildcard certificate, aka *.domain.com which would work for www.domain.com and bitwarden.domain.com

Once you have your working SSL certificate, you will have again two options.

  1. The “main” Nginx will have the valid cert, and can proxy all traffic for Bitwarden to the Bitwarden Nginx (on ports 800 and 444 that were changed).
    Bitwarden can be set to generate a self-signed cert for use, and the main Nginx proxy will send all traffic to the Bitwarden Nginx with the self-signed cert, but your client only ever will see and connect to the main Nginx with the valid cert.

  2. Since the valid SSL certificate will live somewhere in the Debian host machine for the main Nginx, this can also be “passed” into the Bitwarden docker container with the use of environment variables.
    This would mean both of your main Nginx proxy and the Bitwarden Nginx proxy will use the same valid SSL certificate, which lives on the Debian host, and is updated and maintained on the host side, rather than only directly with the Bitwarden service.

I hope this goes to clear it up a bit, feel free to go about asking anything else if you still have any questions you are unsure of. Hopefully I (or someone else) can get back in a timely manner.
Unfortunately full-time jobs tend to take most of the time allocation for my day but I will always do what I can when I can to provide information to the best of my knowledge.

1 Like

Sorry for bringing this topic back up, but I am at the last steps here where you gave 2 options, I’d like to use option 2 and using Nginx Proxy Manager’s SSL cert and pass it onto the bitwarden docker, but how do I do this?
Do you have a link to an article to set this up?

Yes!!
This is the point!

I have set up Bitwarden on a VM
during install, I said:
domain is Bitwarden.local
No certificate…
Created a self signed…

With the IP of the VM I can reach Bitwarden only using HttpS://192.xxx.xxx.xxx
now I point my.Domain com with Nginx Proxy Manager to the IP of VM
Port 443 / 80 !!??
THIS does not work!

Have you finally found a solution – A working solution :grinning:

I hope you have not given UP !

Just in case anyone needs it.

Posting my solution to this here.

  1. Deploy your Nginx PM first ( the external one)
  2. Install bitwarden and do the following
    a. url for your instance should be with your domain
    b. do not use SSL cert from letsencrypt but rather a self-signed cert ( so that means no for any question asking you about ssl)
    c. in the bwdata config.yml file, remove the port mappings for nginx ( leave them blank)
    d. Start bitwarden

would suggest using portainer if you aren’t at this point…

In portainer, add your external nginx to the docker_default and public network ( created from bw install)

in nginx, when creating the proxy host, use the docker container IP of the bw_nginx container ( its gonna be an internal IP like 172 …) and the port would be 8080

Working perfectly for me. Hope it helps!