You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/post/2025/04-29-rathole-traefik-home-server/index.mdx
+27-24Lines changed: 27 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,34 +24,34 @@ import HomeServerContainersImage from '../../../../content/post/2025/04-29-ratho
24
24
25
25
## Introduction
26
26
27
-
In the previous article I wrote about temporary SSH tunneling technique to bypass CG-NAT. This method is not suitable for exposing permanent services, at least not without `autossh` manager. Proper tools for this are [rapiz1/rathole](https://github.com/rapiz1/rathole) or [fatedier/frp](https://github.com/fatedier/frp). I chose Rathole since it's written in Rust and offers better performance and benchmarks.
27
+
In the previous article, I wrote about a temporary SSH tunneling technique to bypass CG-NAT. This method is not suitable for exposing permanent services, at least not without `autossh` manager. Proper tools for this are [rapiz1/rathole](https://github.com/rapiz1/rathole) or [fatedier/frp](https://github.com/fatedier/frp). I chose Rathole since it's written in Rust and offers better performance and benchmarks.
28
28
29
29
## Prerequisites
30
30
31
-
- A VPS server with a public IP and Docker, ideally small, you can't use ports `80` and `443` for any other services aside Rathole
31
+
- A VPS server with a public IP and Docker, ideally small, you can't use ports `80` and `443` for any other services aside from Rathole
32
32
- A home server
33
33
- A domain name
34
34
35
35
## Architecture overview
36
36
37
-
We will use Rathole for encrypted tunnel between VPS and local network. We will also use Traefik since we want to host multiple websites on our home server, like you would on any server.
37
+
We will use Rathole for an encrypted tunnel between the VPS and the local network. We will also use Traefik since we want to host multiple websites on our home server, just like you would on any server.
38
38
39
39
The main question is where to run Traefik:
40
40
41
41
1. On the VPS
42
42
2. On the home server
43
43
44
-
I highly prefer the option 2 because that way the entire configuration is stored in our home server. The home server is almost tunnelagnostic, and you can reuse it on any tunneled or non-tunneled server. Otherwise we would need to maintain state between the VPS and the home server, debug both together, etc.
44
+
I highly prefer option 2 because, that way, the entire configuration is stored on our home server. The home server is almost tunnel-agnostic, and you can reuse it on any tunneled or non-tunneled server. Otherwise, we would need to maintain state between the VPS and the home server, debug both together, etc.
45
45
46
-
Another point is that with option 2, we avoid the gap of unencrypted traffic on the VPS between Traefik (TLS) and Rathole (Noise Protocol). You can read more about the comparison of these two options in this article: https://blog.mni.li/posts/caddy-rathole-zero-knowledge/.
46
+
Another point is that, with option 2, we avoid the gap of unencrypted traffic on the VPS between Traefik (TLS) and Rathole (Noise Protocol). You can read more about the comparison of these two options in this article: https://blog.mni.li/posts/caddy-rathole-zero-knowledge/.
47
47
48
48
The downside is that Rathole will exclusively occupy ports `80` and `443` on the VPS, preventing any other process from using them. We won't be able to run other web servers on that VPS, so it's best to use a small one dedicated to this purpose.
49
49
50
50
image
51
51
52
52
## Rathole server
53
53
54
-
We will run Rathole server inside a Docker container on our VPS. Rathole uses the same binary for both server and client, you just pass the right option `<--server|--client>` and the `.toml` configuration file.
54
+
We will run the Rathole server inside a Docker container on our VPS. Rathole uses the same binary for both the server and client, you just pass the right option (`--server` or `--client`) and the `.toml` configuration file.
55
55
56
56
Here is the Rathole server configuration [rathole.server.toml](https://github.com/nemanjam/rathole-server/blob/5226ff53992abe930302098677a570151ebff927/rathole.server.toml):
57
57
@@ -74,15 +74,16 @@ token = "secret_token_1"
74
74
bind_addr = "0.0.0.0:5443"
75
75
```
76
76
77
-
Let's explain it: we choose port `2333` for the control channel and we bind it to all interfaces inside the Docker container with `0.0.0.0` IP. We choose `noise` encryption protocol and specify a private key. Public key will be used on the Rathole client. Public and private keys pair is generated with:
77
+
Let's explain it: we choose port `2333` for the control channel and bind it to all interfaces inside the Docker container with the `0.0.0.0` IP. We choose the `noise` encryption protocol and specify a private key. The public key will be used on the Rathole client. The public and private key pair is generated with:
78
+
78
79
79
80
```bash
80
81
docker run -it --rm rapiz1/rathole --genkey
81
82
```
82
83
83
-
Then we define two tunnels, one for HTTP and another for HTTPS. For HTTP tunnel we define the name `server.services.traefik-http`, set the value for `token`, and choose the port `5080` and again we bind to all container interfaces with `0.0.0.0`. Similarly for HTTPS we set the name to `server.services.traefik-https`, provide a `token` value and choose port `5443`.
84
+
Then we define two tunnels: one for HTTP and another for HTTPS. For the HTTP tunnel, we define the name `server.services.traefik-http`, set the value for `token`, and choose port `5080`, and again we bind it to all container interfaces with `0.0.0.0`. Similarly, for HTTPS, we set the name to `server.services.traefik-https`, provide a `token` value, and choose port `5443`.
84
85
85
-
Important note is that beside a different name, just a different token value is sufficient to create another tunnel (Rathole service). This practically means we can use a single Rathole server container to expose multiple home servers (Rathole clients) on the same ports `5080` and `5443`, which is pretty convenient.
86
+
An important note is that, aside from a different name, a different token value is sufficient to create another tunnel (Rathole service). This practically means we can use a single Rathole server container to expose multiple home servers (Rathole clients) on the same ports `5080` and `5443`, which is pretty convenient.
86
87
87
88
Token is just a random base64 string, we generate it by running this:
In the command we set the `--server` option and pass the `.toml` configuration file and mount it as a read-only bind-mount volume.
113
+
In the command, we set the `--server` option, pass the `.toml` configuration file, and mount it as a read-only bind-mount volume.
113
114
114
-
Important part are the port mappings, here you can see that Rathole server container will occupy ports `2333`, `80`, and `443` exclusively on the host VPS. This practically means we wont be able to run any other webservers on ports `80` and `443`. We will also need to open ports `80`, `443` and `2333` in the VPS firewall. You don't need to open ports `5080` and `5443`, those are used only by Rathole internally.
115
+
The important part is the port mappings. Here, you can see that the Rathole server container will occupy ports `2333`, `80`, and `443` exclusively on the host VPS. This practically means we won't be able to run any other web servers on ports `80` and `443`. We will also need to open ports `80`, `443`, and `2333` in the VPS firewall. You don't need to open ports `5080` and `5443`, those are used only by Rathole internally.
115
116
116
117
## Rathole client and connecting with Traefik
117
118
118
-
We run Rathole client and Trafik inside the Docker containers on the home server. Configuring Rathole client and connecting it to Traefik is a bit more complex and tricky.
119
+
We run the Rathole client and Traefik inside Docker containers on the home server. Configuring the Rathole client and connecting it to Traefik is a bit more complex and tricky.
119
120
120
121
Here is the Rathole client configuration [core/rathole.client.toml.example](https://github.com/nemanjam/traefik-proxy/blob/e8fece09e31ec99ddd21559f343d0ddea9fb55bf/core/rathole.client.toml.example):
121
122
@@ -143,17 +144,19 @@ token = "secret_token_1"
143
144
local_addr = "traefik:443"
144
145
```
145
146
146
-
Let's go through it. First we define the VPS server IP `remote_addr` and the control channel port `2333`, set `noise` encryption protocol and a public key this time `remote_public_key`.
147
+
Let's go through it. First, we define the VPS server IP `remote_addr`, the control channel port `2333`, set the `noise` encryption protocol, and this time specify a public key `remote_public_key`.
148
+
149
+
Now comes the important and tricky part: defining tunnels and services. We repeat the service name and token that we used in the Rathole server config.
147
150
148
-
Now comes the important and tricky part, defining tunnels - services. We repeat the service name and token that we used in Rathole server config.
151
+
**And now the most important part:** `local_addr`, for this we target the Traefik hostname - service name from `core/docker-compose.local.yml` and the Traefik listening ports `80` and `443`. That's it. It might look simple and obvious, this is the correct setup. I must emphasize: don't fall into temptation of setting any additional port mappings in `core/docker-compose.local.yml`, functionality will break, all should be done in `core/rathole.client.toml`.
149
152
150
-
**And now the most important part:** `local_addr`, for this we target Traefik hostname - service name from `core/docker-compose.local.yml` and Traefik listening ports `80` and `443`. That's it. It might look simple and obvious, this is the correct setup. I must emphasize, don't fall into temptation to set any additional port mappings in `core/docker-compose.local.yml`, functionality will break, all should be done in `core/rathole.client.toml`.
153
+
Another note: You might wonder why ports `5080` and `5443` aren't repeated anywhere in the client config `core/rathole.client.toml`. The answer is "no need for it", we already specified port `2333` for the control channel, which will communicate all additional required information between the Rathole server and client.
151
154
152
-
Another note: You might wonder why ports `5080` and `5443` aren't repeated anywhere in the client config `core/rathole.client.toml`? The answer is "no need for it", we already specified the port `2333` of the control channel, which will communicate all additional required information between Rathole server and client.
155
+
Now that we have configured the Rathole client, we need to define Rathole client and Traefik containers.
153
156
154
-
Now that we have configured Rathole client, we need to define Rathole client and Traefik containers.
155
157
Here is the Rathole client container and the important part of the Traefik container [core/docker-compose.local.yml](https://github.com/nemanjam/traefik-proxy/blob/e8fece09e31ec99ddd21559f343d0ddea9fb55bf/core/docker-compose.local.yml):
156
158
159
+
157
160
```yml title="core/docker-compose.local.yml"
158
161
services:
159
162
@@ -200,17 +203,17 @@ services:
200
203
# other config...
201
204
```
202
205
203
-
Let's start with Rathole service. Similarly line for server, we run the Rathole binary, this time in client mode with `--client` and we pass the client config file `/config/rathole.client.toml` which we also bind mount as volume. Important part, we set both Rathole and Traefik containers on the same **external** network `proxy` so they can communicate with each other and with the host.
206
+
Let's start with the Rathole service. Similarly to the server command, we run the Rathole binary, this time in client mode with `--client` and we pass the client config file `/config/rathole.client.toml` which we also bind mount as volume. An important part is that we set both the Rathole and Traefik containers on the same **external** network `proxy` so they can communicate with each other and with the host.
204
207
205
208
Additional notes about the Rathole image:
206
209
207
-
- Always make sure to use the same Rathole image version for both server and client for compatibility.
208
-
- `x86`- By default Rathole provides only the `x86` image, if your home server uses that architecture you are good.
209
-
- `ARM`- If you have ARM home server (e.g. Raspberry Pi) you will have to build the image yourself or use a prebuilt, unofficial one. **Avoid** building images on lowpower ARM singleboard computers, it will take a long time and a lot of RAM and CPU power. Instead either pre-build one yourself and push to Dockerhub or you can reuse mine `nemanjamitic/my-rathole-arm64:v1.0` image (uses Rathole `v0.5.0`).
210
+
- Always make sure to use the same Rathole image version for both the server and client for compatibility.
211
+
- `x86`- By default, Rathole provides only the `x86` image. If your home server uses that architecture, you are good to go.
212
+
- `ARM`- If you have an ARM home server (e.g., Raspberry Pi), you will have to build the image yourself or use a prebuilt, unofficial one. **Avoid** building images on low-power ARM single-board computers, as it will take a long time and require a lot of RAM and CPU power. Instead, either pre-build one yourself and push it to Docker Hub, or you can reuse my `nemanjamitic/my-rathole-arm64:v1.0` image (which uses Rathole `v0.5.0`).
210
213
211
-
Now the Traefik container. It must be on the same `proxy` external network same as Rathole. Another important part: It must **wait** for Rathole container to boot up `depends_on: rathole` because the traffic will come from the Rathole tunnel. **Do not** expose ports `80` and `443`, Rathole already bound to those Traefik container ports, as we defined in the Rathole client config `core/rathole.client.toml`.
214
+
Now, the Traefik container. It must be on the same `proxy` external network as Rathole. Another important part: It must **wait** for the Rathole container to boot up `depends_on: rathole`, because the traffic will come from the Rathole tunnel. **Do not** expose ports `80` and `443`, Rathole has already bound those Traefik container ports, as we defined in the Rathole client config `core/rathole.client.toml`.
212
215
213
-
The rest of the Traefik container definition is left out here, because it's the usual configuration, unrelated to Rathole tunnel. Bellow is the quick reminder about general Traefik configuration.
216
+
The rest of the Traefik container definition is left out here because it's the usual configuration, unrelated to the Rathole tunnel. Below is a quick reminder about the general Traefik configuration.
214
217
215
218
**Traefik reminder**
216
219
@@ -273,7 +276,7 @@ docker compose -f docker-compose.local.yml up -d
273
276
274
277
## Exposing multiple servers
275
278
276
-
Fortunately Rathole made it trivial to run multiple tunnels using a single Rathole server. We don't need to open any additional ports or run multiple container instances. We just use the different tunnel name e.g. `server.services.traefik-http` and the value for the `token` for each tunnel - service, that's it.
279
+
Fortunately, Rathole makes it trivial to run multiple tunnels using a single Rathole server. We don't need to open any additional ports or run multiple container instances. We just use a different tunnel name, e.g., `server.services.traefik-http`, and the value for the `token` for each tunnel/service. That's it.
0 commit comments