A reverse proxy acts as a middleman between clients and servers, forwarding client requests to servers and returning the servers' responses back to clients. They are often used to load balance traffic, terminate SSL and stream-line security configurations for multiple services.
There are many software options to choose from in order to set up a reverse proxy, including NGINX, Openresty, Caddy, HAProxy, Traefik and many more. NGINX is a popular open-source reverse proxy that is known for its high performance and reliability. Traefik is another open-source reverse proxy that is gaining popularity due to its support for dynamic configurations as well as the ability to discover new containerized services to automatically proxy to.
Both reverse proxies are popular choices to proxy traffic and support the following common core features:
- Automatic management of SSL/TLS certificates as well as renewal. Both reverse proxies support a wide range of providers.
- Proxying various protocols such as HTTP, HTTPS, TCP and UDP. NPM uses NGINX Streams to forward TCP and UDP traffic.
- Providing a web-based management interface.
Nonetheless, there are a few key differences that should be outlined:
- Nginx Proxy Manager provides a web-based GUI that allows users to easily manage and configure the reverse proxy. It provides a user-friendly web interface for creating and managing proxy hosts, as well as managing SSL/TLS certificates and access controls. Although Traefik also provides a web-based GUI, the management UI is rather used to inspect the currently active configuration instead of actively configuring or adjusting things. The configuration is done in configuration files or via docker labels instead.
- Nginx Proxy Manager supports multiple user accounts, roles and audit logs. The reverse proxy can therefore be managed or inspected by different users and access roles. The audit logs can help to track down who made what changes. Traefik does not support multiple user accounts, roles or audit logs. The web-based management UI can be accessed without authentication per default.
- Nginx Proxy Manager stores its configuration for proxy hosts, users etc. in a database. Supported are SQLite and MariaDB/MySQL. Traefik on the other hand does not require a database. Its configuration is defined as code (yml files) and proxy host configurations are applied during runtime and persist in-memory. Therefore, Traefik is less prone to database corruption and a potential downtime.
- Nginx Proxy Manager allows users to proxy to a single host. Therefore, load balancing is not natively supported by the web-based management GUI. Traefik instead supports load balancing natively via its configuration options.
- Since NPM uses Openresty under the hood, an improved NGINX, reverse proxying completely fails as soon as one proxy host configuration is falsely defined. This for example happens, if your NPM docker instance cannot reach a hostname or IP address that was configured as proxy host via the web-based management UI. Alternatively, if e.g. an SSL certificate file is actively referenced but not available or accessible. If this occurs, the NGINX service won't start correctly and all your proxy hosts are inaccessible. Furthermore, the NPM management web UI to fix things will also be unresponsive until the problem is fixed. You end up having a non-operational reverse proxy. Traefik instead will fail for a single proxy host only and the management web UI to inspect things will still stay up. All other proxy hosts will remain working and are not affected by a single proxy host misconfiguration. Since there is no database to maintain, you run less risk of bricking Traefik as reverse proxy.
The following section will focus on setting up both reverse proxies as docker container. Since both containers will bind the required ports TCP/80 and TCP/443 to the docker host system, it is not possible to run them in parallel. If you want to do so, please adjust the port mappings.
Setup of Nginx Proxy Manager
docker-compose.yml file can be used to spawn up a dockerized NPM instance. By using bind volume mounts, we ensure that our upcoming user and proxy configurations will be persistently stored on disk. Therefore, our configuration and issued SSL certificates will persist even when the container is restarted or re-deployed.
For NPM to work, we should first create a new docker network:
docker network create npm_proxy
After adjusting the above configuration file, we can spawn up our instance of NPM by issuing the following bash command on our server:
The NPM management web UI should then be availabe on TCP/81. Just open a web browser of your choice and browse to
[email protected]for the username and
changemefor the initial password. You are tasked to change those default credentials during first login.
Setup of Traefik
docker-compose.yml file can be used to spawn up a dockerized Traefik instance. By using bind volume mounts, we ensure that our upcoming configuration files will be persistently stored on disk. Therefore, our configuration and issued SSL certificates will persist even when the container is restarted or re-deployed.
For Traefik to work, we should first create a new docker network:
After adjusting the above configuration file, we may spawn up our instance of Traefik by issuing the following bash command on our server:
docker compose up -d
The Traefik management web GUI should then be availabe on TCP/8080. Just open a web browser of your choice and browse to
http://<your-server-ip>:8080. Since we have not yet configured any proxy hosts, Traefik's default configuration will be applied and the web dashboard will list default things only.
During first startup, our defined bind volume at
/docker-compose/traefik/ should contain an example configuration file
traefik.yml by now. In order to use Traefik, we have to adjust this default configuration file as well as setup another file for dynamic configurations.
Let's adjust or create the following files at the volume bind mentioned above.
traefik.ymlconfiguration file will redirect incoming, unencrypted HTTP traffic automatically to HTTPS. Furthermore, Cloudflare is used to obtain SSL certificates and a default middleware is enabled to set various recommended HTTP response headers for all upcoming proxy hosts. Finally, docker is defined as provider and containers are not exposed by default.
Furthermore, create a file called
fileConfig.yml, which will reflect our dynamic configuration definitions.
fileConfig.ymlconfiguration file defines a hardened SSL/TLS configuration by using strong algorithms and cipher suites only. Furthermore, it defines the aforementioned middleware
securityHeadersto set various recommended HTTP response headers for security.
Finally, we also defined a new middleware called
local-ipwhitelist, which can be later used to restrict access to proxied services by validating whether the request originated from local lan only.
This configuration file allows for dynamic changes during runtime. Traefik will notice changes and will apply them without the need of a container restart.
Creating our first proxy host
The following section will guide you through the process of defining our first proxy host. For NPM, we will use the provided management web-interface. For Traefik, we will use the configuration files and docker labels.
Proxy Host in Nginx Proxy Manager
A new proxy configuration can be defined by using the provided management web GUI on TCP/81. After logging into the web mgmt ui, we are greeted by various application areas such as
ssl certificates and many more.
The user interface is fairly intuitive and prompts for required input data such as your domain name, IP address or hostname and the port of your proxied service etc.
To create a new proxy host entry, go to
Hosts > Proxy Hosts > Add Proxy Host. Insert your domain name and the IP address or hostname of your web service you want to proxy. If the NPM docker container runs in the same docker network as your to be proxied web service, you can neglect specifying an IP address. You can directly define the docker container name (e.g.
nginx) and port (e.g.
80) of the docker container providing your web service to be proxied by NPM. Let's assume we want to proxy to a running nginx docker container:
Proxy Host in Traefik
Creating a new proxy host in Traefik is done differently then for Nginx Proxy Manager. While both reverse proxies provide a management web ui, only NPM allows you to actively create, modify and adjust all settings via the web GUI.
Traefik instead provides a management web UI solely to inspect your active configuration. The actual proxy configuration is done separately by either adjusting the configuration files or using labels for your to be proxied docker containers. We will use the latter option and define various labels to our example web service to proxy to.
Let's assume we want to proxy to an NGINX docker container. Our NGINX container is defined by the below
docker-compose.yml. We will append a few Traefik labels before spawning up the container. These labels are automatically read and applied by the Traefik reverse proxy during runtime.
Labels define various things such as the subdomain our newly proxied web service will be accessible (
traefik.http.routers.nginx.rule) as well as on which port the Traefik reverse proxy should forward client requests to (
traefik.http.services.nginx.loadbalancer.server.port). With labels we can also enable additional middlewares or specify the docker network of our container.
version: "3" services: web: image: nginx:latest hostname: nginx container_name: nginx restart: unless-stopped networks: - npm_proxy - proxy labels: - traefik.enable=true - traefik.http.routers.nginx.rule=Host(`myfirstproxyhost.example.com`) - traefik.http.services.nginx.loadbalancer.server.port=80 # - traefik.docker.network=nginx_default # Part for local lan services only # - traefik.http.routers.nginx.middlewares=local-ipwhitelist@file networks: proxy: external: true npm_proxy: external: true
After spawning up this NGINX docker container by
docker compose up -d, Traefik will automatically pick up the labels and create a new proxy host.
proxyas the Traefik container (or vice versa). Otherwise, the NGINX web service on port 80 may not be accessible by Traefik and proxying fails.
If everything went correctly, you should be able to see a new proxy host in Traefik's management web ui. Traefik will automatically obtain the NGINX container's docker IP address and proxy client requests to the defined container port TCP/80. If your DNS setup and/or port forwardings work, you should now be able to access your NGINX web service by browsing to
https://myfirstproxyhost.example.com, as defined within the above docker labels.
Traefik is known to be slower than NGINX. However, I wanted to conduct a small performance test between Nginx Proxy Manager and Traefik. We will use the container image
openspeedtest to inspect, which reverse proxy provides faster speeds. We will benchmark the reverse proxies from the same client machine connected to the Internet and my server via Wi-Fi.
docker-compose.yml file for openspeedtest was used:
The raw performance of the openspeedtest docker container via unencrypted HTTP on TCP/3000 without using a reverse proxy at all looks like this:
Performance of Traefik
The Traefik reverse proxy will pick up and define the openspeedtest proxy host by applying our labels in the above
docker-compose.yml file. We will terminate SSL at the reverse proxy and forward client requests to the unencrypted HTTP service on TCP/3000 of the openspeedtest container.
Afterwards, we can just browse to the subdomain and issue a speed test. Here an example result:
Performance of NPM
Nginx Proxy Manager as reverse proxy requires a manual proxy host setup. We will enable SSL and specify our subdomain. No caching, no compression. SSL will also be terminated at the NPM reverse proxy and client requests are forwarded to the unencrypted HTTP service on TCP/3000 of the openspeedtest container.
Afterwards, we can just browse to the subdomain and issue a speed test. Here an example result:
I have conducted the openspeedtest benchmark multiple times in a short period of time and noted the results in Excel. In average, Traefik as reverse proxy seems to be indeed slower than Nginx Proxy Manager, which uses Openresty under the hood.
However, the differences may be considered small and neglectable for a reverse proxy solely used in homelabs. However, for larger infrastructures or scaled services, the performance differences may have a bigger impact and must be considered.
I would recommend Traefik as reverse proxy in the following cases:
- You are an experienced, technical user and don't mind a steep learning curve. You like reading documentation and having various different configuration options to choose from.
- You prefer the autodiscover feature of Traefik to detect new containerized services and create proxy hosts automatically for you.
- You prefer infrastructure as code over configuring things via a web interface or GUI.
- You want to circumvent the need and backup of a database for your reverse proxy.
- You require native support for load balancing.
- You like the support for dynamic configurations without having to restart your reverse proxy.
- You want support for additional plugins like fail2ban, crowdsec, modsecurity, caching or geo blocking.
- You want to implement an authentication provider like Authentik, Authelia etc. within your reverse proxy for Single-Sign-On (SSO). The setup should be well documented and supported by the reverse proxy, without having to find GitHub issues and implement unofficial configurations.
- You proxy to containerized services solely (Docker, Kubernetes etc.), running on the same server or network stack. You only have a few external IP:Port proxy hosts that will require a manual Traefik configuration.
- You don't mind the decreased performance of Traefik over NGINX.
I would recommend Nginx Proxy Manager as reverse proxy in the following cases:
- You are a beginner and want to get things done quickly. No time for reading a lot of documentation and testing out various different configuration options.
- You prefer an intuitive management web UI to configure things instead of crafting configuration files and your whole proxy infrastructure as code.
- You do not require support for various authentication providers like Authentik or Authelia for Single-Sign-On (SSO).
- You require support for audit logs to be able to tell which user made what changes.
- You do not require native support for load balancing.
- You want to proxy to services not solely running on the same server or being containerized. You want to be able to just specify an IP address and a port to create a new proxy host.
- You require the improved performance of NGINX over Traefik.