OSPF is the routing protocol you are most likely to inherit on an enterprise network, and configuring it on Cisco IOS XE takes about four commands per router. The trick is knowing what those commands actually do, how to prove the protocol is working, and which defaults will bite you later. This guide walks through a complete single-area OSPF configuration on three routers, with every output block captured from a live lab (IOS XE 17.18.2), not invented.
If you are new to OSPF concepts (link-state flooding, areas, the DR/BDR election), start with the OSPF complete guide and come back here for the configuration walkthrough.
The lab topology
Three routers in OSPF area 0. R1 and R2 share a LAN segment through a switch, and each has a separate point-to-point style link to R3. That gives us two things worth seeing: a DR/BDR election on the shared segment, and equal-cost multipath in the routing table.
Et0/0 10.50.13.1/24 (to R3)
Lo0 10.255.1.1/32 · router-id 1.1.1.1
Et0/0 10.50.23.2/24 (to R3)
Lo0 10.255.2.2/32 · router-id 2.2.2.2
Et0/1 10.50.23.3/24 (to R2)
Lo0 10.255.3.3/32 · router-id 3.3.3.3
All addressing is RFC 1918 space. Do not copy the old habit of numbering loopbacks 1.1.1.1/8 in labs: 1.0.0.0/8 is live public address space (Cloudflare lives in it), and lab habits become production habits. Use 10.x.x.x for the addresses and save the N.N.N.N pattern for the router ID, which is a 32-bit identifier, not an address.
Step 1: Start the OSPF process and pin the router ID
R1(config)# router ospf 1
R1(config-router)# router-id 1.1.1.1The process ID (1 here) is locally significant. It does not have to match between routers, though most shops keep it consistent for sanity.
Always set the router ID explicitly. If you skip it, IOS XE picks the highest loopback IP, or failing that the highest interface IP, at the moment the process starts. That means the ID can change after a reload or an interface change, and a changed router ID resets every adjacency. Pin it once and never think about it again.
Step 2: Put interfaces into OSPF
The classic way is network statements under the process. The wildcard mask (inverse of a subnet mask) tells OSPF which interface addresses to match:
R1(config)# router ospf 1
R1(config-router)# network 10.50.13.0 0.0.0.255 area 0
R1(config-router)# network 10.50.100.0 0.0.0.255 area 0
R1(config-router)# network 10.255.1.1 0.0.0.0 area 0A wildcard of 0.0.0.255 matches any interface in that /24. A wildcard of 0.0.0.0 matches exactly one address, which is the precise way to grab a loopback. The network command does not advertise "the network"; it enables OSPF on any interface whose address falls in the range, and OSPF then advertises whatever prefix that interface carries.
The modern alternative does the same thing per interface, and many teams prefer it because the intent is visible right where the interface is configured:
R1(config)# interface Ethernet0/0
R1(config-if)# ip ospf 1 area 0Both approaches produce identical behavior. Pick one style per network and stay consistent. R2 and R3 get the mirror-image configuration with their own networks and router IDs.
Step 3: Verify the neighbors
This is the first command to run after any OSPF change:
R1# show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
2.2.2.2 1 FULL/DR 00:00:34 10.50.100.3 Ethernet0/1
3.3.3.3 1 FULL/DR 00:00:38 10.50.13.3 Ethernet0/0FULL means the databases are synchronized: this is the state you want with the DR and BDR, or with any neighbor on a point-to-point link. The suffix after the slash is the neighbor's role on that segment. Here R2 (2.2.2.2) won the DR election on the LAN, and R3 is DR on the R1-R3 link (every multi-access Ethernet segment elects a DR, even one with only two routers on it).
The syslog trail tells you when an adjacency actually formed, and it is worth learning to read:
*Aug 24 00:38:53.134: %OSPF-5-ADJCHG: Process 1, Nbr 2.2.2.2 on Ethernet0/1 from LOADING to FULL, Loading Done
*Aug 24 00:38:56.058: %OSPF-5-ADJCHG: Process 1, Nbr 3.3.3.3 on Ethernet0/0 from LOADING to FULL, Loading DoneStep 4: Verify the routes
R1# show ip route ospf
10.0.0.0/8 is variably subnetted, 8 subnets, 2 masks
O 10.50.23.0/24 [110/20] via 10.50.100.3, 00:00:38, Ethernet0/1
[110/20] via 10.50.13.3, 00:00:38, Ethernet0/0
O 10.255.2.2/32 [110/11] via 10.50.100.3, 00:00:41, Ethernet0/1
O 10.255.3.3/32 [110/11] via 10.50.13.3, 00:00:38, Ethernet0/0Three things to read off this output. The [110/20] pair is administrative distance (110, OSPF's default) and the OSPF cost of the path (20: two 10-cost Ethernet hops). The 10.50.23.0/24 entry has two next hops because R1 has two equal-cost paths to that subnet (via the LAN and via R3), so OSPF installed both: that is equal-cost multipath working with zero extra configuration. And the loopbacks show up as /32 host routes, which is OSPF's default treatment of loopback interfaces regardless of their configured mask.
End-to-end proof, sourced from the loopback so the reply also tests the return path:
R1# ping 10.255.3.3 source Loopback0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 10.255.3.3, timeout is 2 seconds:
Packet sent with a source address of 10.255.1.1
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/3 msStep 5: Read the interface detail
When something is off, this is where the answers live:
R1# show ip ospf interface Ethernet0/1
Ethernet0/1 is up, line protocol is up
Internet Address 10.50.100.2/24, Interface ID 3, Area 0
Attached via Network Statement
Process ID 1, Router ID 1.1.1.1, Network Type BROADCAST, Cost: 10
Transmit Delay is 1 sec, State BDR, Priority 1
Designated Router (ID) 2.2.2.2, Interface address 10.50.100.3
Backup Designated router (ID) 1.1.1.1, Interface address 10.50.100.2
Timer intervals configured, Hello 10, Dead 40, Wait 40, Retransmit 5
Hello due in 00:00:04
Neighbor Count is 1, Adjacent neighbor count is 1
Adjacent with neighbor 2.2.2.2 (Designated Router)The fields that matter for troubleshooting: Area, Network Type, Cost, and the Hello/Dead timers. Hello and Dead must match between neighbors or the adjacency never forms (10 and 40 seconds are the broadcast-network defaults). The area must match on both ends of the link. And note "Attached via Network Statement", which tells you exactly which configuration method enabled OSPF here.
Step 6: Two defaults worth changing
Passive-interface on user-facing ports
Any interface running OSPF sends Hellos and will happily form an adjacency with whatever answers. On segments with no legitimate OSPF neighbor (user VLANs, server LANs), make the interface passive: OSPF still advertises the subnet but stops sending Hellos on it.
R1(config)# router ospf 1
R1(config-router)# passive-interface default
R1(config-router)# no passive-interface Ethernet0/0
R1(config-router)# no passive-interface Ethernet0/1passive-interface default flips the model to deny-by-default, which is the safer posture: new interfaces stay passive until you deliberately enable them.
Reference bandwidth
OSPF cost is reference bandwidth divided by interface bandwidth, and the default reference is antique:
R3# show ip ospf | include Routing Process|Reference
Routing Process "ospf 1" with ID 3.3.3.3
Reference bandwidth unit is 100 mbpsWith a 100 Mbps reference, every link from FastEthernet up to 400 Gigabit gets the same cost. Raise it on every router in the domain (consistently, or path selection goes sideways):
R1(config-router)# auto-cost reference-bandwidth 100000That sets the reference to 100 Gbps. The full story on cost tuning is in OSPF metric and cost calculation.
Step 7: The database and the protocol summary
Two more verification commands complete the picture. The database view shows one router LSA per router and one network LSA per DR segment, which is exactly what a healthy three-router area 0 should hold:
R1# show ip ospf database
OSPF Router with ID (1.1.1.1) (Process ID 1)
Router Link States (Area 0)
Link ID ADV Router Age Seq# Checksum Link count
1.1.1.1 1.1.1.1 46 0x80000006 0x0062A7 3
2.2.2.2 2.2.2.2 44 0x80000006 0x0028C1 3
3.3.3.3 3.3.3.3 39 0x80000006 0x00721B 3
Net Link States (Area 0)
Link ID ADV Router Age Seq# Checksum
10.50.13.3 3.3.3.3 54 0x80000001 0x00537E
10.50.23.3 3.3.3.3 54 0x80000001 0x0017AC
10.50.100.3 2.2.2.2 57 0x80000001 0x008EF3And show ip protocols confirms what OSPF thinks it is configured to do, which is not always what you think you configured:
R1# show ip protocols
Routing Protocol is "ospf 1"
Router ID 1.1.1.1
Number of areas in this router is 1. 1 normal 0 stub 0 nssa
Maximum path: 4
Routing for Networks:
10.50.13.0 0.0.0.255 area 0
10.50.100.0 0.0.0.255 area 0
10.255.1.1 0.0.0.0 area 0
Routing Information Sources:
Gateway Distance Last Update
3.3.3.3 110 00:00:53
2.2.2.2 110 00:00:56
Distance: (default is 110)When the adjacency does not form
The short version of OSPF troubleshooting, in the order the failures actually occur:
Here is what a real dead-timer failure looks like in the log, captured by breaking the R1-R3 link in the lab:
*Aug 24 00:47:36.530: %OSPF-5-ADJCHG: Process 1, Nbr 3.3.3.3 on Ethernet0/0 from FULL to DOWN, Neighbor Down: Dead timer expiredFor the full state-by-state breakdown, see OSPF neighbor states explained.
Command summary
Key takeaways
A working single-area OSPF deployment is four commands per router: process, router ID, and network statements (or per-interface enablement). Verification is three commands: neighbors, routes, interface detail. The defaults to fix on day one are the router ID (pin it), passive-interface (deny by default), and reference bandwidth (raise it everywhere, consistently). Everything in this guide was captured from live IOS XE 17.18.2 routers, and every behavior described is one you can reproduce in a free CML lab with three nodes.
Next steps in the cluster: neighbor states for troubleshooting depth, cost calculation for path control, and the OSPF cheat sheet for the quick reference. The whole map lives in the OSPF complete guide.