Load balancer/reverse-proxy redirects on Ktor application for public URL

Hello everyone! First time user of Balena here :smiley:

I have setup a Ktor application and deployed it on an RPi-4. I have a Docker image that I am building locally by extending balenalib/raspberrypi3-openjdk:8-jdk since there is no JDK one for RPi-4 that I have found.

The application is deployed correctly, but needs an iptables port forwarding in order to redirect the port 80 to port 8080, since you can not listen on port 80 due to Linux permissions for ports lower than 1024, which makes Netty crash with permission denied.

Thus far everything is fine, although there seems to be a load balancer in front of the public URL of a device, which causes repeated redirects, causing the application to not respond. On several load balancers or reverse-proxies there seems to be special request headers preventing those issues and I was able to resolve this issue in Google Cloud Run for example, by utilizing Ktor’s feature https://ktor.io/quickstart/faq.html#infinite-redirect

This seems to not be the case for balenaOS though, since the redirects do not stop. Is there anyone who can give me a hint on what I might be missing?

Thanks in advance :smiley:

Hey, can you share the docker file so we can have a better sense of what might be the issue.

Sure, here it is:

Can you please try as well iptables -P FORWARD ACCEPT as something like that is often needed when running under balenaOS compared to other distributions which have less restrictive default forward policy and see whether this will solve the issue for you?

This rule alone does not work. I used as well:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

But I still get the issue with the repeated redirects, because the load balancer cannot distinguish the proper headers.

Hi there, just to rewind a bit on the conversation, what is the reason for you needing to modify the iptables? In Docker you can map the hostOS port to a container port, so you can do something like 80:8080, and run your web application on port 8080. Is this a multicontainer application? You can see how the ports are mapped here https://github.com/balenalabs/multicontainer-getting-started/blob/master/docker-compose.yml in the docker-compose file. Let us know if that solves your issue.

I am not using Docker Compose right now. Do you believe it would be easier if I would change the setup to docker-compose?

If it is a single container, you can just start your server on port 80 and it should work as expected. See the docs for more information: https://www.balena.io/docs/learn/develop/runtime/#single-container-applications

Netty does not accept it if I start it on port 80 by default and that is why I was searching for a different approach!

I see, in that case you can just add a docker-compose file with a single service and map the ports there.

Will try that as well. Is there a way to revert the iptables rules though in order to be sure, that the docker compose rule works due to port exposure?

Hello, iptables rules should not persist across reboots, so it should be sufficient to restart the device to return to a clean state

@sradevski @majorz @nazrhom Thank you all for your help! I went with the docker-compose approach and it worked like a charm :smiley: I am quite grateful for your responsiveness!

Glad to hear you managed to get it sorted. Good luck, happy to help if anything else pops up :slight_smile:

1 Like