IPv6 adoption has accelerated as IPv4 address exhaustion becomes more acute, and most modern Linux servers must support both protocols simultaneously in a dual-stack configuration. RHEL 8 ships with full IPv6 support in the kernel and in NetworkManager, making dual-stack setup straightforward with nmcli. Firewalld and the major web servers handle IPv6 natively once the interface is configured. This tutorial covers configuring a dual-stack interface, updating web server listeners, adjusting firewall rules, and validating end-to-end connectivity.

Prerequisites

  • RHEL 8 server with a network interface managed by NetworkManager
  • A routable IPv6 address or prefix delegation from your ISP or hosting provider
  • Nginx or Apache installed
  • Root or sudo access
  • iputils package installed for ping6

Step 1 — Assign an IPv6 Address with nmcli

Add a static IPv6 address to your existing connection profile alongside the IPv4 configuration. Substitute ens3, the address, gateway, and DNS with values appropriate to your environment.

# Show current connections
nmcli connection show

# Add a static IPv6 address to the connection (replace ens3 and addresses)
nmcli connection modify ens3 
  ipv6.method manual 
  ipv6.addresses "2001:db8::10/64" 
  ipv6.gateway "2001:db8::1" 
  ipv6.dns "2606:4700:4700::1111,2606:4700:4700::1001"

# Bring the connection down and up to apply changes
nmcli connection down ens3 && nmcli connection up ens3

# Confirm both addresses are assigned
ip addr show ens3

Step 2 — Configure SLAAC or DHCPv6 (Optional)

If your network router advertises prefixes via Router Advertisements, you can use SLAAC instead of a static address. DHCPv6 is available as an alternative when a DHCPv6 server is present.

# Use SLAAC (Stateless Address Autoconfiguration)
nmcli connection modify ens3 ipv6.method auto

# Use DHCPv6 stateful
nmcli connection modify ens3 ipv6.method dhcp

# Re-apply
nmcli connection down ens3 && nmcli connection up ens3

# Check assigned addresses
ip -6 addr show ens3

Step 3 — Enable IPv6 Privacy Extensions

Privacy extensions (RFC 4941) generate temporary IPv6 addresses that rotate over time, reducing client-side tracking. Enable them via sysctl for outbound connections.

# Enable privacy extensions immediately
sysctl -w net.ipv6.conf.all.use_tempaddr=2
sysctl -w net.ipv6.conf.default.use_tempaddr=2

# Make the setting persistent
echo "net.ipv6.conf.all.use_tempaddr=2" >> /etc/sysctl.d/60-ipv6-privacy.conf
echo "net.ipv6.conf.default.use_tempaddr=2" >> /etc/sysctl.d/60-ipv6-privacy.conf
sysctl --system

Step 4 — Update Nginx or Apache to Listen on IPv6

Web servers must explicitly bind to the IPv6 wildcard address :: (or a specific IPv6 address) to accept IPv6 connections.

# Nginx — add IPv6 listen directive to your server block
# /etc/nginx/conf.d/default.conf
#   listen 80;
#   listen [::]:80;        # IPv6
#   listen 443 ssl;
#   listen [::]:443 ssl;   # IPv6 HTTPS

# Apply and reload
nginx -t && systemctl reload nginx

# Apache — ensure mod_ssl and IPv6 listen directives are present
# /etc/httpd/conf/httpd.conf
#   Listen 80
#   Listen [::]:80        # IPv6

# /etc/httpd/conf.d/ssl.conf
#   Listen [::]:443 https

apachectl configtest && systemctl reload httpd

Step 5 — Configure Firewalld IPv6 Rules

Firewalld supports IPv6 natively. Standard service rules apply to both address families; dedicated IPv6 rules can be added where required.

# Ensure HTTP and HTTPS are allowed (applies to both IPv4 and IPv6)
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# Allow ICMPv6 (required for Neighbor Discovery and path MTU)
firewall-cmd --permanent --add-service=dhcpv6-client
firewall-cmd --permanent --zone=public --add-icmp-block-inversion
firewall-cmd --permanent --zone=public --add-icmp-block=redirect

# Add a direct IPv6-only rule if needed (example: allow port 8080 IPv6)
firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 
  -p tcp --dport 8080 -j ACCEPT

firewall-cmd --reload
firewall-cmd --list-all

Step 6 — Test Dual-Stack Connectivity

Verify reachability over both protocols using ping6 and curl before going live.

# Ping the IPv6 gateway
ping6 -c 4 2001:db8::1

# Ping an external IPv6 host
ping6 -c 4 2606:4700:4700::1111

# Force curl to use IPv6
curl -6 -I http://domain.com
curl -6 -I https://domain.com

# Verify both address families resolve for your domain
host domain.com        # shows A record
host -t AAAA domain.com  # shows AAAA record

# Check which address the OS prefers for outbound connections
ip -6 route show

Conclusion

Your RHEL 8 server is now running a full dual-stack configuration, accepting and routing both IPv4 and IPv6 traffic. NetworkManager handles address assignment via static configuration, SLAAC, or DHCPv6; Nginx and Apache listen on the IPv6 wildcard; and firewalld enforces consistent rules across both address families. Privacy extensions are enabled to reduce client-side address tracking on outbound connections.

Next steps: How to Configure an IPv6-Only VPS on RHEL 8, How to Set Up DNS AAAA Records and IPv6 Reverse DNS on RHEL 8, and How to Tune MTU and Path MTU Discovery for IPv6 on RHEL 8.