Can you host a server on Starlink without a public IPv4 address?
Not directly over IPv4, as far as my traces show: the address the internet sees doesn't seem to be on any device I control. A trace from a computer on my home network in October 2026 reached a private address on Starlink's side before the first public one, which is what carrier-grade NAT (CGNAT) looks like from inside the house. The one hop that would show it directly, the second, didn't answer.
I run these tests on my own hardware, with scripts and AI agents I direct, and I check every result before it goes up.
A private address on Starlink's side comes before the first public one
The trace ran from a computer on my home network in October 2026. It was the second of two runs on the same day.
tracepath -n -m 8 1.1.1.1
Here is what it printed, retyped with a label in place of every address:
1?: [LOCALHOST] pmtu 1500
1: my router 1.998ms
1: my router 1.792ms
2: no reply
3: private address (RFC 1918), Starlink's side 34.218ms
4: public address, SpaceX (AS14593) 35.767ms (router returned corrupted payload) asymm 7
5: public address, SpaceX (AS14593) 36.125ms
6: public address, owner not checked 35.623ms asymm 7
7: public address, Cloudflare 44.837ms
8: public address, Cloudflare 36.379ms asymm 9
Too many hops: pmtu 1500
Hop 1 is my router. Hop 2 sent nothing back, in either run. Hop 3 is a private address on Starlink's side, and the first public address doesn't show up until hop 4, in SpaceX's network.
Private addresses are the blocks that RFC 1918 sets aside for use inside a network. Because they "have no global meaning", routes to them aren't supposed to be passed from one network to another (section 3, checked October 2026). So hop 3 only means something inside Starlink's network, and a private hop before the first public one is what CGNAT looks like from inside the house.
RFC 6598 reserves 100.64.0.0/10 as "Shared Address Space" for carrier-grade NAT, and expects providers to number the links between their carrier-grade NAT devices and the equipment on their customers' premises from that block (abstract and sections 1 and 7, checked October 2026). So if my router is the equipment on that link, the hop right after it is where an address from that block would show up. That's hop 2, the one that didn't answer.
If this is CGNAT, a port forward on my router can't receive connections sent to the address the internet sees. RFC 6888 describes a carrier-grade NAT as a function in the provider's network that shares one IPv4 address among several subscribers and isn't managed by them. Subscribers have "limited or no control" over it, while they "typically have full control" over a NAT on their own premises (section 2, checked October 2026). A port forward on my router is a setting on that second kind of NAT.
This trace can't show two things. With hop 2 silent, there's no telling whether its address comes from 100.64.0.0/10. And it can't show whether my router holds the public address itself. RFC 1918 gives router interfaces inside a network as one use for private addresses, and describes a design that uses them "for all internal links" (sections 2 and 5). So a provider can number its own internal links with private addresses without doing any NAT, and a private hop 3 doesn't prove CGNAT on its own.
From a VPS, none of 8 ports answered on the address the internet sees
I watched this test in October 2026. It ran from a VPS, a cloud server rather than my own hardware. A script there tried one TCP connection to each of 8 TCP ports, including 22, 80 and 443, on the address the internet sees for my connection, and gave each one 6 seconds to answer. No port forward was set up for this test. Before the home ports, the script checked itself against targets with known answers.
| Target | What it checks | Result |
|---|---|---|
| The VPS's own address, port 443 | the probe sees an open port as open | connected |
| The VPS's own address, port 80 | the same, on a second port | connected |
| A well-known public resolver, port 443 | the VPS can reach another network | connected |
| The VPS's own address, port 9, nothing listening | an empty port doesn't show as open | no answer within 6 s |
| The address the internet sees for my connection, each of the 8 ports | the test itself | no answer within 6 s |
The whole run took 56 seconds. The empty port and the 8 home ports, nine probes in all, each waited out the full 6 seconds. That's 54 of the 56, so every "no answer" was a real wait and not the tool failing fast.
None of the 8 ports answered, and on its own that says less than it sounds like. If this is CGNAT, the address is shared: RFC 6888 describes a carrier-grade NAT as sharing one IPv4 address among several subscribers (section 2, checked October 2026), so no answer is the expected result, and the run says nothing about my own router. The same timeouts would also come from my router holding the address itself and dropping connections nobody inside asked for. So the run doesn't show where the connections stopped, and it doesn't prove CGNAT. It also never saw a refusal: the empty port on the VPS timed out instead of refusing, so all it shows is that nothing answered within 6 s.
Port 25 timed out; 587 connected
In October 2026, a computer on my home network tried TCP connections over IPv4 to portquiz.net, a public server set up for port tests. Its home page says it "listens on all TCP ports, allowing you to test any outbound TCP port" (checked October 2026). Each connection had a 10 second timeout. The sweep used bash's /dev/tcp, and 25 and 445 were tried again with Python's socket.create_connection and timeout=10.
| Port | Result |
|---|---|
| 25 (SMTP) | timed out after 10.3 s |
| 445 (SMB) | timed out after 10.3 s |
| 465 (SMTPS) | connected |
| 587 (mail submission) | connected |
| 80 | connected |
| 8080 | connected |
The two mail submission ports got through. Port 25 didn't, and neither did 445. The same home page says portquiz.net uses some ports for real services, naming 22 and 25, so port 25 wasn't quite the same test as the others, and the drop could be at portquiz.net's end.
I don't know where 25 and 445 were dropped: at my router, somewhere in Starlink's network, or in portquiz.net's own network. This was IPv4 only, because portquiz.net has no IPv6 address.
What I haven't tested yet
Why hop 2 stays silent. A trace in which it answers would show what sits right after my router, and an address from 100.64.0.0/10 there is what RFC 6598 sets that block aside for. Until then, the CGNAT reading on this page rests on the shape of the trace.
Where 25 and 445 are dropped. That needs the same test from another network.
Inbound IPv6. Nothing on this page says whether a connection over IPv6 can reach a server in my house.
I run a relay for a game server on a small cloud server. Its measurements aren't complete enough to publish, so nothing on this page rests on it.
One way around a missing public IPv4 address that this page doesn't test is an outbound-only tunnel. Cloudflare's documentation for Cloudflare Tunnel says its small background program, cloudflared, opens outbound-only connections to Cloudflare's network, so a server can serve traffic through Cloudflare without a publicly routable IP address (page last updated August 2026, checked October 2026).
Sources
- RFC 1918: Address Allocation for Private Internets, IETF, accessed October 2026
- RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space, IETF, accessed October 2026
- RFC 6888: Common Requirements for Carrier-Grade NATs (CGNs), IETF, accessed October 2026
- Cloudflare Tunnel, Cloudflare, accessed October 2026
- portquiz.net home page, portquiz.net, accessed October 2026
Retest log
- Test From a VPS, one TCP connection to each of 8 ports on the address the internet sees for my connection, with controls. None answered within 6 s.
- Test Two traces of the route out from a computer on my home network, and outbound TCP connections to portquiz.net on six ports.