Leveraging Reverse Proxying
This part of the guide has been updated as a standalone article here
In this article, we will:
- Place portainer, cockpit and nginx proxy manager (well at least the admin interface) behind the reverse proxy for ssl termination/ip whitelisting on all our admin interfaces.
Leveraging the Reverse Proxy
Now we can do something cool. With all of our services in the reverse proxy network, we can now get our management interfaces protected! Even the reverse proxy! This is fantastic as it allows us to tunnel all of our admin interfaces behind validated SSL and protect them with IP whitelisting.
Let’s make 3 more subdomains in our DNS:
<your-docker-host>.<your-domain>.<tld>(this guide uses
cbdocker02as it’s hostname)
in OPNsense, since they’re all the same IP we can do so using aliases
- In the Nginx Proxy Manager, create a proxy host to
npm.<your-domain>.<tld>on http, pointing to
81. Set the access list to
local subnets(management interfaces should not be exposed to the web, except with great discretion).
- Under SSL, set your wildcard SSL certificate (or generate a new let’s encrypt certificate). Press save.
- Now let’s do it all again for
portainer.<yourdomain>.<tld>note the fact that we’re proxying to an https endpoint this time.
- Also add or generate your SSL certificate and save.
- Same thing for
<your-host>.<your-domain>.<tld>for cockpit (on port 9090).
Note that we are reverse proxying to the same domain address (since it should resolve back to our host IP). We are also setting the Scheme to HTTPS, same as portainer.
- Don’t forget the SSL
Putting Portainer on the Reverse Proxy
Oops, we missed a step. Even though we are reverse proxying to portainer, portainer isn’t on the same network! Let’s fix that. in cockpit, navigate to
/mnt/containers/portainer and update the
docker-compose.yaml. Let’s comment out the port exposure at the same time:
services: portainer: image: portainer/portainer-ce:latest container_name: portainer restart: always privileged: true volumes: - /mnt/containers/portainer/container-data/data:/data:Z - /var/run/docker.sock:/var/run/docker.sock:Z # ports: # - 9443:9443 networks: - reverseproxy-nw networks: reverseproxy-nw: external: true
You can see me do that below using mc and micro:
At the start of the animation, you can see me uncheck use internal editor. This tells mc to default to micro as the editor.
Testing our Setup
Let’s now verify that you can access
https://npm.<yourdomain>.<tld>. You can see me do that in the animation below:
Success! We are now proxying all of our web admin interfaces behind nginx proxy manager, and restricting those interfaces to local IPs.
The eagle eyed of you may notice the ‘login with oauth’ prompt for portainer. I may have been reading a bit ahead when creating this animation. We’ll get there!
Removing the Port Exposures
Now log into portainer, and comment out the port exposure for nginx-proxy-manager. Now our only method of accessing the nginx-proxy-manager admin portal and portainer is through the reverse proxy.
Note that we did not comment out the port exposure for cockpit. This is because if we screw up the reverse proxy, we want a way to get back into our host on port 9090. This is referred to as an out of band access method.
Always. Be. ~~Hustling~~ Documenting.
Update gitea to reflect our updated nginx proxy manager configuration:
Alright, we are making good progress. We have most of the tools we need to create a stable, secure docker environment.
One critical part is missing though. We aren’t backing up our data! We need backups. Let’s address that with Backups up Docker.