From SME Server
Jump to navigationJump to search

IPv6 implementation on Koozali SME Server

Some notes on how we can implement IPv6 on Koozali SME Server

This is a massive task and needs careful consideration and a lot of work.

Initial bug: https://bugs.koozali.org/show_bug.cgi?id=6393

Feel free to add notes and comments.

Warning.png Warning:
Code below is highly experimental. Do NOT try it on a production server.


As IPv4 address availability has decreased, the world is slowly starting to use IPv6.

A fundamental block to adoption of IPv6 has been the lack of backwards compatibility. Yes, you could go full IPv6 only, assuming all your devices can handle it, but as most of the world still runs IPv4 you have to manage that.

Essentially every service and app has to be written to allow for both IPv4 AND IPv6. aka 'Dual Stack'.

That means duplicating a lot of work, and due to the nature of IPv6 - it was not designed to handle NAT, and every device is meant to have a routable public IP - this means added complexity and security considerations. That makes it more difficult for Koozali in Server/Gateway mode.

Carriers have found it easier to use CGNAT - double NAT - than deal with the issue of rolling out IPv6.

Some countries have rolled IPv6 out, some are in the process, and many have not at all.

Even where IPv6 has been rolled out, not all ISPs offer it.

IPv6 has been around for 25 years and is still a very long way from widespread adoption. It may well be another 25 years before the world is fully IPv6, and IPv4 will still exist for a long time come thereafter.

List of areas to be considered

Config entries

There are a couple of instances where a key is already used:

config show IPv6

We should use this as the basis for IPv6 settings.

IP addresses

I have no IPv6 from my provider so set up a 6to4 tunnel account with Hurricane:


You can set up a free account and obtain a /64block

The following testing was done with a server in server only mode as this is the easier scenario.

My server is behind a Mikrotik router. I first set up the Mikrotik to handle the IPv6. Then I worked on the server.

The server will pick up an IPv6 address automatically from the tunnel via the router. It will need further configuration for SME to handle the tunnel instead of the router. However, this is sufficient for basic testing.

Remember that IPv6 address are public facing. I have not done any work on firewalling.

Some other brief thoughts:

  • Tunneled 6to4
  • Native IPv6 block from ISP
  • DHCP/DNS in Koozali
  • Routed using public IP and private address space?

Enable networking

Warning.png Warning:
Code below is highly experimental. TESTING ONLY. Do NOT try it on a production server as you will almost certainly get hacked

IPv6 currently disabled.

Get your Gateway IP "Server IPv6 Address:" and set it here:


This seems to get it started:

mkdir -p /etc/e-smith/templates-custom/etc/sysctl.conf
nano /etc/e-smith/templates-custom/etc/sysctl.conf/net.ipv6
   if ( ($IPv6{status} || 'disabled') ne "enabled" ) {
       $OUT .= "# IPv6 is disabled\n";
       $OUT .= "net.ipv6.conf.all.disable_ipv6 = 1\n";
       $OUT .= "net.ipv6.conf.default.disable_ipv6 = 1\n";
   else {
       $OUT .= "# IPv6 is enabled\n";
       $OUT .= "net.ipv6.conf.all.disable_ipv6 = 0\n";
       $OUT .= "net.ipv6.conf.default.disable_ipv6 = 0\n";
mkdir -p /etc/e-smith/templates-custom/etc/sysconfig/network-scripts/ifcfg-ethX
nano /etc/e-smith/templates-custom/etc/sysconfig/network-scripts/ifcfg-ethX/60IPV6
if ($IPv6{'status'} eq "enabled") {
   $OUT .= "IPV6INIT=yes";
   $OUT .= "IPV6_AUTOCONF=yes";
   $OUT .= "IPV6_DEFROUTE=yes";
   $OUT .= "IPV6_PEERROUTES=yes";
   $OUT .= "IPV6_FAILURE_FATAL=yes";
   $OUT .= "DNS0=2001:4860:4860::8888"; # Google DNS - you may want to change them!!
   $OUT .= "IPV6_PRIVACY=no";
   } else {
   return "IPV6INIT=no";
mkdir -p /etc/e-smith/templates-custom/etc/sysconfig/network-scripts/route-ethX
nano /etc/e-smith/templates-custom/etc/sysconfig/network-scripts/route-ethX/08Gateway
   return "" unless (defined $GatewayIP && (
                       ($SystemMode eq 'serveronly' && $InternalInterface{Name} eq $THIS_DEVICE ) ||
                       ($ExternalInterface{Name} eq $THIS_DEVICE) ));
   $OUT .= "$GatewayIP dev $THIS_DEVICE\n";
   $OUT .= "default via $GatewayIP dev $THIS_DEVICE\n";
   if ($IPv6{'status'} eq "enabled") {
       $OUT .= "$IPv6{'Gateway' dev $THIS_DEVICE\n";
       $OUT .= "default via $IPv6{'Gateway'} dev $THIS_DEVICE\n";

Warning.png Warning:
If you run the following command your server will have a public IP and NO firewall. You have been warned

signal-event post-upgrade;signal-event reboot.

You should get an automatic IP assigned from your Hurricane pool.

ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
   link/ether ca:94:35:c2:d6:e1 brd ff:ff:ff:ff:ff:ff
   inet brd scope global eth0
      valid_lft forever preferred_lft forever
   inet6 2001:470:79c1:5ff:c894:35ff:fec2:d6e1/64 scope global mngtmpaddr dynamic 
      valid_lft 2591951sec preferred_lft 604751sec
   inet6 fe80::c894:35ff:fec2:d6e1/64 scope link 
      valid_lft forever preferred_lft forever

Try a ping6

ping6 ipv6.google.com
PING ipv6.google.com(mad06s10-in-x0e.1e100.net (2a00:1450:4003:808::200e)) 56 data bytes
64 bytes from mad06s10-in-x0e.1e100.net (2a00:1450:4003:808::200e): icmp_seq=1 ttl=117 time=56.2 ms
64 bytes from mad06s10-in-x0e.1e100.net (2a00:1450:4003:808::200e): icmp_seq=2 ttl=117 time=55.5 ms

See the bug for some more templates that we might be able to use.






DNS (PiHole in a docker container?)


List of other affected services and vague efforts to get IPv6 running for them.




mysql (already listens for tcp6/3313)

ntpd (already listens on udp6/123)

sshd as below

ldap as below

=====SSH===== (bad hack here so careful as this may open your server up to remote access)

mkdir /etc/e-smith/templates-custom/etc/ssh/sshd_config
nano /etc/e-smith/templates-custom/etc/ssh/sshd_config/15ListenAddress
   my $access = $sshd{'access'} || 'private';
   my $address = ($access eq "public") ? "" : "$LocalIP";
   # Not sure how we allow for 'Local IP only' with IPv6
   # Possibly limit it to the local subnet?
   if ($IPv6{status} eq "enabled") { 
       $OUT .= "ListenAddress ::\n";
       $OUT .= "ListenAddress $address\n";
   } else {
       $OUT .= "ListenAddress $address\n";
signal-event remoteaccess-update

Then try:

ssh root@2001:470:1f13:3ff:2a9:b700:fe99:792c
mkdir -p /etc/e-smith/templates-custom/etc/sysconfig/slapd
nano /etc/e-smith/templates-custom/etc/sysconfig/slapd/40OPTIONS

Add this code:

# Any custom options
#SLAPD_OPTIONS=" -4 -d { $ldap{LogLevel} || 256 } -s 0 "
my $slapdOptions = "#Test";
my $logLevel = $ldap{LogLevel} || 256;
if ($IPv6{'status'} eq "enabled") {
    $slapdOptions = "SLAPD_OPTIONS=\"-d  $logLevel -s 0\" " ;
    } else {
    $slapdOptions = "SLAPD_OPTIONS=\"-4 -d $logLevel -s 0\" " ;
$OUT .= "# Any custom options\n";
$OUT .= "$slapdOptions\n";

Edited the unit file /usr/lib/systemd/system/ldap.service to comment out the Environment line and just leave the config file

#Environment="SLAPD_URLS=ldap:/// ldaps:/// ldapi:///" "SLAPD_OPTIONS=-4 -d 256 -s 0"
systemctl daemon-reload
systemctl restart ldap.service

However, /usr/sbin/cpu is not IPv6 aware and is unmaintained.

We can bypass this and force IPv4 by editing:


Modify the template and change localhost to

LDAP_HOST       =
LDAP_PORT       = 389

Other notes

Use in a web browser



ping6 2001:470:1f13:3ff:2a9:b700:fe99:792c