Interested in getting involved with world changing open source software? Check out the next (WIP) iteration of this project: https://github.com/fractalnetworksco/fractal-link
Jump to Getting Started
This project automates the provisioning of Reverse Proxy-over-VPN (RPoVPN) WireGuard tunnels with Caddy and NGINX. It is particularly well suited for exposing docker compose services defined in a docker-compose
file to the public Internet. There's no code or APIs, just an ultra generic NGINX config and some short provisioning bash script. TLS certs are provisioned automatically with Caddy's Automatic HTTPS feature via Let's Encrypt or ZeroSSL.
RPoVPN is a common strategy for remotely accessing applications self-hosted at home. It solves problems such as:
Using RPoVPN is ideal for self-hosting from both a network security and privacy perspective:
A
record for a domain name.gateway
, typically a cloud VPS (Hetzner, Digital Ocean, etc..) with the following requirements:cat /proc/sys/net/ipv4/ip_local_port_range
open to the Internet.docker
, git
& make
installed on the Gatewaydocker-compose.yml
that you would like to expose to the Internet.docker
, git
& make
installed locallyPoint *.mydomain.com
(DNS A Record) to the IPv4 & IPv6 address of your VPS Gateway host.
Connect to the gateway
via SSH and setup the gateway
service:
foo@gateway:~$ git clone ... && cd selfhosted-gateway
foo@gateway:~/selfhosted-gateway$ make docker
foo@gateway:~/selfhosted-gateway$ make setup
foo@gateway:~/selfhosted-gateway$ make gateway
To generate a link
docker compose snippet run the following commands from the client
:
foo@local:~$ git clone ... && cd selfhosted-gateway
foo@local:~/selfhosted-gateway$ make docker
foo@local:~/selfhosted-gateway$ make link GATEWAY=root@123.456.789.101 FQDN=nginx.mydomain.com EXPOSE=nginx:80
# docker compose --env-file ./nginx-mydomain-com.env ...
link:
image: fractalnetworks/gateway-client:latest
environment:
LINK_DOMAIN: nginx.mydomain.com
EXPOSE: nginx:80
GATEWAY_CLIENT_WG_PRIVKEY: 4M7Ap0euzTxq7gTA/WIYIt3nU+i2FvHUc9eYTFQ2CGI=
GATEWAY_LINK_WG_PUBKEY: Wipd6Pv7ttmII4/Oj82I5tmGZwuw6ucsE3G+hwsMR08=
GATEWAY_ENDPOINT: 123.456.789.101:49185
cap_add:
- NET_ADMIN
The command will also generate a .env
file in your current directory:
foo@local:~/selfhosted-gateway$ cat ./nginx-mydomain-com.env
EXPOSE=nginx:80
GATEWAY_ENDPOINT=123.456.789.101:49185
GATEWAY_LINK_WG_PUBKEY=Wipd6Pv7ttmII4/Oj82I5tmGZwuw6ucsE3G+hwsMR08=
LINK_DOMAIN=nginx.mydomain.com
WG_PRIVKEY=4M7Ap0euzTxq7gTA/WIYIt3nU+i2FvHUc9eYTFQ2CGI=
Add the link
service to your existing docker-compose.yml
file:
version: '3.9'
services:
nginx:
image: nginx:latest
link:
image: fractalnetworks/gateway-client:latest
environment:
LINK_DOMAIN: nginx.mydomain.com
EXPOSE: nginx:80
GATEWAY_CLIENT_WG_PRIVKEY: 4M7Ap0euzTxq7gTA/WIYIt3nU+i2FvHUc9eYTFQ2CGI=
GATEWAY_LINK_WG_PUBKEY: Wipd6Pv7ttmII4/Oj82I5tmGZwuw6ucsE3G+hwsMR08=
GATEWAY_ENDPOINT: 123.456.789.101:49185
cap_add:
- NET_ADMIN
src/create-link/link-compose-snippet.yml
..env
file to use when running docker-compose
commands:
foo@local:~/selfhosted-gateway$ docker compose --env-file ./nginx-mydomain-com.env up -d
See Docker Compose documentation "Substitute environment variables with an .env file" for more information.
Start your docker compose project as you would normally (docker compose up -d
).
This will establish the link
to the gateway
and automatically provision a TLS-certificate.
You may repeat steps 3-5 for as many services as you would like to expose using the same gateway
├── ...
└── src
├── client-link # WireGuard instance for the client. Also handles SSL termination with Caddy
│ └── ...
├── create-link # CLI script for establishing a link.
│ └── ...
├── gateway # NGINX reverse proxy to distribute requests to each gateway-link instance.
│ └── ...
└── gateway-link # WireGuard instance for the gateway.
└── ...
Link
- A dedicated WireGuard tunnel between a local container (client) and the remote container running on the Gateway through which Reverse Proxy traffic is routed. A link is comprised of 2 pieces, the local or client link and the gateway or remote link.In the event you already have a reverse proxy which performs SSL termination for your apps/services you can enable FORWARD_ONLY
mode. Suppose you are using Traefik for SSL termination:
EXPOSE_HTTPS
and FORWARD_ONLY
version: '3.9'
services:
app:
image: traefik:latest
link:
image: fractalnetworks/gateway-client:latest
environment:
LINK_DOMAIN: sub.mydomain.com
EXPOSE: app:80
EXPOSE_HTTPS: app:443
FORWARD_ONLY: "True"
GATEWAY_CLIENT_WG_PRIVKEY: 4M7Ap0euzTxq7gTA/WIYIt3nU+i2FvHUc9eYTFQ2CGI=
GATEWAY_LINK_WG_PUBKEY: Wipd6Pv7ttmII4/Oj82I5tmGZwuw6ucsE3G+hwsMR08=
GATEWAY_ENDPOINT: 5.161.127.102:49185
cap_add:
- NET_ADMIN
You will see logs from the link container indicating it is in forward only mode:
traefikv2_link.1.qvijxtwiu0wb@docker01 | + socat TCP4-LISTEN:8443,fork,reuseaddr TCP4:app:443,reuseaddr
traefikv2_link.1.qvijxtwiu0wb@docker01 | + socat TCP4-LISTEN:8080,fork,reuseaddr TCP4:app:80,reuseaddr
If the backend container already has a TLS certification, the connection between Caddy and the backend container can be switched to TLS/HTTPS with the CADDY_TLS_PROXY
parameter.
In case the certificate is self-signed, the addition CADDY_TLS_INSECURE
can be used to deactivate the certificate check.
This will continue to create a certificate for the backend via Let's Encrypt.
version: '3.9'
services:
app:
image: traefik:latest
link:
image: fractalnetworks/gateway-client:latest
environment:
LINK_DOMAIN: sub.mydomain.com
EXPOSE: https://app:80
CADDY_TLS_PROXY: true
# Optional
# CADDY_TLS_INSECURE: true
GATEWAY_CLIENT_WG_PRIVKEY: 4M7Ap0euzTxq7gTA/WIYIt3nU+i2FvHUc9eYTFQ2CGI=
GATEWAY_LINK_WG_PUBKEY: Wipd6Pv7ttmII4/Oj82I5tmGZwuw6ucsE3G+hwsMR08=
GATEWAY_ENDPOINT: 5.161.127.102:49185
cap_add:
- NET_ADMIN
$ docker ps
The goal of this project is to make self-hosting more accessible and reproducible. This project leverages a "ZeroTrust" network architecture. Each "Link" provides a dedicated WireGuard tunnel that is isolated from other containers and the underlying host. This isolation is provided by Docker Compose's creation of a private Docker network for each compose project.
Yes, just expose ports in your Docker host as you would normally:
ports:
- 80:80
- 443:443
Community support is available via our Matrix Channel https://matrix.to/#/#fractal:ether.ai