Skip to content

Commit

Permalink
Remove Python dependency, enable proxy protocol (#38)
Browse files Browse the repository at this point in the history
* Remove python dep
  • Loading branch information
thebalaa authored Feb 25, 2024
1 parent 75b66e5 commit 7a7b2d6
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ link-macos:
docker run -v /run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock -e SSH_AUTH_SOCK="/run/host-services/ssh-auth.sock" --rm -it fractalnetworks/gateway-cli:latest $(GATEWAY) $(FQDN) $(EXPOSE)

link-ci:
./ci/create-link-ci.sh $(GATEWAY) $(FQDN) $(EXPOSE)
./ci/create-link-ci.sh gateway-sshd app.example.com nginx:80
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
**Jump to [Getting Started](#getting-started)**
## Features and Benefits
- Docker native self-hosted alternative to Cloudflare Tunnels, Tailscale Funnel, ngrok and others.
- Entirely self-hosted and self-managed, both local and remote components tunneling components provided.
- Entirely self-hosted and self-managed, includes local and remote tunneling components.
- No custom code, this project leverages existing battled tested FOSS components:
- WireGuard
- Nginx (Gateway)
- Caddy (Client)
- WireGuard
- Nginx (Gateway)
- Caddy (Client)
- Automatic client side HTTPS cert provisioning thanks to Caddy's automatic https.
- Remote client IPs passed to local container via proxy protocol
- Enable basic authentication by specifying env variable containig username and password
- Proxy generic TCP/UDP traffic to localhost with socat

## Video Overview & Setup Guide
<a href="http://www.youtube.com/watch?feature=player_embedded&v=VCH8-XOikQc" target="_blank">
Expand Down Expand Up @@ -35,16 +38,16 @@ This project automates the provisioning of **Reverse Proxy-over-VPN (RPoVPN)** W

### Prerequisites
- Domain
- Ability to create an `A` record for a domain name.
- Ability to create an `A` record for a domain name.
- Gateway
- A publically addressable Linux host to act as the `gateway`, typically a cloud VPS (Hetzner, Digital Ocean, etc..) with the following requirements:
- SSH access
- Ports 80/443 open (http/https)
- The UDP port range listed by `cat /proc/sys/net/ipv4/ip_local_port_range` open to the Internet.
- `docker`, `git` & `make` installed on the Gateway
- A publically addressable Linux host to act as the `gateway`, typically a cloud VPS (Hetzner, Digital Ocean, etc..) with the following requirements:
- SSH access
- Ports 80/443 open (http/https)
- The UDP port range listed by `cat /proc/sys/net/ipv4/ip_local_port_range` open to the Internet.
- `docker`, `git` & `make` installed on the Gateway
- Client
- An existing `docker-compose.yml` that you would like to expose to the Internet.
- `docker`, `git` & `make` installed locally
- An existing `docker-compose.yml` that you would like to expose to the Internet.
- `docker`, `git` & `make` installed locally

### Steps
1. Point `*.mydomain.com` (DNS A Record) to the IPv4 & IPv6 address of your VPS Gateway host.
Expand Down
3 changes: 2 additions & 1 deletion ci/create-link-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ docker network create gateway || true # create docker network if not exists
docker compose up -d --build
eval $(ssh-agent -s)
ssh-add ./gateway-sim-key
#
# generate a docker compose to test the generated link
cat test-link.template.yaml > test-link.yaml
docker run --network gateway -e SSH_AGENT_PID=$SSH_AGENT_PID -e SSH_AUTH_SOCK=$SSH_AUTH_SOCK -v $SSH_AUTH_SOCK:$SSH_AUTH_SOCK --rm fractalnetworks/gateway-cli:latest $1 $2 $3 >> test-link.yaml
cat network.yaml >> test-link.yaml
# set the gateway endpoint to the gateway link container
sed -i 's/^\(\s*GATEWAY_ENDPOINT:\).*/\1 app-example-com:18521/' test-link.yaml
docker compose -f test-link.yaml up -d
docker compose -f test-link.yaml exec link ping 10.0.0.1 -c 2
Expand Down
10 changes: 0 additions & 10 deletions ci/link.yaml

This file was deleted.

3 changes: 1 addition & 2 deletions ci/test-link.template.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
version: '3.9'

# need this
networks:
gateway:
external: true

services:
services:
11 changes: 10 additions & 1 deletion src/client-link/Caddyfile.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
http_port 8080
https_port 8443
servers {
listener_wrappers {
proxy_protocol
tls
}
}
}

$LINK_DOMAIN {
Expand All @@ -11,4 +17,7 @@ $LINK_DOMAIN {
# BasicAuthPlaceholder

reverse_proxy $EXPOSE
}

# TODO optional internal tls
# tls internal
}
2 changes: 1 addition & 1 deletion src/client-link/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ END
PASSWORD=$(echo $BASIC_AUTH | cut -d':' -f2)
HASHED_PASSWORD=$(caddy hash-password --plaintext $PASSWORD)
# Construct the basic auth configuration
BASIC_AUTH_CONFIG=" basicauth /* {\n $USERNAME $HASHED_PASSWORD\n }\n"
BASIC_AUTH_CONFIG=" basicauth /* {\n "$USERNAME" "$HASHED_PASSWORD"\n }\n"
# Insert basic auth config into the final Caddyfile, replacing the placeholder
sed -i "s|# BasicAuthPlaceholder|$BASIC_AUTH_CONFIG|" /etc/Caddyfile.template
fi
Expand Down
21 changes: 19 additions & 2 deletions src/create-link/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@

set -e

function fqdn_to_container_name() {
local fqdn="$1"

# Check if the FQDN is non-empty
if [[ -z "$fqdn" ]]; then
echo "Error: No FQDN provided."
return 1
fi

# Replace all dots with dashes
CONTAINER_NAME="${fqdn//./-}"

echo "$CONTAINER_NAME"
}

SSH_HOST=$1
SSH_PORT=22
# split port from SSH_HOST if SSH_HOST contains :
Expand All @@ -14,13 +29,15 @@ fi

export LINK_DOMAIN=$2
export EXPOSE=$3
export WG_PRIVKEY=$(wg genkey)
WG_PRIVKEY=$(wg genkey)
export WG_PRIVKEY
# Nginx uses Docker DNS resolver for dynamic mapping of LINK_DOMAIN to link container hostnames, see nginx/*.conf
# This is the magic.
# NOTE: All traffic for `*.subdomain.domain.tld`` will be routed to the container named `subdomain-domain-tld``
# Also supports `subdomain.domain.tld` as well as apex `domain.tld`
# *.domain.tld should resolve to the Gateway's public IPv4 address
export CONTAINER_NAME=$(echo $LINK_DOMAIN|python3 -c 'fqdn=input();print("-".join(fqdn.split(".")[-4:]))')
CONTAINER_NAME=$(fqdn_to_container_name "$LINK_DOMAIN")
export CONTAINER_NAME


LINK_CLIENT_WG_PUBKEY=$(echo $WG_PRIVKEY|wg pubkey)
Expand Down
4 changes: 1 addition & 3 deletions src/gateway/nginx.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ events {
~^(?<subdomain>.+?)?\.(?<domain>.+)\.(?<tld>.+)$ $subdomain-$domain-$tld:443;
~^(?<domain>.+)\.(?<tld>.+)$ $domain-$tld:443;
}

proxy_protocol on;
server {
listen 443;

Expand All @@ -46,6 +46,4 @@ events {
proxy_pass $targetBackend;
ssl_preread on;
}


}

0 comments on commit 7a7b2d6

Please sign in to comment.