Skip to content

Instantly share code, notes, and snippets.

@apparentlymart
Last active August 30, 2023 21:45
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save apparentlymart/d8ebc6e96c42ce14f64b to your computer and use it in GitHub Desktop.
Save apparentlymart/d8ebc6e96c42ce14f64b to your computer and use it in GitHub Desktop.
round robin to three ports on the same host with iptables
# The following example shows a way to use iptables for basic round-robin load balancing, by redirecting
# packets two one of three ports based on a statistic counter.
#
# TCP packets for new sessions arriving on port 9000 will rotate between ports 9001, 9002 and 9003, where
# three identical copies of some application are expected to be listening.
#
# Packets that aren't TCP or that related to an already-established connection are left untouched, letting
# the standard iptables connection tracking machinery send it to the appropriate port.
#
# For this to work well, connections need to be relatively short. Ideally there would be an extra layer
# of load balancing in front that holds longer-term client keepalive connections and then opens short-lived
# connections to the app servers.
# Note that because this uses the PREROUTING chain it will work only for incoming connections from other hosts,
# not connections on local loopback.
# Always accept packets for already-active sessions.
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Default input policy is to ACCEPT
iptables -P INPUT ACCEPT
# One in three TCP packets go to port 9001
iptables -t nat -A PREROUTING -p tcp --dport 9000 -m statistic --mode nth --every 3 --packet 0 -j REDIRECT --to-port 9001
# One in the remaining two go to port 9002
iptables -t nat -A PREROUTING -p tcp --dport 9000 -m statistic --mode nth --every 2 --packet 0 -j REDIRECT --to-port 9002
# The remaining one always routes to port 9003
iptables -t nat -A PREROUTING -p tcp --dport 9000 -j REDIRECT --to-port 9003
# An alternative formulation would be to have one of the app processes listen on port 9000 itself
# and then drop the final rule, so packets that aren't matched by the statistics rules will just go to the port 9000 app by default.
@pandurangarao
Copy link

Hello Martin,

Thanks for the example.

I got the following error while trying to add these rules.
iptables: No chain/target/match by that name.
May I know if I am doing something wrong.

Thanks.

@stokito
Copy link

stokito commented Feb 10, 2021

try to add sudo i.e. sudo iptables -t nat -A PREROUTING -p tcp --dport 9000 -m statistic --mode nth --every 3 --packet 0 -j REDIRECT --to-port 9001

@bigdogdan2
Copy link

bigdogdan2 commented Aug 30, 2023

Note that because this uses the PREROUTING chain it will work only for incoming connections from other hosts,
not connections on local loopback.

If we want to send to loopback, what is needed?

@apparentlymart
Copy link
Author

Hi all,

To be totally honest I don't even remember creating this gist or what I was working on that caused me to use iptables to try to solve this problem in the first place. My memory of the details of iptables is now very rusty -- this gist was from 2015 -- so I can't comment on how exactly this would behave or how you might modify it to solve other problems. I don't even remember exactly what problem this does solve.

If you're trying to do something in the vicinity of this then I'd suggest asking somewhere more visible where folks who have more fresh knowledge of iptables might find it. I also heard that iptables has been deprecated in favor of nftables, so you might be better off looking for equivalent solutions with the newer model instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment