master
md 214 lines 6.38 KB
Rendered Raw
1 # P2P Tunnels
2
3 Kubo supports tunneling TCP connections through libp2p streams, similar to SSH
4 port forwarding (`ssh -L`). This allows exposing local services to remote peers
5 and forwarding remote services to local ports.
6
7 - [Why P2P Tunnels?](#why-p2p-tunnels)
8 - [Quick Start](#quick-start)
9 - [Background Mode](#background-mode)
10 - [Foreground Mode](#foreground-mode)
11 - [systemd Integration](#systemd-integration)
12 - [Security Considerations](#security-considerations)
13 - [Troubleshooting](#troubleshooting)
14
15 ## Why P2P Tunnels?
16
17 Unlike traditional SSH tunnels, libp2p-based tunnels do not require:
18
19 - **No public IP or open ports**: The server does not need a static IP address
20 or port forwarding configured on the router. Connectivity to peers behind NAT
21 is facilitated by [Direct Connection Upgrade through Relay (DCUtR)](https://github.com/libp2p/specs/blob/master/relay/DCUtR.md),
22 which enables NAT hole-punching.
23
24 - **No DNS or IP address management**: All you need is the server's PeerID and
25 an agreed-upon protocol name (e.g., `/x/ssh`). Kubo handles peer discovery
26 and routing via the [Amino DHT](https://specs.ipfs.tech/routing/kad-dht/).
27
28 - **Simplified firewall rules**: Since connections are established through
29 libp2p's existing swarm connections, no additional firewall configuration is
30 needed beyond what Kubo already requires.
31
32 This makes p2p tunnels useful for connecting to machines on home networks,
33 behind corporate firewalls, or in environments where traditional port forwarding
34 is not available.
35
36 ## Quick Start
37
38 Enable the experimental feature:
39
40 ```console
41 $ ipfs config --json Experimental.Libp2pStreamMounting true
42 ```
43
44 Test with netcat (`nc`) - no services required:
45
46 **On the server:**
47
48 ```console
49 $ ipfs p2p listen /x/test /ip4/127.0.0.1/tcp/9999
50 $ nc -l -p 9999
51 ```
52
53 **On the client:**
54
55 Replace `$SERVER_ID` with the server's peer ID (get it with `ipfs id -f "<id>\n"`
56 on the server).
57
58 ```console
59 $ ipfs p2p forward /x/test /ip4/127.0.0.1/tcp/9998 /p2p/$SERVER_ID
60 $ nc 127.0.0.1 9998
61 ```
62
63 Type in either terminal and the text appears in the other. Use Ctrl+C to exit.
64
65 ## Background Mode
66
67 By default, `ipfs p2p listen` and `ipfs p2p forward` register the tunnel with
68 the daemon and return immediately. The tunnel persists until explicitly closed
69 with `ipfs p2p close` or the daemon shuts down.
70
71 This example exposes a local SSH server (listening on `localhost:22`) to a
72 remote peer. The same pattern works for any TCP service.
73
74 **On the server** (the machine running SSH):
75
76 Register a p2p listener that forwards incoming connections to the local SSH
77 server. The protocol name `/x/ssh` is an arbitrary identifier that both peers
78 must agree on (the `/x/` prefix is required for custom protocols).
79
80 ```console
81 $ ipfs p2p listen /x/ssh /ip4/127.0.0.1/tcp/22
82 ```
83
84 **On the client:**
85
86 Create a local port (`2222`) that tunnels through libp2p to the server's SSH
87 service.
88
89 ```console
90 $ ipfs p2p forward /x/ssh /ip4/127.0.0.1/tcp/2222 /p2p/$SERVER_ID
91 ```
92
93 Now connect to SSH through the tunnel:
94
95 ```console
96 $ ssh user@127.0.0.1 -p 2222
97 ```
98
99 **Other services:** To tunnel a different service, change the port and protocol
100 name. For example, to expose a web server on port 8080, use `/x/mywebapp` and
101 `/ip4/127.0.0.1/tcp/8080`.
102
103 ## Foreground Mode
104
105 Use `--foreground` (`-f`) to block until interrupted. The tunnel is
106 automatically removed when the command exits:
107
108 ```console
109 $ ipfs p2p listen /x/ssh /ip4/127.0.0.1/tcp/22 --foreground
110 Listening on /x/ssh, forwarding to /ip4/127.0.0.1/tcp/22, waiting for interrupt...
111 ^C
112 Received interrupt, removing listener for /x/ssh
113 ```
114
115 The listener/forwarder is automatically removed when:
116
117 - The command receives Ctrl+C or SIGTERM
118 - `ipfs p2p close` is called
119 - The daemon shuts down
120
121 This mode is useful for systemd services and scripts that need cleanup on exit.
122
123 ### systemd Integration
124
125 The `--foreground` flag enables clean integration with systemd. The examples
126 below show how to run `ipfs p2p listen` as a user service that starts
127 automatically when the IPFS daemon is ready.
128
129 Ensure IPFS daemon runs as a systemd user service. See
130 [misc/README.md](https://github.com/ipfs/kubo/blob/master/misc/README.md#systemd)
131 for setup instructions and where to place unit files.
132
133 #### P2P listener with path-based activation
134
135 Use a `.path` unit to wait for the daemon's RPC API to be ready before starting
136 the p2p listener.
137
138 **`ipfs-p2p-tunnel.path`**:
139
140 ```systemd
141 [Unit]
142 Description=Monitor for IPFS daemon startup
143 After=ipfs.service
144 Requires=ipfs.service
145
146 [Path]
147 PathExists=%h/.ipfs/api
148 Unit=ipfs-p2p-tunnel.service
149
150 [Install]
151 WantedBy=default.target
152 ```
153
154 The `%h` specifier expands to the user's home directory. If you use a custom
155 `IPFS_PATH`, adjust accordingly.
156
157 **`ipfs-p2p-tunnel.service`**:
158
159 ```systemd
160 [Unit]
161 Description=IPFS p2p tunnel
162 Requires=ipfs.service
163
164 [Service]
165 ExecStart=ipfs p2p listen /x/ssh /ip4/127.0.0.1/tcp/22 -f
166 Restart=on-failure
167 RestartSec=10
168
169 [Install]
170 WantedBy=default.target
171 ```
172
173 #### Enabling the services
174
175 ```console
176 $ systemctl --user enable ipfs.service
177 $ systemctl --user enable ipfs-p2p-tunnel.path
178 $ systemctl --user start ipfs.service
179 ```
180
181 The path unit monitors `~/.ipfs/api` and starts `ipfs-p2p-tunnel.service`
182 once the file exists.
183
184 ## Security Considerations
185
186 > [!WARNING]
187 > This feature provides CLI and HTTP RPC users with the ability to set up port
188 > forwarding for localhost and LAN ports. If you enable this and plan to expose
189 > CLI or HTTP RPC to other users or machines, secure the RPC API using
190 > [`API.Authorizations`](https://github.com/ipfs/kubo/blob/master/docs/config.md#apiauthorizations)
191 > or custom auth middleware.
192
193 ## Troubleshooting
194
195 ### Foreground listener stops when terminal closes
196
197 When using `--foreground`, the listener stops if the terminal closes. For
198 persistent foreground listeners, use a systemd service, `nohup`, `tmux`, or
199 `screen`. Without `--foreground`, the listener persists in the daemon regardless
200 of terminal state.
201
202 ### Connection refused errors
203
204 Verify:
205
206 1. The experimental feature is enabled: `ipfs config Experimental.Libp2pStreamMounting`
207 2. The listener is active: `ipfs p2p ls`
208 3. Both peers can connect: `ipfs swarm connect /p2p/$PEER_ID`
209
210 ### Persistent tunnel configuration
211
212 There is currently no way to define tunnels in the Kubo JSON config file. Use
213 `--foreground` mode with a systemd service for persistent tunnels. Support for
214 configuring tunnels via JSON config may be added in the future (see [kubo#5460](https://github.com/ipfs/kubo/issues/5460) - PRs welcome!).