Guide to setting up Bitwarden behind an OPNsense + nginx plugin Reverse Proxy

Guide to routing to your Bitwarden Server via the OPNsense nginx plugin

This guide, similarly to our other guides for regular nginx reverse proxies and Apache2, is aimed at providing an example configuration to get users up and running. In particular, the GUI of the OPNsense nginx plugin can be tricky to get used to for users accustomed to writing nginx config files manually.

Overview

We have provided an overview of a reverse proxy setup in our previous guide, which goes into fundamentals such as the purpose of a reverse-proxy, as well as the layout of the various components. Please review that guide if you are not already familiar with the concept.

In this guide, we will dive straight into the details, explaining:

  • certificate management via OPNsense
  • nginx configuration via OPNsense’s nginx plugin
  • ensuring that real-IPs are correctly passed through to your backend server

Certificate Management in OPNsense

When configuring a reverse proxy, TLS termination should be performed on the reverse proxy, and not on the Bitwarden server. When using OPNsense, numerous options to obtain and configure these are available, but perhaps the most popular is the ACME Client, available via System → Firmware → Plugins → os-acme-client.

Once installed, the ACME Client menu will become available under Services → ACME Client, and you will be able to obtain clients from a variety of CAs. While obtaining certificates using the ACME Client plugin is not in the scope of this guide, to give a brief overview you will need to provide:

  • an account with a CA (e.g. LetsEncrypt)
  • a challenge type (e.g. Cloudflare DNS Challenge)
  • details of a certificate to be obtained (e.g. vault.yourdomain.com)

Once the certificate has been obtained, this will be available to the nginx plugin’s GUI.

nginx plugin in OPNsense

The nginx plugin also does not come installed in OPNsense by default, and should again be installed via System → Firmware → Plugins → os-nginx

Once installed, the nginx configuration can be managed via Services → nginx

nginx configuration

The nginx plugin will need configuring in several different places, similar to how when defining a config manually you would define /location, /server and /http blocks, amongst others. We will now show an example configuration for a Bitwarden server running at 192.168.242.200, where the nginx plugin is available on a Virtual Interface in OPNsense with the IP 192.168.242.1

Note that in many of the configuration menus detailed below, additional settings will be available, offering e.g. integration with ACLs, Firewalls and other features offered by Nginx. While the availability of simple integrations for these features into a Bitwarden deployment is certainly part of the attraction of using OPNsense as a reverse proxy, the configuration of these features is beyond the scope of this guide. As such, only the core settings required for a functional Bitwarden service have been provided below.

HTTP(s) → Location

The default sub-menu shown when clicking the HTTP(s) button is Location, corresponding to the Location block in a standard nginx config:

For Bitwarden, this should be set as follows:

Setting Value Notes
Decription Bitwarden Display name only
URL Pattern /
Match Type None
URL Rewriting Nothing Selected
Upstream Servers Bitwarden We will define the detail of the Upstream Server later
Cache: Directory None
Force HTTPS Disabled

HTTP(s) → HTTP Server

From the HTTP(s) menu, select the HTTP Server submenu:

Here, the following values should be set:

Setting Value Notes
HTTP Listen Address (Leave Blank) Bitwarden requires HTTPS communication
HTTPS Listen Address 443
Default Server (Ticked)
Server Name vault.your.domain This should match the server name in your config.yml
Locations Bitwarden This refers back to the Location block set above
URL Rewriting Nothing selected
TLS Certificate vault.your.domain This is obtained va the ACME client plugin
Client CA Certificate None
Access Log Format Default These logs are available via the OPNsense GUI. For more advanced monitoring possibilities consider setting a different value and providing an appropriate backend.
Enable Let’s Encrypt Plugin Support Ticked
Charset utf-8
HTTPS Only Ticked
Security Header None

Upstream → Upstream Server

This is where we define the backend server that Bitwarden will be hosted from, i.e. the IP address of the VM running the Bitwarden containers:

The configuration here is fairly straightforward:

Setting Value Notes
Description Bitwarden-443 This is a display name only
Server (Your server’s IP address)
Port 443
Server priority 1

Upstream → Upstream

Finally, this is where the Upstream service, consisting of the servers belonging to the backend, is defined:

As this is a single Bitwarden server, this is also a simple configuration:

Setting Value Notes
Description Bitwarden (Display name only)
Server Entries Bitwarden-443 This is set in the the Upstream menu above
Enable TLS (HTTPS) Ticked
TLS: Supported Versions TLSv1.2, TLSv1.3 Versions lower than TLSv1.2 have been deprecated

Configuring the Bitwarden server to display Real-IPs

Bitwarden offers a few services where the end-user IP address is passed through to the Bitwarden server. These include:

  • nginx access and error logs (/bwdata/logs/nginx)
  • ‘New Device Logged in emails’
  • Event Logs

When Bitwarden is directly accessed (i.e., connections from the Internet / an internal network directly hit the Bitwarden nginx container), the correct IPv4/v6 of the end-user will be passed through, as the Bitwarden nginx container comes pre-configured.

If Bitwarden is not directly accessed (i.e., access is first made to a the OPNsense nginx plugin described in this article, which then proxies the connection onto the Bitwarden nginx container), then without special configuration the IP address of this proxy service will be logged.

The technology responsible for changing the client address is the ngx_http_realip_module. This is included by default in the nginx version provided by OPNsense, so no additional configuration needs to be made on the OPNsense server.

Instead, the set_real_ip_from directive needs to be set in the Bitwarden nginx container - this is achieved by setting this in the config.yml file, and performing a rebuild and then a restart.

The correct syntax for the way that the setup container parses the config.yml is provided below:

Set real_ips to a Single IP

When setting a single IP, the IP should be set using the -'d indent on the line below the real_ips: variable, e.g.:

# real_ips: ['10.10.0.0/24', '172.16.0.0/16']
real_ips:
- 192.168.25.15/32

Set real_ips to a dictionary of values

When setting a dictionary (as suggested by the config.yml’s internal documentation), then the dictionary should be placed on the same line, e.g.:

# real_ips: ['10.10.0.0/24', '172.16.0.0/16']
real_ips:['192.168.25.15/32', '192.168.25.42/32']

After running the rebuild command, the IPs will have been parsed onto multiple lines, e.g.:

# real_ips: ['10.10.0.0/24', '172.16.0.0/16']
real_ips:
- 192.168.25.15/32
- 192.168.25.42/32

Checking the configuration inside the nginx container

The configuration can be checked from the Bitwarden server via:

docker exec bitwarden-nginx cat /etc/nginx/conf.d/default.conf | grep 'set_real' -A3

real_ip_recursive is set to on in the Bitwarden installed nginx container. This allows for the use of a chain of reverse proxies if they are all correctly configured. Doing so is again beyond the scope of this article.

1 Like