16 KiB
laantungir.net: Tor + FIPS + Clearnet Access Plan
Current Server State (discovered via SSH)
| Component | Status |
|---|---|
| OS | Ubuntu 24.04.3 LTS (VM410) |
| nginx | 1.24.0, running, with RTMP module |
| Tor | 0.4.8.10, running, SOCKS on 127.0.0.1:9050 |
| Onion service | kn2jam4kyz6s5wacyozo3do3d2zsvh4to45uh7xliulwdust6zjuvnad.onion — forwards ports 80/443 to 127.0.0.1:80/443 |
| FIPS | Not installed |
| Nostr relay | c-relay-pg (C Nostr Relay, PostgreSQL backend) on port 8888 |
| Blossom | didactyl.service on 127.0.0.1:8484 |
| Website | Static site served by nginx |
| Gitea | Port 3000 (web) + 2222 (SSH) |
| PostgreSQL | 18-main on 127.0.0.1:5432 |
| RTMP | nginx-rtmp on port 1935 with auth + HLS |
| Streaming | OBS → RTMP :1935/publish (auth via rtmp-auth.service on :8091) → ffmpeg forward → :1935/live → HLS at /var/www/html/hls/ |
| Stream stats | stream-stats.service on 127.0.0.1:8092, nginx internal at 127.0.0.1:8080/stat |
| simon.service | 127.0.0.1:8485 (unknown purpose) |
Video Streaming Architecture
OBS (remote)
│
│ RTMP push to :1935/publish/{show}/{variant}/{secret_key}
│
▼
nginx-rtmp :1935
├── on_publish → 127.0.0.1:8091/auth (rtmp-auth.service, validates secret key)
├── exec_push → /usr/local/bin/rtmp-forward.sh
│ └── ffmpeg -c copy → rtmp://127.0.0.1:1935/live/{show}/{variant}
│
▼
nginx-rtmp :1935/live
├── HLS output → /var/www/html/hls/{show}/{variant}/index.m3u8
├── generate-master-playlist.py → /var/www/html/hls/{show}/master.m3u8
└── RTMP playback (allow play all)
Viewer access (clearnet): https://laantungir.net/hls/{show}/{variant}/index.m3u8 (HLS) or rtmp://laantungir.net/live/{show}/{variant} (RTMP direct)
Current shows in HLS: beat-topia, dub-techno, music, the-world-is-coming-to-an-end
Current nginx virtual hosts (from /etc/nginx/conf.d/default.conf)
| Domain | Port 80 | Port 443 | Backend |
|---|---|---|---|
laantungir.net (+ .com, .org, www) |
Redirect to HTTPS | TLS, static site | Local files |
relay.laantungir.net (+ .com, .org) |
Redirect to HTTPS | TLS, WebSocket proxy | 127.0.0.1:8888 (c-relay-pg) |
blossom.laantungir.net |
Redirect to HTTPS | TLS, proxy | 127.0.0.1:8484 (didactyl) |
git.laantungir.net (+ .com, .org) |
Redirect to HTTPS | TLS, proxy | 127.0.0.1:3000 (gitea) |
auth.laantungir.net (+ .com, .org) |
Redirect to HTTPS | TLS, proxy | 127.0.0.1:3000 (gitea) |
Current Tor onion service
HiddenServiceDir /var/lib/tor/nostr_client/
HiddenServicePort 80 127.0.0.1:80
HiddenServicePort 443 127.0.0.1:443
Onion address: kn2jam4kyz6s5wacyozo3do3d2zsvh4to45uh7xliulwdust6zjuvnad.onion
Problem: The onion service forwards to nginx ports 80/443, but nginx virtual hosts use server_name matching. Tor clients send the .onion hostname, which doesn't match any server_name directive — so nginx falls through to the default server block. This needs to be fixed.
Target Architecture
┌─────────────────────────────────────────────────────────┐
│ laantungir.net (VM410) │
│ │
Clearnet user ───►│─── eth0 :80/:443 ──► nginx ──┬── / ──► static site │
│ ├── relay ──► :8888 │
│ └── blossom ──► :8484 │
│ │
Tor user ────────►│─── tor :80/:443 ──► nginx ──┬── / ──► static site │
│ (via .onion) ├── relay ──► :8888 │
│ └── blossom ──► :8484 │
│ │
FIPS user ───────►│─── fips0 :80 ──► nginx ──┬── / ──► static site │
│ (via fd00::/8) ├── relay ──► :8888 │
│ └── blossom ──► :8484 │
│ │
FIPS+Tor user ───►│─── tor transport ──► fips0 ──► nginx (same as FIPS) │
│ (FIPS peering over Tor) │
│ │
│ FIPS daemon: UDP :2121, TCP :8443, Tor .onion:8443 │
└─────────────────────────────────────────────────────────┘
How each access path works
| Path | User needs | Connects via | Encryption |
|---|---|---|---|
| Clearnet | Browser | https://relay.laantungir.net |
TLS (Let's Encrypt) |
| Tor | Tor Browser | http://kn2jam...nad.onion/relay/ or subdomain routing |
Tor onion encryption |
| FIPS | FIPS node | ws://npub1<server-npub>.fips |
Noise IK + Noise XK (double) |
| FIPS over Tor | FIPS node + Tor | FIPS peers via Tor transport | Tor + Noise IK + Noise XK (triple) |
Implementation Plan
Phase 1: Fix Tor Onion Service Routing
The existing onion service already forwards ports 80/443 to nginx, but nginx doesn't know how to route .onion hostnames. Two approaches:
Option A: Path-based routing (single .onion, recommended)
Add the .onion hostname to each server_name directive:
# In the relay server block:
server_name relay.laantungir.com relay.laantungir.net relay.laantungir.org
kn2jam4kyz6s5wacyozo3do3d2zsvh4to45uh7xliulwdust6zjuvnad.onion;
Tor users would access:
- Website:
http://kn2jam...nad.onion/ - Relay:
ws://kn2jam...nad.onion/(if relay is the default server) - Blossom:
http://kn2jam...nad.onion/blossom/(needs path-based routing)
Problem: relay and blossom are separate subdomains, not paths. With a single .onion, we need a way to distinguish them.
Option B: Separate onion services per service (cleaner)
Create three onion services in torrc:
# Website
HiddenServiceDir /var/lib/tor/hs_website/
HiddenServicePort 80 127.0.0.1:80
HiddenServicePort 443 127.0.0.1:443
# Relay
HiddenServiceDir /var/lib/tor/hs_relay/
HiddenServicePort 80 127.0.0.1:80
HiddenServicePort 443 127.0.0.1:443
# Blossom
HiddenServiceDir /var/lib/tor/hs_blossom/
HiddenServicePort 80 127.0.0.1:80
HiddenServicePort 443 127.0.0.1:443
Then add each .onion to the corresponding nginx server_name. Each service gets its own .onion address. Tor users connect to the right service by using the right .onion.
Option C: Single .onion with default-server routing (simplest)
Make the relay the default server (it's the most important service), and add the .onion to the website and blossom blocks too. Use a port-based split:
HiddenServiceDir /var/lib/tor/nostr_client/
HiddenServicePort 80 127.0.0.1:80 # website
HiddenServicePort 443 127.0.0.1:443 # website (TLS)
HiddenServicePort 7777 127.0.0.1:8888 # relay direct (no nginx)
HiddenServicePort 8484 127.0.0.1:8484 # blossom direct (no nginx)
Tor users connect to different ports on the same .onion:
http://kn2jam...nad.onion/→ websitews://kn2jam...nad.onion:7777/→ relay (direct to c-relay-pg)http://kn2jam...nad.onion:8484/→ blossom (direct to didactyl)
Decision: Option B — Separate .onion per service
This gives the best compatibility with existing programs. Nostr clients expect to connect to a relay at a WebSocket URL like ws://host/. Blossom clients expect http://host/. Separate .onion addresses mean each service gets its own hostname — no path rewriting, no port gymnastics. Existing clients work unmodified.
Steps for Phase 1
- Add three HiddenService blocks to
/etc/tor/torrc(website, relay, blossom) - Add each
.onionhostname to the corresponding nginxserver_namedirective - Add plain-HTTP server blocks for
.onionaccess (Tor already encrypts; no TLS needed) - Restart Tor (generates new onion keys), then restart nginx
- Test from Tor Browser
Phase 2: Install and Configure FIPS
2.1 Build and install FIPS
# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# Install build deps for BLE (optional, can skip with --no-default-features)
sudo apt install -y bluez libdbus-1-dev
# Clone and build
git clone https://github.com/jmcorgan/fips.git
cd fips
cargo build --release
# Install via .deb
cargo install cargo-deb
cargo deb
sudo dpkg -i target/debian/fips_*.deb
2.2 Configure FIPS
Edit /etc/fips/fips.yaml:
node:
identity:
persistent: true # Stable npub for the server
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
port: 5354
transports:
udp:
bind_addr: "0.0.0.0:2121"
tcp:
bind_addr: "0.0.0.0:8443"
tor:
mode: "directory"
socks_addr: "127.0.0.1:9050"
directory_service:
hostname_file: "/var/lib/tor/fips_mesh/hostname"
bind_addr: "127.0.0.1:9443"
peers:
- npub: "npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98"
alias: "fips-test-node"
addresses:
- transport: udp
addr: "217.77.8.91:2121"
connect_policy: auto_connect
- npub: "npub1zv58cn7v83mxvttl70w5fwjwuclfmntv9cnmv5wmz2nzz88u5urqvdx96n"
alias: "fips.v0l.io"
addresses:
- transport: udp
addr: "fips.v0l.io:2121"
connect_policy: auto_connect
2.3 Add FIPS Tor onion service to torrc
Add a separate onion service for FIPS mesh peering:
# FIPS mesh peering (separate from web services)
HiddenServiceDir /var/lib/tor/fips_mesh/
HiddenServicePort 9443 127.0.0.1:9443
2.4 Open firewall for FIPS
sudo ufw allow 2121/udp comment "FIPS mesh UDP"
sudo ufw allow 8443/tcp comment "FIPS mesh TCP"
2.5 Start FIPS
sudo systemctl enable --now fips
sudo systemctl enable --now fips-dns
2.6 Configure DNS for .fips resolution on the server
sudo resolvectl dns fips0 127.0.0.1:5354
sudo resolvectl domain fips0 ~fips
Phase 3: Make Services Reachable Over FIPS
3.1 Make nginx listen on IPv6 (for FIPS fd00::/8 traffic)
Add listen [::]:80; and listen [::]:443 ssl; to each server block in /etc/nginx/conf.d/default.conf. This allows FIPS traffic (which arrives as IPv6 on the fips0 TUN interface) to reach nginx.
3.2 Decision: Separate server blocks per service (matching Tor approach)
For maximum compatibility with existing programs, we use the same approach as Tor: each service gets its own server block matched by hostname. FIPS users use different .fips hostnames (via /etc/fips/hosts) to reach each service — just like Tor users use different .onion addresses.
Since blossom (didactyl) is a FastCGI extension of nginx, all three services must go through nginx.
# FIPS: Website
server {
listen [::]:80;
server_name ~^npub1.+\.fips$ laantungir.fips;
# Same config as the clearnet website server block
# (static site root, locations, etc.)
}
# FIPS: Relay
server {
listen [::]:80;
server_name relay.fips;
location / {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
# FIPS: Blossom
server {
listen [::]:80;
server_name blossom.fips;
# Same FastCGI config as the clearnet blossom server block
}
FIPS users access:
http://laantungir.fips/→ websitews://relay.fips/→ Nostr relay (standard WebSocket URL, works with all Nostr clients)http://blossom.fips/→ Blossom (standard HTTP, works with all Blossom clients)
The direct npub also works: http://npub1<server-npub>.fips/ → website (default)
3.3 Add /etc/fips/hosts entries
laantungir npub1<server-npub>
relay npub1<server-npub>
blossom npub1<server-npub>
This lets FIPS users access:
http://laantungir.fips/→ websitews://relay.fips/→ relay (if using path-based routing)http://blossom.fips/→ blossom
Phase 4: Enable FIPS-over-Tor (Combined)
This is already handled by Phase 2.3. The FIPS config includes a Tor transport with a dedicated onion service for mesh peering. Remote FIPS nodes can peer with this server through Tor by adding:
# On the remote FIPS node
peers:
- npub: "npub1<server-npub>"
alias: "laantungir"
addresses:
- transport: tor
addr: "<fips-mesh-onion>.onion:9443"
connect_policy: auto_connect
The remote node's FIPS traffic goes through Tor to reach this server's FIPS daemon, then the FIPS session provides end-to-end encryption on top. Triple encryption: Tor + Noise IK (hop) + Noise XK (session).
Summary of Access Paths After Implementation
Website (laantungir.net)
| Path | URL | Encryption |
|---|---|---|
| Clearnet | https://laantungir.net |
TLS |
| Tor | http://kn2jam...nad.onion/ |
Tor |
| FIPS | http://npub1<npub>.fips/ or http://laantungir.fips/ |
Noise IK+XK |
| FIPS+Tor | Same as FIPS (transport is transparent) | Tor + Noise IK+XK |
Nostr Relay (relay.laantungir.net)
| Path | URL | Encryption |
|---|---|---|
| Clearnet | wss://relay.laantungir.net |
TLS |
| Tor | ws://<relay-onion>.onion/ |
Tor |
| FIPS | ws://relay.fips/ |
Noise IK+XK |
| FIPS+Tor | Same as FIPS (transport is transparent) | Tor + Noise IK+XK |
Blossom (blossom.laantungir.net)
| Path | URL | Encryption |
|---|---|---|
| Clearnet | https://blossom.laantungir.net |
TLS |
| Tor | http://<blossom-onion>.onion/ |
Tor |
| FIPS | http://blossom.fips/ |
Noise IK+XK |
| FIPS+Tor | Same as FIPS (transport is transparent) | Tor + Noise IK+XK |
Video Streaming (laantungir.net/hls/)
| Path | URL | Encryption | Notes |
|---|---|---|---|
| Clearnet | https://laantungir.net/hls/{show}/master.m3u8 |
TLS | HLS playback via static files |
| Clearnet RTMP | rtmp://laantungir.net/live/{show}/{variant} |
None | Direct RTMP playback |
| Tor | http://<website-onion>.onion/hls/{show}/master.m3u8 |
Tor | HLS over Tor (same website .onion) |
| FIPS | http://laantungir.fips/hls/{show}/master.m3u8 |
Noise IK+XK | HLS over FIPS |
| FIPS+Tor | Same as FIPS | Tor + Noise IK+XK | HLS over FIPS+Tor |
Streaming considerations:
- HLS playback (HTTP-based) works naturally over Tor and FIPS — it's just static
.m3u8and.tsfiles served by nginx. No special config needed beyond the website server block. - RTMP ingest (OBS publishing on port 1935) stays clearnet-only. RTMP is a TCP protocol on a non-HTTP port; exposing it over Tor or FIPS would require additional transport config and is not needed — the publisher (you) controls the ingest path.
- RTMP direct playback (port 1935/live) is clearnet-only for the same reason. Viewers over Tor/FIPS use HLS instead.
- Stream stats (127.0.0.1:8092) and RTMP auth (127.0.0.1:8091) are internal-only and not exposed on any path.
Decisions (Resolved)
- Tor routing: Option B — separate
.onionper service. Best compatibility with existing clients. - FIPS service routing: Separate
.fipshostnames per service via/etc/fips/hosts. Best compatibility with existing clients. - Blossom: Stays behind nginx (it's a FastCGI extension, must go through nginx).
- Bootstrap peers: fips-test-node (217.77.8.91:2121) + fips.v0l.io (fips.v0l.io:2121).
Execution Order
- Fix Tor onion routing (nginx server_name + torrc)
- Test Tor access from Tor Browser
- Build and install FIPS
- Configure FIPS with persistent identity + Tor transport
- Add FIPS onion service to torrc, restart Tor
- Open firewall ports for FIPS
- Start FIPS, verify fips0 interface and peer connectivity
- Update nginx to listen on IPv6 and handle FIPS traffic
- Test FIPS access from another FIPS node
- Test FIPS-over-Tor access
- Publish server npub and .onion addresses