Going back to first principles might clarify things a little.
The classes of ipv6 addresses are identified by the first (left hand) block of four hex digits of the ipv6 address. An identifying block such as this is the first block of the prefix. A prefix is 3 blocks long.
In the context of this thread, the important classes are as follows:
- Global Unicast Addresses (GUA) - Fully route-able public/registered addresses. Valid anywhere.
The first block of the prefix must be in the range of 2000 to 3fff (although I don't think any have yet been allocated in the 3xxx range). Supplied from upstream, no local control, can (and often does) change at the whim of the ISP.
- Unique Local Unicast (ULA) - Locally route-able unregistered private addresses. Valid on locally routed networks (eg corporate sites linked by private backhaul). Should be blocked from the Internet by ISPs, but if not, it does not matter because there are no routes for this class of unregistered addresses in the Internet backhaul. Generated locally so is fully controllable and persistent.
The first block of the prefix must be in the range of fc00 to fdff.
- Link Local Unicast (LLA) - Non route-able local address, always associated with a network interface on the host. Reserved for host to host communications on the same layer 2 local area network. Often blocked by layer 3 user-applications eg browsers. Auto generated by the host.
So for you to get a reliable static address for your in house local servers, ULA is the way forward.
An aside -DHCP vs SLAAC:
In the context of an ipv6 network, the intention is for SLAAC to provide the actual addresses for hosts and DHCP to provide a means of distributing networking parameters/options.
But, confusingly, DHCP6 can also distribute ip addresses, resulting in the duplication usually seen.
Potential problems with this in hosts are mitigated by ignoring the DHCP6 provided address (Android being the strictest)
The host generates it based on what the router advertises.
The router has the following config options:
- network.globals.ula_prefix (full three blocks of four hex digits as described above. This is generated randomly on first boot, but can also be set to specific values.
- network.lan.ip6hint. This is a fourth block of four hex digits. This is the sub-prefix (or ipv6 ULA subnet). Defaults to 0000 and auto increments by one for each configured "lan" if not specified.
The router periodically sends Router Announcements (RA) to inform hosts of the prefix and sub-prefix.
Hosts can also send Router Solicitations (RS), so they don't have to wait for the next RA to come from the router.
Once the host has the ULA prefix/sub-prefix, it then uses its own unique mac address to generate the full ULA.
Real Example (my test current test system):
ULA prefix fd46:cfe5:34c5::/48
ULA sub-prefix (the ip6hint) ddd6
Host mac address 94:83:c4:20:c7:1d
This results in a stable ULA of fd46:cfe5:34c5:ddd6:9483:c4ff:fe20:c71d/64
Here, the first four blocks fd46:cfe5:34c5:ddd6 represent the prefix/sub-prefix part of the address.
The fifth block is the first two octets of the mac address '9483'
The sixth block is the third octet of the mac plus the hex digits ff, giving c4ff
The seventh block is the hex digits fe, plus the fourth octet of the mac address, giving fe20
The eighth block is the last two octets of the mac address.
This will be stable and fixed and can be used by any application (such as browsers, wget, curl etc). In addition, if you know the host mac address, you can work out the host ULA yourself.
It is not the whole story as there are more nuances, but this always applies.
I hope this helps with your problem.