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.