DEV Community

Cover image for Why I Run Nginx on My OpenWrt Router (And How You Can Too)
Natsuki
Natsuki

Posted on • Originally published at blog.natsuki-cloud.dev on

Why I Run Nginx on My OpenWrt Router (And How You Can Too)

TL;DR

Your router already handles all network traffic. Why not let it handle reverse proxying too? Running nginx on OpenWrt eliminates an extra hop, simplifies your network architecture, and gives you a single point of SSL termination. This post covers why OpenWrt is the right choice, what nginx actually does, and how to configure it using OpenWrt’s UCI system to proxy 25+ homelab services with clean subdomain URLs.

📦 This nginx setup runs on my DeskPi 12U homelab in a 10sqm Tokyo apartment. See the full setup: Small But Mighty Homelab: DeskPi 12U Running 20+ Services.

Contents:

  1. Why OpenWrt?
  2. What is Nginx and Why Do You Need It?
  3. Why Run Nginx on Your Router?
  4. Installing Nginx on OpenWrt
  5. Understanding OpenWrt’s UCI Configuration
  6. Setting Up Wildcard SSL Certificates
  7. Adding Your First Service
  8. DNS Configuration with dnsmasq
  9. Real Example: 25 Services Proxied Through One Router
  10. Tips and Considerations

1. Why OpenWrt?

Before diving into nginx, let’s talk about why OpenWrt is the foundation that makes this setup possible.

OpenWrt is a Linux distribution designed for embedded devices, primarily routers. Unlike the locked-down firmware that comes with consumer routers, OpenWrt gives you a full Linux system with:

  • Package management : Install what you need, remove what you don’t
  • SSH access : Full command-line control over your network
  • Customizable firewall : iptables/nftables with granular control
  • Real services : Run nginx, wireguard (for remote access to your homelab), adblock, and more natively

Most consumer router firmware is a black box. You get a web UI with limited options and no way to extend functionality. OpenWrt turns your router into a proper Linux server that happens to also route packets.

Hardware Matters

Not all routers can run OpenWrt well. You need:

  • Sufficient RAM : 256MB minimum, 512MB+ recommended for nginx
  • Storage : Internal flash or USB storage for configs
  • CPU : Modern ARM or MIPS processors handle nginx easily

Check the OpenWrt Table of Hardware to see if your router is supported.

I’m running the OpenWrt One - a router specifically designed for OpenWrt with 1GB RAM and 256MB NAND storage. It runs nginx with 25+ reverse proxy configurations without breaking a sweat.

2. What is Nginx and Why Do You Need It?

Nginx (pronounced “engine-x”) is a high-performance web server and reverse proxy. In a homelab context, you’ll primarily use it as a reverse proxy - a server that sits between your clients and your backend services.

The Problem Nginx Solves

Without a reverse proxy, accessing your homelab services looks like this:

  • Grafana: http://192.168.1.201:3000
  • Home Assistant: http://192.168.1.213:8123
  • Jellyfin: http://192.168.1.201:8096

This approach has several issues:

  1. Memorizing IPs and ports is tedious
  2. No HTTPS means credentials sent in plaintext
  3. Port conflicts when services want the same port
  4. No centralized access control

With nginx as a reverse proxy:

  • Grafana: https://grafana.raspberrypi.home
  • Home Assistant: https://homeassistant.raspberrypi.home
  • Jellyfin: https://jellyfin.raspberrypi.home

How Reverse Proxying Works

Reverse_Proxy_Diagram

  1. Client requests https://grafana.raspberrypi.home
  2. DNS resolves to your router’s IP (192.168.1.1)
  3. Nginx receives the request, terminates SSL
  4. Nginx looks at the hostname (SNI), routes to the correct backend
  5. Backend responds, nginx forwards response to client

The key insight: nginx uses the hostname (Server Name Indication) to route traffic. All services share ports 80/443, but nginx routes based on which subdomain you’re requesting.

3. Why Run Nginx on Your Router?

You could run nginx anywhere - a Raspberry Pi, a VM, a Docker container. So why specifically on the router?

Elimination of Extra Hops

Every network request already goes through your router. If nginx runs on a separate machine, you add an extra hop:

Routing_Diagram

One less hop means lower latency, less routing rules, and one less point of failure.

Single Point of Configuration

Your router already manages:

  • DHCP (IP assignments)
  • DNS (name resolution via dnsmasq)
  • Firewall rules

Adding reverse proxying to this list keeps all network configuration in one place. When you add a new service, you configure the DNS entry and nginx proxy in the same system.

Always-On Guarantee

Your router is the one device that’s always running. If it’s down, you have no network anyway. Running nginx on the router means your reverse proxy has the same uptime as your network itself.

Resource Efficiency

Modern routers have more than enough power for reverse proxying. Nginx is extremely lightweight - it was designed to handle thousands of concurrent connections on minimal hardware. My OpenWrt One barely notices the 25 proxy configurations:

 total used free shared buff/cache available
Mem: 1011248 163144 241180 505676 606924 291924

Enter fullscreen mode Exit fullscreen mode

Less than 200MB used with nginx, dnsmasq, and all other services running.

4. Installing Nginx on OpenWrt

SSH into your router and install nginx:

opkg update
opkg install nginx-ssl

Enter fullscreen mode Exit fullscreen mode

The nginx-ssl package includes SSL/TLS support. Without it, you can only proxy HTTP.

Enable and start the service:

/etc/init.d/nginx enable
/etc/init.d/nginx start

Enter fullscreen mode Exit fullscreen mode

Verify it’s running:

nginx -v
# nginx version: nginx/1.26.1 (x86_64-pc-linux-gnu)

Enter fullscreen mode Exit fullscreen mode

5. Understanding OpenWrt’s UCI Configuration

OpenWrt uses UCI (Unified Configuration Interface) to manage all system configuration, including nginx. Instead of editing nginx config files directly, you define settings through UCI and OpenWrt generates the actual nginx config at /var/lib/nginx/uci.conf on each restart.

Nginx configuration on OpenWrt has two parts:

  1. Server blocks (via UCI) - Define which subdomain to listen for and which SSL certificate to use
  2. Location files (plain nginx config) - Define where to proxy the traffic

Part 1: Server Block (UCI)

A server block tells nginx: “When someone requests this subdomain, use this SSL certificate and look at this location file for routing rules.”

uci set nginx.srv_grafana=server
uci set nginx.srv_grafana.uci_enable='true'
uci set nginx.srv_grafana.server_name='grafana.raspberrypi.home'
uci set nginx.srv_grafana.include='conf.d/grafana.locations'
uci set nginx.srv_grafana.ssl_certificate='/etc/nginx/ssl/wildcard.raspberrypi.home.crt'
uci set nginx.srv_grafana.ssl_certificate_key='/etc/nginx/ssl/wildcard.raspberrypi.home.key'
uci add_list nginx.srv_grafana.listen='443 ssl'
uci add_list nginx.srv_grafana.listen='[::]:443 ssl'
uci set nginx.srv_grafana.ssl_session_cache='shared:SSL:32k'
uci set nginx.srv_grafana.ssl_session_timeout='64m'
uci commit nginx
/etc/init.d/nginx restart

Enter fullscreen mode Exit fullscreen mode

The key line is server_name - this enables SNI (Server Name Indication). When a client connects to port 443 and says “I want grafana.raspberrypi.home”, nginx matches it to this server block.

Part 2: Location File

The location file tells nginx where to actually send the traffic. Create /etc/nginx/conf.d/grafana.locations:

location / {
 proxy_pass http://192.168.1.201:3000;
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection "upgrade";
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
}

Enter fullscreen mode Exit fullscreen mode
  • proxy_pass - The backend server address and port
  • Upgrade / Connection - Enable WebSocket support
  • X-Real-IP / X-Forwarded-For - Pass the client’s real IP to the backend
  • X-Forwarded-Proto - Tell the backend the original request was HTTPS

6. Setting Up Wildcard SSL Certificates

Instead of managing certificates for each subdomain, use a wildcard certificate that covers *.raspberrypi.home.

Generating a Self-Signed Wildcard Certificate

On your router or any Linux machine with OpenSSL:

# Generate private key
openssl genrsa -out wildcard.raspberrypi.home.key 2048

# Generate certificate signing request
openssl req -new -key wildcard.raspberrypi.home.key \
 -out wildcard.raspberrypi.home.csr \
 -subj "/CN=*.raspberrypi.home"

# Generate self-signed certificate (valid for 10 years)
openssl x509 -req -days 3650 \
 -in wildcard.raspberrypi.home.csr \
 -signkey wildcard.raspberrypi.home.key \
 -out wildcard.raspberrypi.home.crt

Enter fullscreen mode Exit fullscreen mode

Place the files in /etc/nginx/ssl/:

mkdir -p /etc/nginx/ssl
mv wildcard.raspberrypi.home.* /etc/nginx/ssl/
chmod 600 /etc/nginx/ssl/*.key

Enter fullscreen mode Exit fullscreen mode

Browser Trust

Self-signed certificates will show browser warnings until you install them. Import wildcard.raspberrypi.home.crt into your browser or OS trust store to make the warnings go away. On most systems, double-clicking the certificate file will open an import wizard.

Accessing Grafana via clean subdomain URL with HTTPS

7. Adding Your First Service

Let’s add a complete example for Home Assistant:

Step 1: Create the Location File

Create /etc/nginx/conf.d/homeassistant.locations:

location / {
 proxy_pass http://192.168.1.213:8123;
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection "upgrade";
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;

 # Home Assistant specific settings
 proxy_buffering off;
 proxy_request_buffering off;
 chunked_transfer_encoding on;
 tcp_nodelay on;
 proxy_read_timeout 3600s; # Long timeout for WebSocket connections
}

Enter fullscreen mode Exit fullscreen mode

Home Assistant uses WebSockets heavily, so we disable buffering and set a long read timeout.

Step 2: Add UCI Configuration


uci set nginx.srv_homeassistant=server
uci set nginx.srv_homeassistant.uci_enable='true'
uci set nginx.srv_homeassistant.server_name='homeassistant.raspberrypi.home'
uci set nginx.srv_homeassistant.include='conf.d/homeassistant.locations'
uci set nginx.srv_homeassistant.ssl_certificate='/etc/nginx/ssl/wildcard.raspberrypi.home.crt'
uci set nginx.srv_homeassistant.ssl_certificate_key='/etc/nginx/ssl/wildcard.raspberrypi.home.key'
uci add_list nginx.srv_homeassistant.listen='443 ssl'
uci add_list nginx.srv_homeassistant.listen='[::]:443 ssl'
uci set nginx.srv_homeassistant.ssl_session_cache='shared:SSL:32k'
uci set nginx.srv_homeassistant.ssl_session_timeout='64m'
uci commit nginx
/etc/init.d/nginx restart

Enter fullscreen mode Exit fullscreen mode

Step 3: Verify

Check nginx configuration is valid:

nginx -t

Enter fullscreen mode Exit fullscreen mode

8. DNS Configuration with dnsmasq

For subdomains to resolve to your router, configure dnsmasq (OpenWrt’s built-in DNS server).

Wildcard DNS Entry

The cleanest approach is a wildcard entry that routes all *.raspberrypi.home to your router:

uci set dhcp.@dnsmasq[0].domain='raspberrypi.home'
uci add dhcp domain
uci set dhcp.@domain[-1].name='raspberrypi.home'
uci set dhcp.@domain[-1].ip='192.168.1.1'
uci commit dhcp
/etc/init.d/dnsmasq restart

Enter fullscreen mode Exit fullscreen mode

Now any *.raspberrypi.home request resolves to 192.168.1.1, where nginx handles routing based on the subdomain.

Testing DNS Resolution

From any device on your network:

nslookup grafana.raspberrypi.home
# Should return 192.168.1.1

nslookup anything.raspberrypi.home
# Also returns 192.168.1.1

Enter fullscreen mode Exit fullscreen mode

9. Real Example: 25 Services Proxied Through One Router

Here’s my actual setup - services running across Raspberry Pis, an N305 mini PC, and other devices, all proxied through the OpenWrt One. Every service accessible via clean subdomain URLs with HTTPS:

Homer dashboard with all services accessible via subdomains

Service Subdomain Backend
Homer (Dashboard) homer.raspberrypi.home 192.168.1.201:8080
Grafana grafana.raspberrypi.home 192.168.1.201:3000
Prometheus prometheus.raspberrypi.home 192.168.1.201:9090
Home Assistant homeassistant.raspberrypi.home 192.168.1.213:8123
Jellyfin jellyfin.raspberrypi.home 192.168.1.201:8096
Portainer portainer.raspberrypi.home 192.168.1.201:9000
Bitwarden bitwarden.raspberrypi.home 192.168.1.201:8081
qBittorrent qbittorrent.raspberrypi.home 192.168.1.201:8090
Komga komga.raspberrypi.home 192.168.1.201:8082
Uptime Kuma uptimekuma.raspberrypi.home 192.168.1.201:3001
Syncthing syncthing.raspberrypi.home 192.168.1.201:8384
Guacamole guacamole.raspberrypi.home 192.168.1.201:8083
PiKVM pikvm.raspberrypi.home 192.168.1.100:443
OctoPrint octopi.raspberrypi.home 192.168.1.101:80

Every service is accessed through https://servicename.raspberrypi.home on port 443. You don’t need to remember different port numbers - nginx reads the subdomain from the URL and forwards your request to the correct backend service internally.

10. Tips and Considerations

Logging

OpenWrt centralizes all logs through logread. To view nginx logs:

logread | grep nginx

Enter fullscreen mode Exit fullscreen mode

By default, access logging is disabled (access_log off) since router storage is limited. Error logs still go to the system log and are accessible via logread.

Backup Your Configuration

UCI configurations live in /etc/config/. Location files are in /etc/nginx/conf.d/. Back these up:

# Create backup
tar -czf nginx-backup.tar.gz /etc/config/nginx /etc/nginx/conf.d/ /etc/nginx/ssl/

# Restore
tar -xzf nginx-backup.tar.gz -C /

Enter fullscreen mode Exit fullscreen mode

Service-Specific Configuration

Some services need to know they’re behind a reverse proxy. Nginx alone isn’t enough - you need to configure the service itself. For example, Grafana requires:

environment:
 - GF_SERVER_ROOT_URL=https://grafana.yourdomain.home

Enter fullscreen mode Exit fullscreen mode

Without this, Grafana fails to load its assets through the proxy. Check your service’s documentation for reverse proxy settings if things don’t work after setting up nginx.

What’s Next

This post covered local access to your homelab services. In an upcoming post, I’ll cover remote access - setting up WireGuard on OpenWrt to securely reach your services from anywhere.

Conclusion

Running nginx on your OpenWrt router leverages hardware you already have running 24/7. It eliminates network hops, centralizes configuration with DNS, and provides a clean subdomain-based access pattern for all your services.

The combination of OpenWrt’s UCI system and nginx’s flexibility creates a maintainable setup that scales from a handful of services to dozens. My 25-service configuration runs on minimal resources and has been rock solid.

Start with one or two services, get comfortable with the UCI workflow, and expand from there. Your router is more capable than you might think.


I write weekly about homelabs, monitoring, and DevOps. If you found this helpful, check out my other posts or subscribe on Dev.to for more practical guides like this one.

Top comments (0)