Create a reverse proxy for two ports

I am using Caddy version 2. I am running a docker container on linux with 2 apps, one running on port 8080, and another on port 5000. I am looking for both to be under the same subdomain via a reverse_proxy, and am looking for suggestions on how to do that. I am open to making two different routes on the subdomain (ie subdomain/app1 and subdomain app2). The preferred solution would be to have a reverse proxy covering port 8080, and if route to https://subdomain/ , it would redirect to http:ipAddress:5000, which would still “displayed” as https://subdomain/. As I said though, I am open to solutions that would put each port on a different route.

current Caddy file:

subdomain.example

reverse proxy ipaddress:8080

some attempted solutions:

subdomain.example

reverse proxy ipaddress:8080
reverse proxy ipaddress:5000
subdomain.example

reverse proxy /app1 ipaddress:8080
reverse proxy /app2 ipaddress:5000

Please see https://caddyserver.com/docs/caddyfile/directives/handle#examples

Something like this should work:

handle /app1/* {
	reverse_proxy ipaddress:8080
}

handle /app2/* {
	reverse_proxy ipaddress:5000
}

Thanks for the fast response. It doesn’t appear to be the solution. This is the caddyfile now:

subdomain.example

handle /app1/* {
    reverse_proxy ip:8080
}

handle /app2/* {
    reverse_proxy ip:5000
}

I stopped the docker containers before running again.
I don’t get any errors, and if i go to /app1/login for example, i see it redirecting properly in the url. However, it is a completely blank page.

hmm, maybe put file_server in each handle directive.

redir /app2 /app2/ # might want to include this as well
handle /app2/* {
    file_server
    reverse_proxy ip:5000
}

this may not work if you need the login page is php, for that look at https://caddyserver.com/docs/caddyfile/directives/php_fastcgi

I dont see the point in doing the redirect? I only wanted the redirect if I couldn’t get a solution on seperate routes.
new Caddyfile:

subdomain.example 

handle /app1/* {
    file_server
    reverse_proxy ip:8080
}

handle /app2/* {
    file_server
    reverse_proxy ip:5000
}

Same results :frowning:

Additionally, thanks for the suggestion, but it is not in php

hmm, now that I think about it, the file_server directive isn’t going to do anything.

can the docker containers reach each other at the IP? try pinging the IP from the caddy docker container.

How would I do that? Dont have tons of experience with the caddy container

If it helps, I previous had it that if you went to subdomain/ with the reverse proxy at 8080, it would redirect to http:ip:5000

you should be able to run a command from the context of the container using docker exec

for example (caddy is the ID of the container for caddy, can find using docker ps`)

> docker exec -it caddy /bin/sh
/srv # ping php-fpm
PING php-fpm (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.083 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.067 ms
^C
--- php-fpm ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.075/0.083 ms
/srv #

what does php-fpm represent? i did ping subdomain.example/app1 and i got: bad address

that is the hostname for my php server. you should replace it with the ip portion of ip:5000

Ok. ya they both went through. it was very slow and i hit control-c after like 10-15 seconds, but I did see that first line of 56 data bytes for both ports

Can you paste the output?

the ping command will keep going until you stop it, but you should see multiple successful pings if you ran it for 10-15 seconds.

sure. this is after running for about 30 seconds.
PING “ip”:5000 (“ip”): 56 data bytes
^C
— “ip”:5000 ping statistics —
34 packets transmitted, 0 packets received, 100% packet loss

That is showing some kind of networking issue, none of the pings are reaching their destination. What is the IP of the server hosting something on port 5000? You want to ping just the ip, leave out the port (5000) and any quotes. Also I want to make sure you are replacing ip with the ip of the server hosting something on port 5000.

At this point I think you have something wrong with your networking or something wrong with the values you are giving to the caddyfile. Can you send the whole caddyfile (minus any passwords)? It is hard to troubleshoot when you are redacting even internal IPs.

My boss at the moment is not ok with me putting the domain and ip up :frowning: ill post it if he changes his mind. This is copy and paste of caddy file currently running, with dummy ip obvs.

domain

handle /server/* {
    reverse_proxy 123.123.123.123:8080
}

handle /ui/* {
    reverse_proxy 123.123.123.123:5000
}

Ill believe it is an issue with what is being given to the caddy file, being that

domain

reverse_proxy 123.123.123.123:8080

works just fine.

I think you’re looking for the handle_path, which is the same as handle, but it also does a rewrite to strip the specified prefix from the URL before proxying. This is important, because Caddy preserves the request path when proxying. This is different than the default behaviour of nginx. handle_path is what solves that.

domain

handle_path /api1/* {
	reverse_proxy ipaddress:8080
}

handle_path /api2/* {
	reverse_proxy ipaddress:5000
}

The suggestion of adding the redirect is good as well, i.e. redir /app1 /app1/. This is relevant, because when you use a path matcher like /api1/*, requests to /api1/ and /api1/foo will match, but not /api1. The redirect ensures that if exactly /api1 is requested, it will add the trailing / which would be required to satisfy your path matcher.

You could use a matcher like /api1* to avoid this issue, but it introduces the other issue that that would also match /api1foo which is likely not the intended result.

1 Like

This solution was an improvement, but it did not seal the deal. Occasionally I was able to get through, but I’m still getting this blank white page. It’s very strange. For example, if I go to the /ui route, I see in the network tab in of dev tools the domain/static/ css and js files, which would imply that it is reaching the 5000 port, but the page is just completely white.

current caddy file:

domain

redir /server /server/
handle_path /sever/* {
    reverse_proxy ip:8080
}

redir /ui /ui/
handle_path /ui/* {
    reverse_proxy ip:5000
}

Once again, just having a caddy file with:

domain 

reverse_proxy ip:8080 

works for just one port, so it still implies a syntax error in the caddyfile

When you use a handle or handle_path with a matcher, only requests that match the path will get handled by them. You don’t have anything that handles anything except /ui/* and /sever/* (note your typo!)

I don’t think I understand what your goal is here, so I’m not certain what to suggest. Do you expect any request that isn’t to /ui/* or /server/* to get handled by your service on port 5000 or 8080? Either way, just add a reverse_proxy that is not in a handle to act as a fallback.

When Caddy doesn’t know how to handle a request (i.e. nothing in the configuration tells it what to do with it), it just returns an empty 200 response. This is because it’s technically not an error, Caddy is just following its configuration. It’s up to the user to make sure the config does what they need :smile: