This example setup for RouterOS 7.22 configures a MikroTik router as a PPPoE offloader. The router establishes a connection to a PPPoE server (e. g. over GPON or DSL), acquires an IPv4 address and an IPv6 prefix and delegates these to a downstream firewall via DHCP. The MikroTik device acts purely as a router, it has no firewall / NAT rules.
This is motivated by wanting a basic IP over Ethernet connection for the WAN interface of the main firewall (e. g. OPNsense). Specific hardware and protocols required for the WAN uplink are handled by the MikroTik device. RouterOS is known to have a robust PPPoE implementation.
It is assumed that the router has no default configuration like bridges, firewall rules etc.:
/system/reset-configuration no-defaults=yes
Interfaces used in this example:
- sfp1 is the upstream interface (used for establishing the PPPoE connection)
- ether1 is the downstream interface (connects to the WAN interface of the firewall)
- ether2 is a dedicated management interface
You can of course use bridges, VLANs etc. instead.
I currently (2025 / 2026) use this in production with a hEX S (RB760iGS) which is equipped with a GPON ONT SFP.
/ip/vrf/add interfaces=ether2 name=management
Configure the management interface layer 3 settings to your liking (IP addresses, routes, ...).
We don't want any RouterOS services exposed to the WAN.
/ip/neighbor/discovery-settings/set discover-interface-list=none
/ip/service
set ftp disabled=yes
set ssh vrf=management
set telnet disabled=yes
[...]
Use dummy addresses for now, these will later be set dynamically.
/ip/address/add interface=ether1 address=203.0.113.26/30
/ipv6/address/add interface=ether1 address=2001:db8::1
SLAAC doesn't work particularly well with some firewalls, so don't set the A flag in Router Advertisements:
/ipv6/nd/prefix/default set autonomous=no
These will delegate the IPv4 address and the delegated IPv6 prefix to the downstream firewall.
Use dummy addresses for now, these will later be set dynamically.
/ip/pool/add name=wan ranges=203.0.113.25
/ip/dhcp-server/add name=wan interface=ether1 address-pool=wan lease-time=2m
/ip/dhcp-server/network/add comment="WAN" address=203.0.113.24/30 gateway=203.0.113.26
/ipv6/dhcp-server/add name=wan interface=ether1 prefix-pool=wan lease-time=2m
/ipv6/nd/set [ find default=yes ] interface=ether1 managed-address-configuration=yes other-configuration=yes mtu=1492
My ISP requires VLAN 7. If yours doesn't, skip the VLAN creation and add the PPPoE client directly to an Ethernet interface.
/interface/vlan/add name=sfp1vlan7 interface=sfp1 vlan-id=7
/interface/pppoe-client/add name=pppoe interface=sfp1vlan7 add-default-route=yes use-peer-dns=yes disabled=no user=example password=****
/ipv6/dhcp-client/add interface=pppoe request=prefix pool-name=wan pool-prefix-length=56
We delegate the entire delegated prefix to the downstream firewall, so set pool-prefix-length to the size of the PD you get from your ISP.
This is where the magic happens. Add this script to the DHCPv6 client so it gets executed whenever we get a new lease from upstream (/ipv6/dhcp-client/set script="..."):
:if ($"pd-valid" = 1) do={
:local wanAddr4 ([/interface/pppoe-client/monitor pppoe as-value once] -> "local-address");
:local mask4 1;
:local netAddr4;
:local bcastAddr4;
:local gatewayAddr4;
:do {
:set mask4 ($mask4 + 1);
:set netAddr4 (($wanAddr4 >> $mask4) << $mask4);
:set bcastAddr4 ($netAddr4 + (1 << $mask4) - 1);
} while=(($wanAddr4 = $netAddr4) || ($wanAddr4 = $bcastAddr4));
:set gatewayAddr4 ($netAddr4 + 1);
:if ($gatewayAddr4 = $wanAddr4) do={:set gatewayAddr4 ($bcastAddr4 - 1)};
/ip/address/remove [find interface=pppoe]
/ip/address/set [find interface=ether1] address="$gatewayAddr4/$(32 - $mask4)"
/ip/dhcp-server/network/set [find comment="WAN"] address="$netAddr4/$(32 - $mask4)" gateway=$gatewayAddr4
/ip/pool/set wan ranges=$wanAddr4
/ipv6/address/set [find interface=ether1 global=yes] address=([:pick $"pd-prefix" 0 [:find $"pd-prefix" "/"]] . "1/64")
}
For IPv4, the script calculates the smallest possible subnet which fits the PPPoE IPv4 address wanAddr4 as well as a second address.
This second address gatewayAddr4 is the first address in the subnet, except when wanAddr4 is the first address. Then gatewayAddr4 is the last address in the subnet.
It then removes the wanAddr4 from the PPPoE interface.
After adding the gatewayAddr4 to the downstream interface, it reconfigures the DHCPv4 server to delegate the wanAddr4 to the downstream firewall, along with the matching gateway gatewayAddr4.
For IPv6, it sets the IPv6 address of the downstream interface by merging the delegated prefix with ::1. This means the first /64 subnet of the delegated prefix is used for the link to the downstream firewall. The firewall must not use this subnet for other interfaces, but it can use it to generate a WAN address. For OPNsense, that's Optional prefix ID 0x0 and an Optional interface ID of your choice (e. g. 0x2).