Skip to content

Latest commit

 

History

31 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Aleph Domain Gateway

A Python FastAPI gateway that gives every Aleph VM a deterministic *.2n6.me URL via L4 SNI passthrough on HAProxy.

How It Works

  1. Sync — Fetches all INSTANCE messages from the Aleph network API
  2. Derive — Converts each instance hash to a 4-word BIP-39 subdomain (e.g., swift-falcon-arrow-piano.2n6.me)
  3. Resolve — Bulk-scans all CRNs (Compute Resource Nodes) to find running VMs and their IPv6 addresses
  4. Route — Generates HAProxy map files for SNI-based routing
User Request                    HAProxy                         Aleph VM
     |                            |                                |
     |  swift-falcon-arrow-piano.2n6.me                           |
     |--------------------------->|                                |
     |                            |  SNI lookup → IPv6             |
     |                            |------------------------------->|
     |                            |<-------------------------------|
     |<---------------------------|                                |

Subdomain Generation

Subdomains are derived deterministically from instance hashes using the BIP-39 wordlist (2048 words). The top 44 bits of the hash select 4 words (11 bits each):

Instance Hash: a3f8b2c1d4e5f6...
                ↓
Top 44 bits → 4 × 11-bit indices
                ↓
Subdomain: physical-sheriff-race-soul

Same hash always produces the same subdomain. No database lookup needed.

Installation

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Running

# Development
python run.py

# Production
uvicorn gateway.main:app --host 0.0.0.0 --port 8000

Configuration

Environment variables or create_app() parameters:

Env var create_app() param Default Description
domain 2n6.me Base domain for subdomains
cache_path /var/lib/gateway/cache.json Persistent cache location
haproxy_config_dir /etc/haproxy HAProxy config directory
HAPROXY_RELOAD_CMD haproxy_reload_command systemctl reload haproxy Command to reload HAProxy
sync_interval 300 Seconds between syncs
CERT_PATH cert_path None Path for combined PEM (e.g., /etc/haproxy/certs/api.2n6.me.pem). TLS disabled if unset.
CERT_EMAIL cert_email None Email for Let's Encrypt. Required for auto-provisioning.
ACME_WEBROOT acme_webroot /var/lib/gateway/acme Directory for ACME HTTP-01 challenge files

API Endpoints

GET /api/lookup/{subdomain}

Look up an instance by its subdomain.

{
  "subdomain": "swift-falcon-arrow-piano",
  "url": "swift-falcon-arrow-piano.2n6.me",
  "instance_hash": "a3f8b2c1d4e5f6...",
  "ipv6": "2001:db8::1",
  "active": true
}

GET /api/hash/{instance_hash}

Look up an instance by its hash.

{
  "instance_hash": "a3f8b2c1d4e5f6...",
  "subdomain": "physical-sheriff-race-soul",
  "url": "physical-sheriff-race-soul.2n6.me",
  "ipv6": "2001:db8::1",
  "active": true
}

GET /api/status

Gateway status.

{
  "instance_count": 425,
  "route_count": 184,
  "last_sync_time": 1700000000.0,
  "domain": "2n6.me"
}

POST /api/sync

Trigger an immediate sync.

Architecture

gateway/
├── main.py          # FastAPI app, lifespan, API endpoints, ACME challenge
├── aleph_sync.py    # Fetches INSTANCE messages from Aleph API
├── subdomain.py     # BIP-39 hash-to-subdomain conversion
├── resolver.py      # Bulk CRN scanning for IPv6 resolution
├── haproxy.py       # HAProxy config generation (conditional TLS)
├── tls.py           # Let's Encrypt cert automation
└── cache.py         # Persistent JSON cache

Data Flow

Aleph API                    Gateway                         CRNs
    |                           |                              |
    |  GET /messages.json       |                              |
    |<--------------------------|                              |
    |  INSTANCE messages        |                              |
    |-------------------------->|                              |
    |                           |                              |
    |                           |  GET /about/executions/list  |
    |                           |----------------------------->|
    |                           |  {hash: {ipv6: ...}}         |
    |                           |<-----------------------------|
    |                           |                              |
    |                           |  Write HAProxy maps          |
    |                           |---> sni.map, backends.cfg    |

HAProxy Integration

The gateway generates the full haproxy.cfg on each sync cycle (base config + dynamic backends). It also writes:

  • sni.map — Maps FQDN to backend name for TLS SNI routing
  • host.map — Maps FQDN to backend name for HTTP Host header routing

The management API is exposed publicly via api.2n6.me through an HAProxy ACL (no extra DNS record needed since the wildcard covers it).

See haproxy/haproxy.cfg.template for the base config reference.

TLS for the API

The API (api.2n6.me) supports automatic HTTPS via Let's Encrypt. HAProxy's :443 frontend is TCP mode for VM SNI passthrough, so the API uses the loopback pattern to selectively terminate TLS:

:443 ft_ssl (TCP) ──┬── SNI api.2n6.me ──→ bk_api_loopback (127.0.0.1:8443)
                     │                           ↓
                     │                     ft_api_tls (TLS terminated, HTTP)
                     │                           ↓
                     │                     bk_gateway_api (127.0.0.1:8000 → FastAPI)
                     │
                     └── SNI *.2n6.me ──→ VM backends (passthrough, unchanged)

:80 ft_http (HTTP) ──┬── /.well-known/acme-challenge/* ──→ bk_gateway_api
                      ├── api.2n6.me (other) ──→ 301 redirect to HTTPS
                      └── *.2n6.me ──→ VM HTTP backends (unchanged)

Lifecycle:

  1. First start (no cert): HAProxy config is HTTP-only, ACME endpoint active. A background task runs certbot, obtains the cert, builds the combined PEM, installs a renewal hook, and regenerates HAProxy config with TLS. The API becomes HTTPS within ~30s of first boot.
  2. Subsequent starts (cert exists): HAProxy config immediately includes TLS sections.
  3. Renewal: Certbot's systemd timer runs certbot renew twice daily. The deploy hook at /etc/letsencrypt/renewal-hooks/deploy/gateway.sh rebuilds the combined PEM and reloads HAProxy automatically.

Deployment

Prerequisites

  • A server with a public IPv4 and IPv6 address
  • A wildcard DNS record (*.yourdomain) pointing to the server
  • Python 3.12+
  • HAProxy 2.8+

Server Setup

These steps were used to deploy to the current production server (46.247.131.199 / 2a05:6e02:1067:f510:d021:8dff:fe1a:a478).

1. Install system packages

sudo apt-get update && sudo apt-get install -y haproxy python3-venv certbot

2. Deploy the gateway code

sudo mkdir -p /opt/aleph-domain-gateway
sudo chown ubuntu:ubuntu /opt/aleph-domain-gateway

# From development machine:
rsync -avz --exclude='.venv' --exclude='__pycache__' --exclude='.pytest_cache' --exclude='.git' \
  ./ ubuntu@<server>:/opt/aleph-domain-gateway/

3. Create Python environment

cd /opt/aleph-domain-gateway
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

4. Create data and cert directories

sudo mkdir -p /var/lib/gateway
sudo mkdir -p /var/lib/gateway/acme/.well-known/acme-challenge
sudo mkdir -p /etc/haproxy/certs
sudo chown -R ubuntu:ubuntu /var/lib/gateway /etc/haproxy/certs

5. Configure HAProxy

The gateway writes haproxy.cfg directly, so it needs write access:

sudo chown ubuntu:ubuntu /etc/haproxy/haproxy.cfg
sudo touch /etc/haproxy/sni.map /etc/haproxy/host.map
sudo chown ubuntu:ubuntu /etc/haproxy/sni.map /etc/haproxy/host.map

Allow the gateway user to reload HAProxy and run certbot without a password:

echo 'ubuntu ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload haproxy' | sudo tee /etc/sudoers.d/gateway-haproxy
sudo chmod 440 /etc/sudoers.d/gateway-haproxy

echo 'ubuntu ALL=(ALL) NOPASSWD: /usr/bin/certbot, /usr/bin/sh -c cat /etc/letsencrypt/*, /usr/bin/tee /etc/letsencrypt/*, /usr/bin/chmod * /etc/letsencrypt/*' | sudo tee /etc/sudoers.d/gateway-certbot
sudo chmod 440 /etc/sudoers.d/gateway-certbot

6. Create systemd service

cat <<'EOF' | sudo tee /etc/systemd/system/aleph-gateway.service
[Unit]
Description=Aleph Domain Gateway
After=network.target haproxy.service

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/aleph-domain-gateway
Environment=CERT_PATH=/etc/haproxy/certs/api.2n6.me.pem
Environment=CERT_EMAIL=letsencrypt@aleph.cloud
Environment=ACME_WEBROOT=/var/lib/gateway/acme
Environment="HAPROXY_RELOAD_CMD=sudo systemctl reload haproxy"
ExecStart=/opt/aleph-domain-gateway/.venv/bin/uvicorn gateway.main:app --host 127.0.0.1 --port 8000
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now aleph-gateway

To disable automatic TLS, omit the CERT_PATH and CERT_EMAIL lines.

7. Configure DNS

Add a wildcard record for your domain pointing to the server. For Gandi:

Record Type Value
* A 46.247.131.199
* AAAA 2a05:6e02:1067:f510:d021:8dff:fe1a:a478

Verifying the deployment

# Check gateway is running
curl https://api.2n6.me/api/status

# Look up a specific instance
curl https://api.2n6.me/api/hash/<instance_hash>

# Check HTTP redirects to HTTPS
curl -sI http://api.2n6.me/api/status
# → 301 Moved Permanently, Location: https://...

# Check TLS certificate
echo | openssl s_client -connect api.2n6.me:443 -servername api.2n6.me 2>/dev/null | openssl x509 -noout -subject -dates

# Check HAProxy is routing VMs
curl -sk https://<subdomain>.2n6.me/

Updating

# From development machine:
rsync -avz --exclude='.venv' --exclude='__pycache__' --exclude='.pytest_cache' --exclude='.git' \
  ./ ubuntu@<server>:/opt/aleph-domain-gateway/

# On server:
sudo systemctl restart aleph-gateway

The gateway takes ~30-40 seconds to start (syncs instances + scans all CRNs).

Testing

pytest tests/ -v

External APIs

API Purpose
api2.aleph.im/api/v0/messages.json Fetch INSTANCE messages
crns-list.aleph.sh/crns.json Bulk list of all CRN URLs
{crn}/v2/about/executions/list Running VMs on a CRN (with actual IPv6)

License

MIT

About

Automatic matching of a subdomain to an aleph instance through a transparent proxy

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages