Reverse proxy matching on port

1. Caddy version (V2.2.1):

2. How I run Caddy:

Installed on Ubuntu server 20.04 with apt, so loading Caddyfile from /etc/caddy

a. System environment:

Ubuntu server 20.04

b. Command:

runs as service

c. Service/unit/compose file:

default

d. My complete Caddyfile or JSON config:

{
  experimental_http3
}

# Add gzip compression to requests
(webconf) {
  encode gzip
}

#define logging
(logging) {
  log {
    output file /var/log/caddy/caddy.log {
      roll_size 1gb
      roll_keep 5
    }
  }
}

#define wildcard certificate
(certs) {
  tls /etc/caddy/STAR_eltomation_com.pem /etc/caddy/STAR_eltomation_com.key
}

# Add forward headers to requests
(theheaders) {
  header_up X-Forwarded-Ssl on
  header_up Host {http.request.host}
  header_up X-Real-IP {http.request.remote}
  header_up X-Forwarded-For {http.request.remote}
  header_up X-Forwarded-Port {http.request.port}
  header_up X-Forwarded-Proto {http.request.scheme}
  header_up X-Url-Scheme {http.request.scheme}
  header_up X-Forwarded-Host {http.request.host}
}

ovpn.eltomation.com, ovpn.eltomation.com:1194 {
  import logging
  import certs
  reverse_proxy host *:1194 https://192.168.16.9:1194 {
    import theheaders
    transport http {
      tls_insecure_skip_verify
    }
  }
reverse_proxy https://192.168.16.9 {
    import theheaders
    transport http {
      tls_insecure_skip_verify
    }
  }
  import webconf
}

3. The problem I’m having:

I want one rule for the ovpn.
reverse-proxy to internal ip with correct port for each port.
Some services, like openvpn, we run 3 services.
Openvpn uses 3 ports (443, 1194 and 500).
I want to route to the correct internal ip-address depending on the fqdn.
So ovpn.eltomation.com goes to 192.168.16.9, openvpn.eltomation.com goes to 192.168.16.4, and so on.

4. Error messages and/or full log output:

It isn’t working.
I get an error 502 or the wrong service or the correct service at random.

5. What I already tried:

reverse_proxy host :1194 https://192.168.16.9
reverse_proxy header http.request.port 1194 https://192.168.16.9
reverse_proxy host ovpn.eltomation.com:1194 https://192.168.16.9

6. Links to relevant resources:

So, two things.

First, matchers must either be a path, starting with /, a named matcher starting with @, or * meaning “match anything”. You need to use named matchers for anything other than simple path matchers. This is explained at the top of the page you linked:

Second, It’s not really possible to match on the port. You’ll need to make two separate site blocks in this case. This is because under the hood, those are actually two separate servers, because they’re listening on different ports. You can see this by running caddy adapt --pretty to see the underlying JSON for your Caddyfile.

It would look like this:

...

ovpn.eltomation.com {
	import logging
	import certs

	reverse_proxy https://192.168.16.9 {
		import theheaders
		transport http {
			tls_insecure_skip_verify
		}
	}

	import webconf
}

ovpn.eltomation.com:1194 {
	import logging
	import certs

	reverse_proxy https://192.168.16.9:1194 {
		import theheaders
		transport http {
			tls_insecure_skip_verify
		}
	}

	import webconf
}

Also:

(theheaders) {
  header_up X-Forwarded-Ssl on
  header_up Host {http.request.host}
  header_up X-Real-IP {http.request.remote}
  header_up X-Forwarded-For {http.request.remote}
  header_up X-Forwarded-Port {http.request.port}
  header_up X-Forwarded-Proto {http.request.scheme}
  header_up X-Url-Scheme {http.request.scheme}
  header_up X-Forwarded-Host {http.request.host}
}

All of this is likely useless. Caddy automatically sets Host, X-Forwarded-For and X-Forwarded-Proto which are usually the only ones that are necessary. It also takes care to set them correctly, and to spec. Overriding them like this can cause trouble, so it’s best to let Caddy do its thing, unless you actually know you need to override them.

2 Likes

This isn’t always accurate; if the Host header comes in with a non-standard port, for example example.com:1234, you can use a host matcher to match on example.com:1234. I’m not sure you can (yet?) match on port alone, but maybe with wildcards? I dunno, haven’t tried it: *.*:1234

Of course, this assumes the client is virtuous… in theory, an HTTP client could connect to port A and then send a request with a Host header for port B. It’s nonsense, but I guess it could happen.

Yeah, hence the “really”. I don’t recommend it because it makes it more complicated than it needs to be, as you explained. I think just making a second site block is the better option.

1 Like

Ok, thank you very much.
Tried it this way.
But, OpenVPN gives an error that it couldn’t connect.

OpenVPN gives the following log:

Event: Connection_timeout

Looks like Caddy isn’t responding either, becouse I see no entries in the log of Caddy.
The IP of Caddy is 10.99.99.100.

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