Reverse proxy to router not working

1. The problem I’m having:

I’m trying to reverse proxy from my homelab to my router admin dashboard using my domain with subdomain router.777333777.xyz . It used to work when I still used Nginx Proxy Manager but haven’t got it working in Caddy yet.

I do get a response from the page but it’s a white page with favicon and js file 404 responses (like below). I can access it straight through the ip (like 192.168.0.1) but not through the reverse proxy. How can I fix this?

2. Error messages and/or full log output:

When using the curl command to the favicon of the Gl Inet router.

curl -v https://router.777333777.xyz/favicon.ico
* Host router.777333777.xyz:443 was resolved.
* IPv6: (none)
* IPv4: 100.94.151.24
*   Trying 100.94.151.24:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=router.777333777.xyz
*  start date: Nov 24 11:34:56 2025 GMT
*  expire date: Feb 22 11:34:55 2026 GMT
*  subjectAltName: host "router.777333777.xyz" matched cert's "router.777333777.xyz"
*  issuer: C=US; O=Let's Encrypt; CN=E8
*  SSL certificate verify ok.
*   Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
*   Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* Connected to router.777333777.xyz (100.94.151.24) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://router.777333777.xyz/favicon.ico
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: router.777333777.xyz]
* [HTTP/2] [1] [:path: /favicon.ico]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
> GET /favicon.ico HTTP/2
> Host: router.777333777.xyz
> User-Agent: curl/8.14.1
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Request completely sent off
< HTTP/2 404
< alt-svc: h3=":443"; ma=2592000
< content-type: text/html
< date: Mon, 24 Nov 2025 14:16:39 GMT
< server: nginx/1.17.7
< via: 1.1 Caddy
< content-length: 153
<
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.7</center>
</body>
</html>
* Connection #0 to host router.777333777.xyz left intact

3. Caddy version:

v2.10.2

4. How I installed and ran Caddy:

Installed and ran through docker compose (config below)

a. System environment:

Running Debian 13.2 with Tailscale installed on base system.

c. Service/unit/compose file:

services:
  # Caddy - Reverse Proxy
  caddy:
    container_name: caddy
    hostname: caddy
    image: ghcr.io/caddybuilds/caddy-cloudflare:latest
    cap_add:
      - NET_ADMIN
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '443:443/udp'
    volumes:
      - ./caddy:/etc/caddy
      - ./caddy/data:/data
      - ./caddy/config:/config
    environment:
      - CLOUDFLARE_API_TOKEN=xxxx

d. My complete Caddy config:

{
    acme_dns cloudflare "xxx"
}

router.777333777.xyz {
	reverse_proxy 192.168.0.1:80
}

printer.777333777.xyz {
  reverse_proxy http://192.168.0.3:80
}

vaultwarden.777333777.xyz {
  reverse_proxy vaultwarden:80
}

homeassistant.777333777.xyz {
  reverse_proxy homeassistant:8123
}

What do you get when you run:

curl -v http://192.168.0.1

This is what I get when I run curl on the IP

curl -v http://192.168.0.1
*   Trying 192.168.0.1:80...
* Connected to 192.168.0.1 (192.168.0.1) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 192.168.0.1
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx/1.17.7
< Date: Wed, 26 Nov 2025 16:03:28 GMT
< Content-Type: text/html
< Content-Length: 746
< Last-Modified: Fri, 07 Mar 2025 03:14:56 GMT
< Connection: keep-alive
< ETag: "67ca64b0-2ea"
< Cache-Control: private, no-store, no-cache, must-revalidate, proxy-revalidate
< Accept-Ranges: bytes
<
* Connection #0 to host 192.168.0.1 left intact
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="Cache-Control" content="no-cache,no-store,must-revalidate"><meta http-equiv="pragma" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"><link rel="icon" href="/favicon.ico"><title>GL.iNet Admin Panel</title><link href="/js/app.7ec6347c.js" rel="preload" as="script"></head><body><noscript><strong>We're sorry but gl-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/app.7ec6347c.js"></script></body></html>

See if this would work:

router.777333777.xyz {
	reverse_proxy 192.168.0.1:80 {
		header_up Host {http.reverse_proxy.upstream.host}
	}
}

Hi again, thx! Sadly the result doesn’t change. I’m starting to think it has something to do with my domain having an A record to the tailscale ip of my home server and GL.iNet not allowing anything other than the LAN IP range to access the admin panel. I have been crawling through the logs a few hours on caddy, using curl commands and in the browser dev panel but the only thing I get is a 404 :frowning:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.