Rewrite + reverse_proxy

1. The problem I’m having:

I am trying to set up a reverse proxy that maps the original path to a slightly altered path on the server, i.e. I want all requests to api.server.com/data to be redirected to server2.com/core-api/data. I have been trying to follow similar examples on here but have not had success yet.

This is relevant part of my Caddyfile:

api.server.com {
    rewrite * /core-api{uri}
    reverse_proxy server2.com
}

Clearly it’s stuck redirecting infinitely from the browser network view and the logs but I would expect new requests to go to server2.com, not back to api.server.com. I’m clearly missing something!

Thank you for your help.

2. Error messages and/or full log output:

Logs are truncated to meet post character limits but basically this pattern repeats a dozen times before the browser gives up and stops redirecting.

2024/01/09 18:22:49.127	DEBUG	http.handlers.rewrite	rewrote request	{"request": {"remote_ip": "127.0.0.1", "remote_port": "51922", "client_ip": "127.0.0.1", "proto": "HTTP/3.0", "method": "GET", "host": "api.server.com", "uri": "/data", "headers": {"Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Mode": ["navigate"], "Accept-Language": ["en-US,en;q=0.5"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"], "Alt-Used": ["api.server.com"], "Sec-Fetch-Dest": ["document"], "Sec-Fetch-Site": ["none"], "Sec-Fetch-User": ["?1"], "Pragma": ["no-cache"], "Priority": ["u=1"], "Accept-Encoding": ["gzip, deflate, br"], "Cache-Control": ["no-cache"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h3", "server_name": "api.server.com"}}, "method": "GET", "uri": "/core-api/data"}
2024/01/09 18:22:49.127	DEBUG	http.handlers.reverse_proxy	selected upstream	{"dial": "server2.com:80", "total_upstreams": 1}
2024/01/09 18:22:49.128	DEBUG	http.handlers.reverse_proxy	upstream roundtrip	{"upstream": "server2.com:80", "duration": 0.001142334, "request": {"remote_ip": "127.0.0.1", "remote_port": "51922", "client_ip": "127.0.0.1", "proto": "HTTP/3.0", "method": "GET", "host": "api.server.com", "uri": "/core-api/data", "headers": {"Accept-Language": ["en-US,en;q=0.5"], "Sec-Fetch-Site": ["none"], "Priority": ["u=1"], "Accept-Encoding": ["gzip, deflate, br"], "Sec-Fetch-Mode": ["navigate"], "Alt-Used": ["api.server.com"], "Sec-Fetch-Dest": ["document"], "Pragma": ["no-cache"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "X-Forwarded-Host": ["api.server.com"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"], "Cache-Control": ["no-cache"], "X-Forwarded-For": ["127.0.0.1"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-User": ["?1"], "X-Forwarded-Proto": ["https"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h3", "server_name": "api.server.com"}}, "headers": {"Location": ["https://api.server.com/core-api/data"], "Server": ["Caddy"], "Date": ["Tue, 09 Jan 2024 18:22:49 GMT"], "Content-Length": ["0"]}, "status": 308}
2024/01/09 18:22:49.139	DEBUG	http.handlers.rewrite	rewrote request	{"request": {"remote_ip": "127.0.0.1", "remote_port": "51922", "client_ip": "127.0.0.1", "proto": "HTTP/3.0", "method": "GET", "host": "api.server.com", "uri": "/core-api/data", "headers": {"Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Sec-Fetch-User": ["?1"], "Pragma": ["no-cache"], "Cache-Control": ["no-cache"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-Site": ["none"], "Priority": ["u=1"], "Alt-Used": ["api.server.com"], "Accept-Language": ["en-US,en;q=0.5"], "Accept-Encoding": ["gzip, deflate, br"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Dest": ["document"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h3", "server_name": "api.server.com"}}, "method": "GET", "uri": "/core-api/core-api/data"}
2024/01/09 18:22:49.139	DEBUG	http.handlers.reverse_proxy	selected upstream	{"dial": "server2.com:80", "total_upstreams": 1}
2024/01/09 18:22:49.141	DEBUG	http.handlers.reverse_proxy	upstream roundtrip	{"upstream": "server2.com:80", "duration": 0.00173525, "request": {"remote_ip": "127.0.0.1", "remote_port": "51922", "client_ip": "127.0.0.1", "proto": "HTTP/3.0", "method": "GET", "host": "api.server.com", "uri": "/core-api/core-api/data", "headers": {"Priority": ["u=1"], "Upgrade-Insecure-Requests": ["1"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-Site": ["none"], "Accept-Encoding": ["gzip, deflate, br"], "X-Forwarded-For": ["127.0.0.1"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Pragma": ["no-cache"], "Accept-Language": ["en-US,en;q=0.5"], "X-Forwarded-Proto": ["https"], "Cache-Control": ["no-cache"], "Alt-Used": ["api.server.com"], "X-Forwarded-Host": ["api.server.com"], "Sec-Fetch-User": ["?1"], "Sec-Fetch-Dest": ["document"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h3", "server_name": "api.server.com"}}, "headers": {"Location": ["https://api.server.com/core-api/core-api/data"], "Server": ["Caddy"], "Date": ["Tue, 09 Jan 2024 18:22:49 GMT"], "Content-Length": ["0"]}, "status": 308}

3. Caddy version:

v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=

4. How I installed and ran Caddy:

brew install caddy

a. System environment:

OSX, not in a container

b. Command:

caddy run

c. Service/unit/compose file:

d. My complete Caddy config:

api.server.com {
    rewrite * /core-api{uri}
    reverse_proxy server2.com
}

5. Links to relevant resources:

You’re proxying to the HTTP endpoint of your upstream server, which is responding with a redirect to HTTPS.

You either need to turn off redirects on your upstream, or proxy over HTTPS.

Why are you proxying this way? Is the app on the same server? If so don’t use the domain name to proxy, use localhost or whatever. Your setup seems strange.

Hi Francis, thanks for responding. I am new to Caddy so please excuse any mistakes on my part!

Unfortunately I did not design the system, but I need to replicate the host/subdomain structure using Caddy. api.server.com is basically an api gateway that redirects to different servers/paths based on the original path.

E.g.
api.server.com/dataserver2.com/core-api/data
api.server.com/eventsserver2.com/core-api/events
api.server.com/platformsserver2.com/core-api/platforms
api.server.com/authauthserver.com

These apps are all running locally on my computer but it would be nice to make this flexible enough that if one server is on another computer it doesn’t break. I’m trying to model a architecture on one computer that matches the production architecture where these are on different servers.

How would I proxy over https? Do I need to specify the scheme explicitly?

Thank you for your help!

See reverse_proxy (Caddyfile directive) — Caddy Documentation for proxying to an HTTPS upstream.

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