Easy Dual WAN Load Balancing with MikroTik RouterOS PCC

RouterOS’s load balancing is simple but tricky. Even Mikrotik shows an example of how to configure PCC for load balancing. It does not say how to implement it with dynamic IP. The method introduced here is simple. We will add lease scripts to WAN1 and WAN2. RouterOS will run the script to add the correct gateway IP and firewall rules to make the load balancing work.

Requirements:

1. Name your WAN ports as WAN1 and WAN2. Your bridge as bridge.
2. Basic knowledge of RouterOS
3. Turn off fasttrack. Yes. It must be off. Otherwise, router can’t mark traffic and distribute to both WANs. Disable the firewall filter with action “fasttrack-connection” and that is it.

Add below scripts to IP/DHCP Client/WAN1 and IP/DHCP Client/WAN2. You can do that via web config.

For WAN1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

{
:local count [/ip route print count-only where comment=WAN1]
:if ($bound=1) do={
:if ($count = 0) do={
/ip route add gateway=$"gateway-address" routing-mark=WAN1 comment=WAN1
/ip firewall nat add chain=srcnat out-interface=WAN1 action=masquerade comment=WAN1
/ip firewall mangle add chain=prerouting dst-address=$"gateway-address" action=accept in-interface=bridge comment=WAN1
/ip route add gateway=$"gateway-address" routing-mark=WAN1_out check-gateway=ping comment=WAN1
/ip route add gateway=$"gateway-address" distance=1 check-gateway=ping comment=WAN1
} else={
:if ($count > 1) do={
:local test [/ip route find where comment=WAN1]
:if ([/ip route get $test gateway] != $"gateway-address") do={
/ip route set $test gateway=$"gateway-address"
}
:local test2 [/ip firewall mangle find where comment=WAN1]
:if ([/ip firewall mangle get $test2 gateway] != $"gateway-address") do={
/ip route set $test2 gateway=$"gateway-address"
}
} else={
:error "Multiple routes found"
}
}
} else={
/ip route remove [find comment=WAN1]
/ip firewall mangle remove [find comment=WAN1]
/ip firewall nat remove [find comment=WAN1]
}
}

For WAN2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
:local count [/ip route print count-only where comment=WAN2]
:if ($bound=1) do={
:if ($count = 0) do={
/ip route add gateway=$"gateway-address" routing-mark=WAN2 comment=WAN2
/ip firewall nat add chain=srcnat out-interface=WAN2 action=masquerade comment=WAN2
/ip firewall mangle add chain=prerouting dst-address=$"gateway-address" action=accept in-interface=bridge comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=WAN1 connection-mark=no-mark action=mark-connection new-connection-mark=WAN1_conn comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=WAN2 connection-mark=no-mark action=mark-connection new-connection-mark=WAN2_conn comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=bridge connection-mark=no-mark dst-address-type=!local protocol=tcp dst-port=22,80,443 per-connection-classifier=both-addresses:2/0 action=mark-connection new-connection-mark=WAN1_conn comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=bridge connection-mark=no-mark dst-address-type=!local protocol=tcp dst-port=22,80,443 per-connection-classifier=both-addresses:2/1 action=mark-connection new-connection-mark=WAN2_conn comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=bridge connection-mark=no-mark dst-address-type=!local per-connection-classifier=both-addresses-and-ports:2/0 action=mark-connection new-connection-mark=WAN1_conn comment=WAN2
/ip firewall mangle add chain=prerouting in-interface=bridge connection-mark=no-mark dst-address-type=!local per-connection-classifier=both-addresses-and-ports:2/1 action=mark-connection new-connection-mark=WAN2_conn comment=WAN2
/ip firewall mangle add chain=prerouting connection-mark=WAN1_conn in-interface=bridge action=mark-routing new-routing-mark=WAN1_out comment=WAN2
/ip firewall mangle add chain=prerouting connection-mark=WAN2_conn in-interface=bridge action=mark-routing new-routing-mark=WAN2_out comment=WAN2
/ip firewall mangle add chain=output connection-mark=WAN1_conn action=mark-routing new-routing-mark=WAN1_out comment=WAN2
/ip firewall mangle add chain=output connection-mark=WAN2_conn action=mark-routing new-routing-mark=WAN2_out comment=WAN2
/ip route add gateway=$"gateway-address" routing-mark=WAN2_out check-gateway=ping comment=WAN2
/ip route add gateway=$"gateway-address" distance=2 check-gateway=ping comment=WAN2
} else={
:if ($count > 1) do={
:local test [/ip route find where comment=WAN2]
:if ([/ip route get $test gateway] != $"gateway-address") do={
/ip route set $test gateway=$"gateway-address"
}
:local test2 [/ip firewall mangle find where comment=WAN2]
:if ([/ip firewall mangle get $test2 gateway] != $"gateway-address") do={
/ip route set $test2 gateway=$"gateway-address"
}
} else={
:error "Multiple routes found"
}
}
} else={
/ip route remove [find comment=WAN2]
/ip firewall mangle remove [find comment=WAN2]
/ip firewall nat remove [find comment=WAN2]
}
}

For port 22,80,443 we use “both-addresses” as connection classifier to avoid HTTPS error or other authentication issues. Other ports we use both-addresses-and-ports so we can get maximum speed from both WANs.

If you want to see the official doc of how to configure PCC in RouterOS. Here is the link: https://wiki.mikrotik.com/wiki/Manual:PCC

29 Code Snippets for WordPress Users Set custom DNS servers on Linux with resolv.conf

Comments