Reverse Proxy Benchmark 2025: NPM vs. NPM+ (HTTP/3) vs. Zoraxy

A detailed performance benchmark comparing Nginx Proxy Manager, NPM+ with HTTP/3, and the newcomer Zoraxy. Which reverse proxy is the fastest and easiest for your setup?

Reverse Proxy Benchmark 2025: NPM vs. NPM+ (HTTP/3) vs. Zoraxy hero image

Why Use a Reverse Proxy? The Basics Explained

In the world of home servers and self-hosting, we often juggle numerous applications, each accessible on a different port. Remembering addresses like 192.168.1.10:8080, 192.168.1.10:9000, and 192.168.1.10:3000 is cumbersome and insecure.

This is where a Reverse Proxy comes in. It acts as a central gatekeeper for all incoming requests. Instead of memorizing dozens of ports, we can simply access a subdomain like service.your-domain.com. The reverse proxy receives the request, handles SSL/TLS encryption (the https in the address bar), and forwards it internally to the correct service and port.

In a previous video, I compared several reverse proxies. Today, we’re taking it a step further by putting three modern, visually-oriented contenders through a performance benchmark:

  1. Nginx Proxy Manager (NPM): The popular classic, serving as our stable baseline.
  2. NPM+: A community fork of NPM, where we will specifically enable HTTP/3.
  3. Zoraxy: A new but extremely powerful and modern challenger.

We’ll install all three using Docker and put their performance to the test with the tools wrk and k6.

Glossary: Key Terms and Technologies

TermDescription
DockerA platform for creating and running applications in isolated environments called containers.
Reverse ProxyA server that accepts requests from the internet and forwards them to one or more internal servers.
Nginx Proxy ManagerAn easy-to-use reverse proxy with a graphical user interface (UI), based on Nginx.
NPM+A fork of NPM that offers more modern features, such as HTTP/3 support.
ZoraxyA modern reverse proxy written in Go, designed for high performance and ease of use.
HTTP/3The latest version of the HTTP protocol, based on QUIC, designed to reduce latency, especially on poor networks.
QUICA transport protocol developed by Google that runs on UDP instead of TCP and forms the basis for HTTP/3.
wrkA simple command-line tool for HTTP stress testing, designed for high throughput.
k6A modern, scriptable load testing tool for simulating realistic user behavior under various load scenarios.

The Preparation: Our Test Setup

For a fair comparison, we need a consistent test environment.

1. Installing Server Tools

I am renting four servers from Hetzner. On three of them, I install Docker:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

On the fourth server, I install wrk and k6:

sudo apt install wrk -y
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

Alternatively, this can be done using a Cloud-Init-Config.

2. A Common Network for All Containers

To allow our proxies to communicate with the backend service, we create a common Docker network on each of the three servers.

sudo docker network create proxy

3. The Backend Service: Homepage

As the target service for our proxies, we use the gethomepage/homepage dashboard. It’s lightweight and perfect for our test.

homepage/docker-compose.yml:

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    environment:
      - HOMEPAGE_ALLOWED_HOSTS=your.domain.com # ADJUST HERE
      - PUID=1000
      - PGID=1000
    volumes:
      - ./config:/app/config
    networks:
      - proxy
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

networks:
  proxy:
    external: true

We start this container with sudo docker compose up -d. It has no public port – access is exclusively through our reverse proxies.

The Contenders in Detail

1. Nginx Proxy Manager (NPM)

The classic. Known for its extremely simple, web-based configuration.

npm/docker-compose.yml:

services:
  app:
    image: 'jc21/nginx-proxy-manager:2.12.6'
    container_name: npm
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '81:81'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        
networks:
  proxy:
    external: true

We create the data and letsencrypt folders. After starting with docker compose up -d, we log in at http://<SERVER_IP>:81 and create a proxy host pointing to the homepage service on port 3000. The SSL certificate is automatically obtained via Let’s Encrypt.

2. NPM+ (with HTTP/3)

The modernized version of NPM. The key feature here is enabling HTTP/3.

npm-plus/docker-compose.yml:

services:
  app:
    image: 'ghcr.io/zoeyvid/npmplus:latest'
    container_name: npm-plus
    restart: unless-stopped
    ports:
      - '80:80/tcp'
      - '443:443/tcp'
      - '443:443/udp'
      - '81:81/tcp'
    environment:
      - 'PUID=1000'
      - 'PGID=1000'
      - 'TZ=Europe/Berlin'
      # To enable HTTP/3, you have to enable it in the settings page of the UI
    volumes:
      - ./data:/data
    networks:
      - proxy
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        
networks:
  proxy:
    external: true

The crucial difference is exposing port 443 for UDP. The configuration in the UI is identical to NPM, with an additional toggle in the settings to enable HTTP/3. The login password can be found in the logs: sudo docker compose logs.

3. Zoraxy

A modern challenger written in Go, focusing on performance and a clean UI. HTTP/3 is active by default.

zoraxy/docker-compose.yml:

services:
  zoraxy:
    image: tobiaskoch/zoraxy
    container_name: zoraxy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp" # HTTP/3 is on by default
      - "8000:8000"
    volumes:
      - ./config/:/opt/zoraxy/config/
      - ./plugin/:/opt/zoraxy/plugin/
      - /etc/localtime:/etc/localtime:ro
    networks:
      - proxy
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        
networks:
  proxy:
    external: true

Here, we create the config and plugin folders. After starting, we can access the admin UI at http://<SERVER_IP>:8000. Setting up a proxy host is just a few clicks away.

The Benchmark: The Results

I conducted two tests from the fourth server:

  1. wrk: A raw stress test with 100 concurrent connections for 1 minute to measure maximum throughput (version 4.1.0).
  2. k6: A dynamic scenario that slowly ramps up the load, holds it, and simulates load spikes to test realistic behavior (version 1.1.0).

wrk Results: Raw Power

wrk -t4 -c100 -d60s --latency your.domain.com

MetricNginx Proxy ManagerNPM+ (with HTTP/3)Zoraxy
Requests/Second91102155
Average Latency287 ms245 ms77 ms
p99 Latency605 ms413 ms263 ms
Errors (Timeouts)00701 (0.02%)

The wrk results are clear: Zoraxy is in a league of its own in terms of speed. It handles 50% more requests than Nginx Proxy Manager at a fraction of the latency. BUT: under this extreme, continuous fire, Zoraxy started to drop requests (701 timeouts). NPM and NPM+ remained perfectly stable.

k6 Results: Realistic Scenario

// The k6 script used for testing
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 50 },    // Phase 1: Ramp-up
    { duration: '1m', target: 50 },     // Phase 2: Soak
    { duration: '30s', target: 200 },   // Phase 3: Stress
    { duration: '1m', target: 200 },    // Phase 4: Soak
    { duration: '30s', target: 0 },      // Phase 5: Ramp-down
  ],
  thresholds: {
    'http_req_duration': ['p(95)<800'],
    'http_req_failed': ['rate<0.01'],
    'checks': ['rate>0.99'],
  },
};
// ... rest of the script ...
MetricNPMNPM+Zoraxy
Total Requests22,42922,27822,460
Response Time p(95)13.1 ms27.6 ms10.7 ms
Error Rate0%0%0%

The dynamic k6 test paints a different picture. Here, all three contenders are perfectly stable and deliver error-free results. Zoraxy is again the fastest, closely followed by the classic NPM. NPM+ shows a slight performance overhead, likely due to the enabled HTTP/3 processing for the test tool’s HTTP/1.1 requests.

Final Verdict and Recommendation

So, which reverse proxy should you choose? It depends on your priorities.

  • For Beginners and Stability Fans: Nginx Proxy Manager
    It’s the rock-solid choice. Incredibly easy to use and absolutely reliable in every scenario. The perfect, worry-free option.

  • For the Modern All-Rounder: NPM+
    The ideal evolution. You get a familiar UI and modern features like HTTP/3 that can be enabled with a single click. The best compromise between stability, features, and ease of use.

  • For Performance Hunters: Zoraxy
    The k6 test proved that Zoraxy is also perfectly stable in realistic scenarios. Its potential is undeniable, making it a contender you should definitely keep an eye on.

FAQs

What exactly is a reverse proxy?

A reverse proxy is a server that acts as a central entry point for requests to your internal services. It distributes requests, manages SSL certificates, and enhances security by shielding your backend services from direct internet access.

Why should I use Docker for installation?

Docker greatly simplifies installation and management. Each service runs in an isolated container with all its dependencies. This ensures a clean, reproducible, and portable setup that doesn't alter your host system.

What are the real-world benefits of HTTP/3?

HTTP/3, based on QUIC, can noticeably improve website loading times, especially over poor or fluctuating internet connections (like mobile networks). It reduces connection setup overhead and is more resilient to packet loss.

Is Zoraxy unstable because of the errors in the wrk test?

Not necessarily. The wrk test simulates an extreme scenario of constant, high-pressure requests. It handled more requests than the Nginx Proxy Managers. In the more realistic, dynamic k6 test, Zoraxy was 100% stable.

Can I run these reverse proxies on a Synology NAS or Raspberry Pi?

Yes, absolutely. As long as Docker is running on the device, all three contenders can be installed. On less powerful devices (like an older Raspberry Pi), the performance differences might be even more pronounced. For ARM-based devices (like the Raspberry Pi), make sure you use ARM-compatible Docker images.

Share this post:

This website uses cookies. These are necessary for the functionality of the website. You can find more information in the privacy policy