A public IPv4 address is expensive, and it is not always needed. A build server, an agent working in the background, a compute node or a machine you only reach over SSH never wait for IPv4 visitors. For those jobs, every VPS plan now comes in an IPv6-only version, for 2 CAD less per month.
The VM has no public IPv4, yet it still reaches the whole Internet, including the sites that still have no IPv6: GitHub, ghcr.io, plenty of APIs. Here is what you get, how it works, and a demo on a real machine.
1. What changes, what does not
| IPv4 + IPv6 | IPv6 only | |
|---|---|---|
| IPv6 address and routed /64 | yes | yes |
| Public IPv4 | yes | no |
vm-…ffxf.zone name | A + AAAA | AAAA only |
| Outbound access to IPv4 sites | direct | through the NAT64 gateway |
| Reachable from | the whole Internet | IPv6 networks |
| Nano, monthly | 8.50 CAD | 6.50 CAD |
| Nano, hourly | 0.018 CAD | 0.014 CAD |
The discount applies to every plan: 2 CAD a month, 20 CAD a year, and the hourly rate drops in the same proportion. Resources, backups, console, included traffic: everything else is identical. The choice is made at order time, for the life of the machine.
2. Ordering an IPv6-only VM
In the console, the order page has a Network card: pick "IPv6 only". The discount is shown per month, per year or per hour depending on the billing mode.
Through the API, it is one field: "ipv4": false. With
dry_run, the call runs every check and returns the price without
creating anything.
curl -s -X POST "https://api.ffxf.net/v1/vms" \
-H "Authorization: Bearer $FFXF_TOKEN" -H "Idempotency-Key: v6-demo-1" \
-H 'Content-Type: application/json' \
-d '{"plan":"nano","region":"montreal","image":"debian-13",
"hostname":"v6-demo","billing":"hourly","ipv4":false,
"ssh_keys":["SHA256:…"],"password_delivery":"none","dry_run":true}'
The region catalog also reports what is left through its ipv4 and
ipv6 fields. When IPv4 addresses run short, a region turns
limited but still accepts IPv6-only VMs.
3. Demo
A Debian 13 delivered IPv6-only, seen from the inside. It has a single global address and no IPv4 route at all:
$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 2602:f3a4:0:100::fff0/64 fe80::be24:11ff:fea6:616d/64
$ ip -4 route
$
GitHub has no IPv6. Yet the name resolves to an IPv6 address, inside a special
prefix, 64:ff9b::/96:
$ getent ahostsv6 github.com
64:ff9b::8c52:7204 STREAM github.com
The last eight hex digits are GitHub's IPv4: 8c52:7204 is
140.82.114.4. The connection goes through:
$ curl -sI https://github.com | head -1
HTTP/2 200
$ curl -s https://api.ipify.org
23.159.52.25
$ dig +short -x 23.159.52.25
nat64.ffxf.net.
Seen from outside, the VM leaves through the IPv4 address of our gateway,
nat64.ffxf.net. Sites that do have IPv6 are reached directly, with no
detour:
$ curl -s -o /dev/null -w '%{http_code} via %{remote_ip}\n' https://www.google.com
200 via 2001:4860:4827:7700::
System updates, git clone from GitHub, docker pull from
Docker Hub or ghcr.io: it all works. In our tests, a download from GitHub sustained
about 40 MB/s through the gateway. Windows Server and FreeBSD behave the same way:
remote desktop and SSH over IPv6, IPv4 traffic out through the gateway.
4. How it works: DNS64 and NAT64
Two standard mechanisms work together.
-
DNS64. The resolvers set on the VM (Cloudflare's and Google's
DNS64 services) answer normally for a name that has an IPv6 address. For a name
that only has an IPv4, they build an IPv6 address by appending that IPv4 to the
64:ff9b::/96prefix. -
NAT64. Our network sends everything bound for
64:ff9b::/96to a gateway, which translates the packet to IPv4, sends it out from its own address, then translates the reply back.
For the software in the VM, this is invisible: it asks for a name, gets an IPv6 address and connects. There is nothing to configure.
Keep the DNS64 resolvers. If you replace them with a regular
resolver, names without IPv6 will stop resolving and those sites will become
unreachable. To run your own resolver, enable DNS64 on it with the
64:ff9b::/96 prefix.
5. Connecting to the VM
An IPv6-only VM can only be reached from an IPv6 network. Many home connections and mobile networks already are. To check yours:
curl -6 -s https://api64.ipify.org && echo " : IPv6 available"
If nothing is printed, you have three options:
- the KVM console in the browser, which does not go through the VM's network;
- an SSH jump through a machine that has both families:
ssh -J me@bastion debian@vm-xxxxxxxxx.ffxf.zone; - a WireGuard tunnel from another of your machines, as in our guide WireGuard VPN on a VPS.
6. Limits to know about
- No direct IPv4 visitors. A public site hosted on the VM will only be seen by IPv6 visitors. Put it behind a proxy or a CDN that accepts an IPv6 origin, or take the plan with IPv4.
- Port 25 closed towards IPv4. The outbound address is shared: to protect its reputation, port 25 towards IPv4 is closed, with no exception. Send mail through an authenticated relay on port 587.
-
Hard-coded IPv4 addresses. Software that connects to an IPv4
address without going through a name gets no help from DNS64. Write the translated
address instead:
64:ff9b::1.1.1.1, for example. - A final choice. The network is chosen at order time and does not change afterwards. Adding an IPv4 later takes a new machine.
7. Who is it for?
IPv6-only suits machines that send a lot and receive little: continuous integration, AI agents, data collection, compute, test environments, or nodes of a private network. If you serve an IPv4 audience, keep the plan with IPv4. For more on addressing, reverse DNS and the firewall, see our guide IPv6 on a VPS.