docs: firewall (ufw) walkthrough for port 4001 (#11332)
Surfaced by ipfs/service-worker-gateway#1067, where operators behind a default-deny firewall hit unreachable nodes from browser peers because UDP/4001 (QUIC, WebTransport, WebRTC-Direct) was not opened alongside TCP/4001. - new docs/production/firewall.md: inspect ufw rules, open 4001/tcp and 4001/udp, optional Kubo application profile, custom-port and rule-removal notes - daemon health (ipfs diag healthy) split from reachability (ipfs swarm addrs autonat), with Swarm.DisableNatPortMap and Swarm.EnableHolePunching pointers for nodes that stay Private - link the walkthrough from Addresses.Swarm and the Security section in docs/config.md, and from the Production index in docs/README.md
Marcin Rataj committed
May 19, 2026 at 17:29 UTC
c81317e342d550c0aff545bd476bed78b87614db
3 files changed
+211
-2
docs/README.md
+1
@@ -47,6 +47,7 @@ If you're experiencing an issue with IPFS, please [file an issue](https://github
47
## Production
48
49
- [Reverse proxy setup](production/reverse-proxy.md)
50
+- [Firewall setup (ufw)](production/firewall.md)
51
52
## Specifications
53
docs/config.md
+3
-2
@@ -358,7 +358,8 @@ Supported Transports:
358
359
> [!IMPORTANT]
360
> Make sure your firewall rules allow incoming connections on both TCP and UDP ports defined here.
361
-> See [Security section](#security) for network exposure considerations.
361
+> See [`docs/production/firewall.md`](./production/firewall.md) for a `ufw` walkthrough,
362
+> and the [Security section](#security) below for wider network exposure considerations.
363
364
Note that quic (Draft-29) used to be supported with the format `/ipN/.../udp/.../quic`, but has since been [removed](https://github.com/libp2p/go-libp2p/releases/tag/v0.30.0).
365
@@ -4611,7 +4612,7 @@ Several configuration options expose TCP or UDP ports that can make your Kubo no
4612
4613
- Keep admin services ([`Addresses.API`](#addressesapi)) bound to localhost unless authentication ([`API.Authorizations`](#apiauthorizations)) is configured
4614
- Use [`Gateway.NoFetch`](#gatewaynofetch) to prevent arbitrary CID retrieval if Kubo is acting as a public gateway available to anyone
4614
-- Configure firewall rules to restrict access to exposed ports. Note that [`Addresses.Swarm`](#addressesswarm) is special - all incoming traffic to swarm ports should be allowed to ensure proper P2P connectivity
4615
+- Configure firewall rules to restrict access to exposed ports. Note that [`Addresses.Swarm`](#addressesswarm) is special - all incoming traffic to swarm ports should be allowed to ensure proper P2P connectivity. See [`docs/production/firewall.md`](./production/firewall.md) for a `ufw` walkthrough.
4616
- Control which public-facing addresses are announced to other peers using [`Addresses.NoAnnounce`](#addressesnoannounce), [`Addresses.Announce`](#addressesannounce), and [`Addresses.AppendAnnounce`](#addressesappendannounce)
4617
- Consider using the [`server` profile](#server-profile) for production deployments
4618
docs/production/firewall.md
new
+207
@@ -0,0 +1,207 @@
1
+# Firewall Setup for Kubo
2
+
3
+By default, kubo's libp2p swarm listens on **port 4001** over both TCP and
4
+UDP. Open both so peers can reach you:
5
+
6
+- **TCP/4001** carries the plain TCP transport (and the optional WebSocket `/ws`).
7
+- **UDP/4001** carries QUIC, WebTransport, and WebRTC-Direct.
8
+
9
+Block either one and kubo falls back to slower relayed or hole-punched
10
+connections.
11
+
12
+The defaults come from [`Addresses.Swarm`](../config.md#addressesswarm):
13
+
14
+```json
15
+[
16
+ "/ip4/0.0.0.0/tcp/4001",
17
+ "/ip6/::/tcp/4001",
18
+ "/ip4/0.0.0.0/udp/4001/webrtc-direct",
19
+ "/ip4/0.0.0.0/udp/4001/quic-v1",
20
+ "/ip4/0.0.0.0/udp/4001/quic-v1/webtransport",
21
+ "/ip6/::/udp/4001/webrtc-direct",
22
+ "/ip6/::/udp/4001/quic-v1",
23
+ "/ip6/::/udp/4001/quic-v1/webtransport"
24
+]
25
+```
26
+
27
+The examples below use [`ufw`](https://help.ubuntu.com/community/UFW), the
28
+default firewall tool on Debian and Ubuntu. The same rules translate to
29
+`firewalld`, `nftables`, or cloud security groups.
30
+
31
+## Check what rules you have
32
+
33
+List active rules:
34
+
35
+```bash
36
+sudo ufw status verbose
37
+```
38
+
39
+Or with line numbers, useful when deleting one later:
40
+
41
+```bash
42
+sudo ufw status numbered
43
+```
44
+
45
+A typical SSH-only host looks like this:
46
+
47
+```
48
+Status: active
49
+Logging: off
50
+Default: deny (incoming), allow (outgoing), disabled (routed)
51
+
52
+To Action From
53
+-- ------ ----
54
+22/tcp ALLOW IN Anywhere
55
+22/tcp (v6) ALLOW IN Anywhere (v6)
56
+```
57
+
58
+You want 4001 in that list, on both TCP and UDP.
59
+
60
+## Open port 4001
61
+
62
+The short way opens both TCP and UDP at once:
63
+
64
+```bash
65
+sudo ufw allow 4001 comment 'ipfs/libp2p swarm'
66
+```
67
+
68
+One rule per protocol reads more clearly later:
69
+
70
+```bash
71
+sudo ufw allow 4001/tcp comment 'ipfs/libp2p tcp+http+ws'
72
+sudo ufw allow 4001/udp comment 'ipfs/libp2p quic+webtransport+webrtc'
73
+```
74
+
75
+`ufw` covers IPv4 and IPv6 together when `IPV6=yes` is set in
76
+`/etc/default/ufw` (the default on Ubuntu).
77
+
78
+To limit a rule to one interface or source range:
79
+
80
+```bash
81
+sudo ufw allow in on eth0 to any port 4001 proto tcp
82
+sudo ufw allow in on eth0 to any port 4001 proto udp
83
+sudo ufw allow from 203.0.113.0/24 to any port 4001
84
+```
85
+
86
+> [!NOTE]
87
+> A public IPFS node needs to be reachable by anyone. Restrict by source IP
88
+> only on private deployments.
89
+
90
+Check the result:
91
+
92
+```bash
93
+sudo ufw status verbose
94
+```
95
+
96
+You should see `4001/tcp` and `4001/udp` (and the matching `(v6)` lines).
97
+
98
+## Optional: a `Kubo` application profile
99
+
100
+When you run kubo across many hosts, a `ufw` "application profile" lets you
101
+allow it by name. Create `/etc/ufw/applications.d/kubo`:
102
+
103
+```ini
104
+[Kubo]
105
+title=Kubo
106
+description=ipfs kubo swarm ports
107
+ports=4001/tcp|4001/udp
108
+```
109
+
110
+Allow it by name:
111
+
112
+```bash
113
+sudo ufw allow Kubo
114
+```
115
+
116
+Inspect the profile:
117
+
118
+```bash
119
+sudo ufw app info Kubo
120
+```
121
+
122
+If you later edit the `ports=` line in the profile, push the new ports
123
+into the existing rule with:
124
+
125
+```bash
126
+sudo ufw app update Kubo
127
+```
128
+
129
+## Different ports?
130
+
131
+If you changed [`Addresses.Swarm`](../config.md#addressesswarm) (for example,
132
+when running several kubo nodes on one host), open the port you chose. Open
133
+both TCP and UDP unless you explicitly disabled a transport in
134
+[`Swarm.Transports.Network`](../config.md#swarmtransportsnetwork).
135
+
136
+## Remove a rule
137
+
138
+Find the rule number:
139
+
140
+```bash
141
+sudo ufw status numbered
142
+```
143
+
144
+Numbers shift after each delete, so list again between deletes:
145
+
146
+```bash
147
+sudo ufw delete <number>
148
+```
149
+
150
+Or delete by spec:
151
+
152
+```bash
153
+sudo ufw delete allow 4001/tcp
154
+sudo ufw delete allow 4001/udp
155
+```
156
+
157
+## Is the daemon healthy?
158
+
159
+To confirm kubo is running and the local block pipeline works:
160
+
161
+```bash
162
+ipfs diag healthy
163
+```
164
+
165
+It exits 0 when the daemon is up. Use it for container healthchecks. It
166
+only checks local state; for reachability from outside, see the next
167
+section.
168
+
169
+## Can peers reach you?
170
+
171
+`ipfs id` shows the addresses your node advertises. To test them from
172
+outside, ask AutoNAT V2:
173
+
174
+```bash
175
+ipfs swarm addrs autonat
176
+```
177
+
178
+Look for `Reachability: Public`. The `Reachable` and `Unreachable` lists
179
+break things down by address, so you can see at a glance which protocol is
180
+blocked upstream.
181
+
182
+If you stay `Private` even with `ufw` open, something upstream is blocking
183
+you. Common next steps:
184
+
185
+- **Behind a home or office router (NAT):** let kubo ask the router to
186
+ forward the port. Keep
187
+ [`Swarm.DisableNatPortMap`](../config.md#swarmdisablenatportmap) at `false`
188
+ (the default; this is UPnP / NAT-PMP). The `server` profile disables it,
189
+ so if you applied that profile but you are behind a router, set it back
190
+ to `false`.
191
+- **No control over the upstream NAT (CGNAT, mobile, locked-down corporate
192
+ networks):** keep
193
+ [`Swarm.EnableHolePunching`](../config.md#swarmenableholepunching) on
194
+ (the default). Peers will then reach you through a relay using DCUtR
195
+ (direct connection upgrade through relay).
196
+
197
+More background: the
198
+[libp2p AutoNAT V2 spec](https://github.com/libp2p/specs/blob/master/autonat/autonat-v2.md).
199
+
200
+## Related
201
+
202
+- [`Addresses.Swarm`](../config.md#addressesswarm): the addresses kubo
203
+ listens on.
204
+- [`Swarm.Transports.Network`](../config.md#swarmtransportsnetwork): which
205
+ transports are enabled.
206
+- [Security section in `config.md`](../config.md#security): port and
207
+ exposure guidance for the API, Gateway, and swarm.