PPP HOWTO: PPPoE for DSL and fiber, and PPP over serial today

Updated November 2026

PPP (the Point-to-Point Protocol) is still how many DSL and fiber providers hand out connections: your router or Linux box runs PPP over Ethernet (PPPoE) and logs in with a user name and password. This page shows how to do that with NetworkManager or plain pppd, how to deal with VLAN tags and the smaller MTU, and how to run PPP over a serial line.

The classic PPP-HOWTO (modem dial-up, kernel 2.2) and the ADSL and DSL HOWTOs are kept by the Linux Documentation Project; the PPP-HOWTO is at tldp.org. This page replaces them for current systems.

How PPPoE works

PPPoE (RFC 2516) has two stages. In discovery, your machine broadcasts a PADI packet on the Ethernet link; the provider's access concentrators answer with PADO; your machine picks one with PADR and gets a session number in PADS. In the session stage, ordinary PPP runs inside Ethernet frames: it authenticates you (PAP or CHAP), then IPCP and IPv6CP hand out addresses. Either side ends the session with PADT.

The PPPoE header takes 6 bytes and the PPP protocol field 2 more, so the largest IP packet is 1500 − 6 − 2 = 1492 bytes. That number matters, as you will see below.

IP (≤1492 bytes) PPP (2) PPPoE (6) VLAN tag? Ethernet
Each layer wraps the one to its left. The 8 bytes of PPP and PPPoE headers are why the MTU drops from 1500 to 1492.

What you need from the provider

Your DSL modem or ONT must be in "bridge" mode, so that it passes PPPoE through instead of dialing itself.

PPPoE with NetworkManager

On desktops and most servers that use NetworkManager, one command creates the profile. Without a VLAN:

sudo nmcli connection add type pppoe con-name wan ifname enp1s0 \
    pppoe.username 'name@provider' pppoe.password 'secret'
sudo nmcli connection up wan

With a VLAN tag (here VLAN 7 — use your provider's number), create the VLAN interface first and run PPPoE on top of it with pppoe.parent:

sudo nmcli connection add type vlan con-name wan-vlan ifname enp1s0.7 dev enp1s0 id 7 \
    ipv4.method disabled ipv6.method disabled
sudo nmcli connection add type pppoe con-name wan ifname ppp0 pppoe.parent enp1s0.7 \
    pppoe.username 'name@provider' pppoe.password 'secret'
sudo nmcli connection up wan

Leave pppoe.service empty unless the provider gives you a service name. To detect a dead line faster, set ppp.lcp-echo-interval 20 and ppp.lcp-echo-failure 3 (the second only works together with the first). Check the result:

nmcli device status
ip addr show ppp0
ip route              # default route via ppp0
journalctl -b | grep -i pppd

NetworkManager starts pppd with its own plugin, so the logs say pppd even though you never wrote a pppd configuration.

PPPoE with pppd directly

On a router or minimal server without NetworkManager, use pppd from the ppp package (as of November 2026: 2.5.2 in Debian 13 and Ubuntu 26.04, 2.4.9 in Ubuntu 24.04; the latest upstream release is 2.5.5). PPPoE support is a plugin built into the package, pppoe.so; releases before 2.4.9 called it rp-pppoe.so. It uses the kernel's PPPoE driver, so no separate user-space daemon is needed.

First check that the provider answers at all. pppoe-discovery sends PADI and lists the access concentrators that reply, without starting a session:

sudo ip link set enp1s0 up
sudo pppoe-discovery -I enp1s0

Create the peer file /etc/ppp/peers/wan:

plugin pppoe.so
nic-enp1s0
user "name@provider"
noauth
hide-password
defaultroute
replacedefaultroute
usepeerdns
+ipv6
persist
maxfail 0
holdoff 10
lcp-echo-interval 20
lcp-echo-failure 3
mtu 1492
mru 1492
noipdefault

For a VLAN, create the VLAN interface (sudo ip link add link enp1s0 name enp1s0.7 type vlan id 7, then sudo ip link set enp1s0.7 up, and make it permanent in your network configuration) and use nic-enp1s0.7.

Put the password in /etc/ppp/chap-secrets and /etc/ppp/pap-secrets, because you do not know in advance which method the provider will choose. The fields are client, server, secret and allowed addresses:

# client            server  secret    IP addresses
"name@provider"     *       "secret"  *
sudo chmod 600 /etc/ppp/chap-secrets /etc/ppp/pap-secrets

Start it in the foreground the first time, with debugging, so you see every step:

sudo pppd call wan nodetach debug

When it works, stop it with Ctrl-C and start it in the background with sudo pppd call wan. On Debian and Ubuntu, sudo pon wan and sudo poff wan do the same, and plog shows the last log lines. To start at boot on Debian, add a stanza to /etc/network/interfaces (auto wan, iface wan inet ppp, provider wan) or write a small systemd unit that runs /usr/sbin/pppd call wan nodetach.

About the route options: defaultroute adds a default route through the peer only if none exists yet; replacedefaultroute lets it replace an existing one. usepeerdns asks for up to two DNS servers and writes them to /etc/ppp/resolv.conf; with systemd-resolved, hook them in from a script in /etc/ppp/ip-up.d/ or set DNS servers yourself.

The MTU problem and MSS clamping

Hosts on your LAN use an MTU of 1500. When they open a TCP connection through a 1492-byte PPPoE link, large packets must be fragmented or rejected, and if ICMP "fragmentation needed" messages are filtered somewhere, connections hang: the page starts loading and then stalls. The standard fix on the router is to clamp the TCP maximum segment size to the route MTU. In nftables, in the forward chain of your firewall:

table inet filter {
    chain forward {
        type filter hook forward priority filter; policy accept;
        oifname "ppp0" tcp flags syn tcp option maxseg size set rt mtu
    }
}

Merge the rule into your existing ruleset rather than loading this table on its own with a policy you did not plan; see the Firewall HOWTO. If your provider supports RFC 4638 and your Ethernet path carries frames slightly larger than normal, you can negotiate a 1500-byte PPP MTU instead, but 1492 always works.

PPP still connects two machines over a null-modem cable, a radio modem or an out-of-band console line. On the first machine:

sudo pppd /dev/ttyS0 115200 10.0.0.1:10.0.0.2 crtscts local lock noauth nodetach

And on the second machine, the addresses reversed:

sudo pppd /dev/ttyS0 115200 10.0.0.2:10.0.0.1 crtscts local lock noauth nodetach

local ignores the modem control lines (there is no carrier on a plain cable), crtscts turns on hardware flow control (leave it out if your cable lacks RTS/CTS), and lock creates a lock file so no other program opens the port. Use noauth only on a cable you control; on anything reachable by others, set require-chap and a secret in chap-secrets. For dial-up through a modem, add connect "/usr/sbin/chat -v -f /etc/chatscripts/dialup" and use the modem's device; see the Modem HOWTO.

Troubleshooting

No PADO / "Timeout waiting for PADO packets"
Nothing answers the discovery broadcast. Check the cable and the interface name, that the modem or ONT is in bridge mode, and the VLAN number. pppoe-discovery is the quickest test.
Authentication failed
Wrong user name or password, or the secret is in only one of the two secrets files. Look for "PAP authentication failed" or "CHAP authentication failed" in the log.
Connected, but no Internet
Check ip route: if another default route already existed and you did not use replacedefaultroute, traffic still goes the old way. Then check DNS.
Some web sites hang, others work
The MTU problem. Add MSS clamping on the router.
Link drops after some hours
Many providers force a reconnect daily. persist and maxfail 0 (or NetworkManager's autoconnect) bring it back; the LCP echo options detect a dead link.

Where to look: pppd logs to syslog with facility daemon, so journalctl -b -t pppd or journalctl -b | grep pppd shows the whole negotiation when debug is set. To share the connection with your LAN, continue with the IP Masquerade HOWTO.

Sources