Caddy Reverse Proxy Not Resolving Upstream Port

Started by Stinger0674, August 14, 2026, 01:49:40 AM

Previous topic - Next topic
I tried to make a post under the Caddy FAQ, but it was a pretty dead thread.

So far I've determined that Caddy isn't redirecting traffic to the right port for my services. I run most of my services in Docker on a Debian VM in Proxmox, the IP of the Debian VM (and my services) is 192.168.10.247. All of this is meant to run internally only.

I made an Override in Unbound DNS for this server as *.homelab.internal. I am able to resolve the domain name, so when I do nslookup immich.homelab.internal, jellyfin.homelab.internal, etc., it works both in the OPNsense terminal and on my laptop connected via WiFi.

When I do
curl -vk http://immich.homelab.internal:2283it resolves and pulls the site html.

But when I do curl -vk http://immich.homelab.internal, it fails:

* Host immich.homelab.internal:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.10.247
*   Trying 192.168.10.247:80...
* connect to 192.168.10.247 port 80 from 192.168.10.89 port 53232 failed: Connection refused
* Failed to connect to immich.homelab.internal port 80 after 5 ms: Could not connect to server
* closing connection #0
curl: (7) Failed to connect to immich.homelab.internal port 80 after 5 ms: Could not connect to server

It's trying to contact port 80 despite me setting the upstream port in the Caddy settings.

This is the same behavior for my proxmox.internal domain.

You cannot view this attachment.

I even tried to do Host {upstream_hostport}
Here's my caddyfile:

# DO NOT EDIT THIS FILE -- OPNsense auto-generated file


# caddy_user=root

# Global Options
{
log {
output net unixgram//var/run/caddy/log.sock {
}
format json {
time_format rfc3339
}
}

http_port 80
https_port 443

servers {
protocols h1 h2 h3
}

auto_https disable_redirects
grace_period 10s
skip_install_trust
import /usr/local/etc/caddy/caddy.d/*.global
}

# Reverse Proxy Configuration


immich.homelab.internal {
handle {
reverse_proxy 192.168.10.247:2283 {
header_up Host {upstream_hostport}

transport http {
}
}
}
}

proxmox.internal {
handle {
reverse_proxy 192.168.10.4:8006 {
header_up Host {upstream_hostport}

transport http {
}
}
}
}

import /usr/local/etc/caddy/caddy.d/*.conf

I have    auto_https disable_redirects set.

What am I missing?

August 14, 2026, 06:35:05 AM #1 Last Edit: August 14, 2026, 06:38:56 AM by Monviech (Cedrik)
Nobody public CA will issue certificates for .internal.

You either need a self signed certifiate, or set the domain to http instead of https.

Using http will make caddy receive on port 80 and proxy to port 2283.

In curl you will only see port 80 though as thats what the proxy will use.

Your DNS override points immich.homelab.internal to 192.168.10.247, so you're bypassing Caddy entirely. It needs to resolve to the OPNsense/Caddy IP address. The upstream port 2283 is only used by Caddy after it receives the request.

Use the FAQ here for more infos:
https://docs.opnsense.org/manual/how-tos/caddy.html#caddy-troubleshooting
Hardware:
DEC740

Yeah, I understand that public CAs can't give certs to .internal, I do want this to be local only. Sorry, I've got a lot of stuff scrambled around due to trying to follow the FAQ tutorial and random guides. I previously selected http for both the domain and handler and still had issues.

I removed my DNS override entries, although now I'm struggling to resolve homelab.internal domains. Where can I view A and AAAA records for Unbound? Do I need to enable Register ISC DHCP4 Leases and Register DHCP Static Mappings?

I added 192.168.10.4 proxmox.internal nova to my /etc/hosts file in Proxmox and I can resolve it, but 192.168.10.247 homelab.internal dockarr didn't work for the Debian VM...

I originally followed the FAQ and tried the troubleshooting steps, but I still get ERR_NAME_NOT_RESOLVED in browser (FF, Chromium, etc.)

Curl outputs:
curl -vk http://proxmox.internal:8006
* Host proxmox.internal:8006 was resolved.
* IPv6: (none)
* IPv4: 192.168.10.4
*   Trying 192.168.10.4:8006...
* Established connection to proxmox.internal (192.168.10.4 port 8006) from 192.168.10.89 port 53008
* using HTTP/1.x
> GET / HTTP/1.1
> Host: proxmox.internal:8006
> User-Agent: curl/8.16.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Cache-Control: max-age=0
< Connection: Keep-Alive
< Date: Fri, 14 Aug 2026 17:15:47 GMT
< Pragma: no-cache
< Location: https://proxmox.internal:8006/
< Server: pve-api-daemon/3.0
< Content-Length: 17
< Expires: Fri, 14 Aug 2026 17:15:47 GMT
<
* Connection #0 to host proxmox.internal:8006 left intact
Moved Permanently

Is "Moved Permanently" normal?

Failed curl:
curl -vk http://proxmox.internal
* Host proxmox.internal:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.10.4
*   Trying 192.168.10.4:80...
* connect to 192.168.10.4 port 80 from 192.168.10.89 port 49200 failed: Connection refused
* Failed to connect to proxmox.internal port 80 after 6 ms: Could not connect to server
* closing connection #0
curl: (7) Failed to connect to proxmox.internal port 80 after 6 ms: Could not connect to server

If your OPNsense has eg 192.168.10.1 on thr LAN interface, your DNS overrides have to point proxmox.internal (and any other hostnames) to 192.168.10.1.

How else should Caddy get the traffic to proxy?

192.168.10.4 port 80 from 192.168.10.89:
Thats Proxmox directly from one of your clients, OPNsense and Caddy sees nothing.
Hardware:
DEC740

THANK YOU!!! You're a saint!

I didn't realize I needed to have overrides that point to the gateway for Caddy to resolve it...

I'm able to get my *.homelab.internal domains to come up in browser, although I have to disable my DNS over HTTPS to do so (which makes sense, as I need to use my own DNS servers to be able to access my stuff, not an external server like NextDNS). As long as my OPNsense DNS servers are set, I won't have to worry about that setting on my browsers now right? I can just set NextNDS, AdGuard, etc's IP in System > Settings > General, and my browsers will use those servers?

The only issue is http://proxmox.internal, curl gives this:

* Host proxmox.internal:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.10.1, 192.168.10.4
*   Trying 192.168.10.1:80...
* Established connection to proxmox.internal (192.168.10.1 port 80) from 192.168.10.89 port 43454
* using HTTP/1.x
> GET / HTTP/1.1
> Host: proxmox.internal
> User-Agent: curl/8.16.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Cache-Control: max-age=0
< Content-Length: 17
< Date: Sat, 15 Aug 2026 18:00:08 GMT
< Expires: Sat, 15 Aug 2026 18:00:08 GMT
< Location: https://proxmox.internal/
< Pragma: no-cache
< Server: pve-api-daemon/3.0
< Via: 1.1 Caddy
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host proxmox.internal:80 left intact
Moved Permanently

And the webpage is ERR_CONNECTION_TIMED_OUT (301 makes sense). Unsure of what's wrong, my override for host proxmox, domain internal points to 192.168.10.1. My Caddy config is http://proxmox.internal, upstream domain 192.168.10.4 and port 8006. But I'm less worried about that one for now.

Hey, looks like progress.

The Via: 1.1 Caddy header shows that Caddy is now receiving and proxying the request.

However, proxmox.internal still resolves to both 192.168.10.1 and 192.168.10.4. You should find out where the .4 record comes from and remove it, otherwise clients can still connect directly to Proxmox.

The timeout happens because Proxmox responds with:

Location: https://proxmox.internal/

Your Caddy domain is configured as HTTP only, so the browser follows the redirect to HTTPS port 443, where you don't have this domain configured. Proxmox really expects HTTPS, so for this one it makes more sense to configure HTTPS in Caddy with an internal/self-signed certificate or Let's Encrypt.

And yes, browser DoH bypasses Unbound and therefore your local overrides. Setting an external DNS server in System > Settings > General is different; your clients can still use Unbound and resolve your local overrides.

(Partially formatted with chatgpt cause Im tired)
Hardware:
DEC740