Every few months someone says IPv4 addresses are running out and we should all be on IPv6 by now. I wanted to know what that would actually mean for an ordinary server. Not a lab network, just a Linux box where you install packages, pull images and talk to a few APIs.
So I took a fresh Ubuntu 24.04 Droplet on DigitalOcean, in Frankfurt, with IPv6 turned on, and ran the same checks twice. First with both IPv4 and IPv6, as a control. Then again after removing its IPv4 default route, so anything that needs IPv4 to reach the outside world simply can't.
What I checked
53 services a typical server talks to, grouped roughly as:
- package sources: Ubuntu, Docker's and PostgreSQL's apt repos, PyPI, npm, Go's module proxy, crates.io, RubyGems, Maven Central, Packagist, the Snap store
- install scripts: get.docker.com, rustup, uv, Ollama, Tailscale, Node.js downloads
- code hosting: GitHub, GitLab, Bitbucket, Hugging Face
- container registries: Docker Hub, ghcr.io, Quay, registry.k8s.io, Google's Artifact Registry, DigitalOcean's registry
- APIs: DigitalOcean, OpenAI, Anthropic, Stripe, Twilio, SendGrid, Slack, Discord, Sentry, Cloudflare, AWS S3, Vercel, Supabase, Telegram, Let's Encrypt
For each one I made a single HTTPS request with curl and counted any HTTP response as reachable, including a 401 or a 404. Getting a status code back means the network part works. Then I ran 13 real commands on top: apt-get update, a pip install, an npm install, git clone from GitHub and GitLab, go get, three docker pulls, the uv installer, downloading a GitHub release, and snap install.
Most of it was already IPv6
The first surprise came from the control run. With both protocols available, 38 of the 53 services were already being reached over IPv6. Nobody configured that. curl looked up both addresses, preferred the IPv6 one, and it worked. Ubuntu's mirrors, PyPI, npm, Docker Hub, OpenAI, Anthropic, Cloudflare, Let's Encrypt and DigitalOcean's own API all went over IPv6 by default.
So a dual-stack server is already mostly an IPv6 server. It just has IPv4 as a fallback for the rest.
What broke without IPv4
With the IPv4 route gone, 39 of 53 still answered. These 14 didn't:
- GitHub: github.com, api.github.com, and the host that serves release downloads
- ghcr.io, GitHub's container registry
- AWS S3 at s3.amazonaws.com
- Stripe, Twilio, SendGrid, Slack webhooks, Discord
- Sentry, Vercel's API, Supabase
- ollama.com, so its install script
None of those 14 publish an IPv6 address at all. They didn't time out or misbehave. curl failed in 1 or 2 milliseconds with "Couldn't connect to server", because there was no way to get there.
The real commands followed the same line. 10 of the 13 worked. The three that failed were all GitHub: git clone from GitHub, docker pull from ghcr.io, and downloading a release file. The same commands against GitLab and Quay worked, and so did pulling from Docker Hub.
The GitHub result is the one that would hurt in practice, and it has an odd shape. raw.githubusercontent.com, which serves single files, does have IPv6, so curl of a raw file works. Cloning the repository the file lives in doesn't. The uv installer worked for a related reason: its binaries come from releases.astral.sh rather than GitHub releases.
How fast things were didn't change. apt-get update took 4.8 seconds with both protocols and 4.9 with IPv6 only. pip install requests took 9.5 and 9.3. That's expected, since those were already using IPv6 in the first run.
The part that kept working because of DigitalOcean
I expected DNS to be the first thing to break, because the resolvers a Droplet is given are IPv4 addresses. It didn't break. Every Droplet also has a private network interface, and that interface has its own resolver, which kept answering after the public IPv4 route was gone.
Spaces, DigitalOcean's object storage, was the other surprise. From inside the Frankfurt Droplet, fra1.digitaloceanspaces.com resolved to a private address and the request went over the private network. Amsterdam's Spaces endpoint did the same. New York's and Singapore's resolved to public IPv4 addresses, have no IPv6 address, and failed. So a Droplet with no public IPv4 can still use object storage in its own region or a nearby one, but not on the other side of the world.
What I got wrong
I planned to SSH into the Droplet over IPv6, so the test machine would have no IPv4 path at all. The connection on my end lost its IPv6 partway through, and the script sat for half an hour waiting for an SSH connection that could never open. In the end I connected over IPv4 and kept a single route back to my own address. Everything else outbound had no IPv4 route.
My first DNS check after cutting IPv4 came back fine, and I nearly wrote that down as "DNS works". It had answered from cache. The real test needed a cleared cache and a name it hadn't seen.
And I assumed the DNS problem would be the headline. On DigitalOcean it isn't, because of that private-network resolver. On a provider without one, it would be the first thing you hit.
Caveats
This isn't a true IPv6-only server. DigitalOcean always gives a Droplet a public IPv4 address, so I simulated it by deleting the default route, and the private network was still there. Real IPv6-only networks often use NAT64 and DNS64, which translate for IPv4-only services. With those, most of the 14 would have worked through the translator.
It's one Droplet in one region on one day, with one request per service, and reachability isn't the same as everything working. A service that answers with a 401 might still fail later in a longer flow. These lists also change: any of the 14 could add IPv6 next month.
What I'd take from it
If you run a dual-stack server today, most of your traffic is probably already IPv6 and you never noticed. Going IPv6-only is mostly fine for installing software and calling the big AI and cloud APIs. It isn't fine if your deploys clone from GitHub, pull from ghcr.io, take payments through Stripe, or report errors to Sentry. Check those first, because they won't time out slowly. They'll fail straight away.
