Add ONION-URLS.md, export script, and tighten README

- ONION-URLS.md: static registry of all 43 hidden services (port, role, app path)
- scripts/export-onion-urls.sh: writes live .onion addresses to onion-urls.txt at runtime
- npm run onions:export shortcut added to package.json
- onion-urls.txt added to .gitignore (runtime artifact, not source)
- README: cohesive rewrite — architecture diagram, operator command table, source-of-truth
  map, BTCPay notes, full site map, common fixes
- BTCPay status route: awaited params destructuring (Next 15 async params)

Made-with: Cursor
This commit is contained in:
drjones
2026-04-16 18:03:30 -07:00
parent 4354416f1c
commit cb072437d0
6 changed files with 348 additions and 201 deletions

361
README.md
View File

@@ -2,199 +2,155 @@
> **The clearnet is a showroom. The onion is the door. One engine behind every door.**
We did not build forty-three repos. We built **one** Next.js stack and **refused** to fracture it—then we **projected** it through Tor until every vertical had its own v3 address, its own myth, its own entry point. Nginx sits in the middle like a bouncer; Tor does the rest. Same codebase. Same deploy. **Different `.onion` front doors** with host-aware rewrites (`proxy.ts` + `X-Cyberlux-Node`).
This is not a route demo. It is **infrastructure with intent**: stable `HiddenServiceDir` names, backup and restore for onion keys, Tor + nginx generated from **one JSON source of truth**. It is built to **boot, survive operator mistakes, and stay legible when everything else is on fire**.
One Next.js stack projected through 43 independent Tor v3 hidden services. Nginx sits in the middle; Tor does the publishing. Same codebase, same deploy **different `.onion` front doors** with host-aware rewrites (`proxy.ts` + `X-Cyberlux-Node`). No fork army. No split deployments.
---
## The thesis
## Architecture
- **One truth, many masks** — one build, dozens of onions; no fork army.
- **Identity persists** — keys and dirs are first-class; restarts dont erase your address book.
- **Loopback only** — Next and nginx dont audition on the public internet; Tor publishes what you mean to publish.
- **Verify or rot** — `npm run verify` is the line between shipping and LARP.
```
Tor Browser
│ http://<56-char>.onion
[ Tor Network ]
nginx 127.0.0.1:80808122 (one vhost per .onion, host header → X-Cyberlux-Node)
Next.js 127.0.0.1:3000 (single instance, proxy.ts routes by header)
```
**43 onion services → one app → zero public ports.**
---
## Operator controls
| Command | What |
|--------|------|
| `./start.sh` | Full pipeline: generate → build → Tor/nginx → print **every `.onion` URL**`next start` on `127.0.0.1:3000` |
| `npm run onions:list` | Print all `http://….onion` URLs from `/var/lib/tor/*/hostname` (use `sudo` if needed) |
| `npm run health:stack` | **Terminal A:** keep `npm run start:onion` running · **Terminal B:** curl Tor/nginx/Next loopbacks |
| `npm run onions:status` | URLs + HTTP probe each nginx vhost |
| `sudo bash scripts/install-systemd.sh` | Install `cyberlux.service` for boot-time Next |
| **`DEPLOY.md`** | Firewall posture, compliance reminder, full systemd notes |
**Tor on a phone:** **Onion Browser** (iOS) or **Tor Browser for Android** — Safari and Chrome will **never** resolve `.onion`. Paste the full `http://` + 56-char host + `.onion`. Some carriers fight Tor; WiFi often wins.
---
## What ships in the box
- `43` Tor v3 services
- stable loopback range `127.0.0.1:80808122`
- Next bound only to `127.0.0.1:3000`
- one `.onion` per major surface
- persistent hidden-service identity keyed by `HiddenServiceDir`
- self-healing backup / restore of onion key directories
## What it does (the map)
CyberLux boots **one** Next.js app and **projects** it through multiple onion entry points.
- `hub` — main storefront
- `forum` — Void Aggregate
- `exchange` — classifieds stack
- `market` — full catalog vertical
- `search` — Void Crawler
- `wiki` — hidden-wiki layer
- `w` — syndicate shell network
- dozens more dedicated onions map to top-level app routes
The routing layer uses host-aware rewrites so a dedicated onion **feels** like its own property without splitting the app into forty-three deployments.
## One-command launch
Install system deps on Debian/Ubuntu:
## Quick Start
```bash
sudo apt install tor nginx
```
Then:
```bash
chmod +x start.sh
./start.sh
```
What `./start.sh` does:
Open the hub in **Tor Browser** (addresses print at the end of start.sh).
Local-only (skip Tor/nginx): `CYBERLUX_SKIP_TOR=1 ./start.sh`
1. regenerates Tor / nginx / app route maps from `scripts/onion-nodes.json`
2. runs `git pull --ff-only` if the repo has `.git` (failure is non-fatal)
3. runs `npm install`
4. repairs `.next` ownership if a root-owned build left it unwritable
5. runs a production build
6. restores backed-up onion keys if any hidden-service directories are missing
7. installs Tor + nginx config only when it actually changed
8. waits for all onion hostname files, not just the hub
9. refreshes the onion key backup set
10. prints every live `.onion` URL
11. starts Next on `127.0.0.1:3000`
---
Open in Tor Browser:
## Operator Commands
```text
http://<56-char-v3-address>.onion
| Command | What it does |
|---------|-------------|
| `./start.sh` | Full pipeline: generate → build → Tor/nginx → print URLs → start Next |
| `npm run onions:list` | Print all live `.onion` URLs from `/var/lib/tor/*/hostname` |
| `sudo npm run onions:export` | Write live URLs to `onion-urls.txt` in repo root |
| `npm run onions:status` | URLs + HTTP probe each nginx vhost |
| `npm run health:stack` | Curl Tor/nginx/Next loopbacks and report status |
| `npm run verify` | Full pre-ship check: config gen, TS, shell syntax, build |
| `sudo bash scripts/install-tor-onion.sh` | Install/refresh Tor + nginx config |
| `sudo bash scripts/backup-onion-keys.sh` | Back up all hidden-service key dirs |
| `sudo bash scripts/restore-onion-keys.sh` | Restore missing key dirs from backup |
| `sudo bash scripts/install-systemd.sh` | Install `cyberlux.service` for boot-time start |
| `sudo bash scripts/classroom-ufw.sh` | Lock firewall to loopback-only (recommended) |
---
## Onion URL Reference
See [`ONION-URLS.md`](ONION-URLS.md) — full table of all 43 services with ports and app paths.
To export live `.onion` addresses after Tor is running:
```bash
sudo bash scripts/export-onion-urls.sh
# writes onion-urls.txt (gitignored — reflects runtime state)
```
## Persistent onion addresses
---
Yes — the onion addresses are **meant** to persist.
## What Ships in the Box
Each service uses a fixed Tor directory:
- **43** Tor v3 hidden services
- Loopback range `127.0.0.1:80808122` (nginx vhosts, never public)
- Next.js bound only to `127.0.0.1:3000`
- One `.onion` per major surface — hub, forum, market, exchange, wiki, and 38 more
- Persistent hidden-service identity keyed by `HiddenServiceDir` name
- Self-healing backup / restore for onion keys
- BTCPay Server integration (configurable) for on-chain + Lightning deposits
- Systemd unit generator for unattended boot
```tor
HiddenServiceDir /var/lib/tor/<service-dir>
HiddenServicePort 80 127.0.0.1:<loopback-port>
---
## What `./start.sh` Does (in order)
1. Regenerates Tor / nginx / app route maps from `scripts/onion-nodes.json`
2. Runs `git pull --ff-only` if repo has `.git` (non-fatal on failure)
3. Runs `npm install`
4. Repairs `.next` ownership if a root-owned build left it unwritable
5. Runs a production build
6. Restores backed-up onion keys if any hidden-service directories are missing
7. Installs Tor + nginx config (only when it changed)
8. Waits for **all** onion hostname files, not just the hub
9. Refreshes the onion key backup set
10. Prints every live `.onion` URL
11. Starts Next on `127.0.0.1:3000`
---
## Source of Truth
Everything — Tor config, nginx vhosts, app route maps — is generated from one file:
```
scripts/onion-nodes.json
```
The `.onion` stays stable as long as:
Generated artifacts (do not edit manually):
| File | Description |
|------|-------------|
| `tor/cyberlux-nodes.conf` | Tor `HiddenServiceDir` / `HiddenServicePort` blocks |
| `nginx/cyberlux-onion-servers.inc` | nginx server blocks (one per onion) |
| `lib/onionRoutes.generated.ts` | TypeScript route map used by `proxy.ts` |
| `scripts/generated/tor-dirs.txt` | Newline-separated list of service dir names |
| `scripts/generated/onion-labels.tsv` | Human-readable labels per service |
| `scripts/generated/onion-port-range.txt` | Port min / max for scripts |
---
## Persistent Onion Addresses
Addresses are stable as long as:
- `torDir` names in `scripts/onion-nodes.json` do not change
- `/var/lib/tor/<service-dir>` is preserved
- `/var/lib/tor/<service-dir>/` is preserved
- or the backup set can restore those directories
Normal app restarts, rebuilds, and standard Tor restarts do **not** rotate addresses by design.
Normal app restarts, rebuilds, and standard Tor restarts **do not rotate addresses**.
## Self-healing onion identity
Backup location: `/var/backups/cyberlux-onion-keys/current`
- `scripts/backup-onion-keys.sh`
- `scripts/restore-onion-keys.sh`
---
Backup location:
## BTCPay Server
```text
/var/backups/cyberlux-onion-keys/current
```
The checkout flow supports BTCPay Server for on-chain + Lightning payments. Configure with environment variables (see `.env.example` or `DEPLOY.md`). The stack runs without BTCPay — the API returns `503` if not configured.
After boot, ready onion service directories are backed up. If a service dir is missing from `/var/lib/tor` next boot, it is restored from backup. That is the gap between **screenshotware** and **survives a tired operator**.
---
## Tor / nginx topology
Source of truth: `scripts/onion-nodes.json`
Generated artifacts:
- `tor/cyberlux-nodes.conf`
- `nginx/cyberlux-onion-servers.inc`
- `lib/onionRoutes.generated.ts`
- `scripts/generated/tor-dirs.txt`
- `scripts/generated/onion-labels.tsv`
- `scripts/generated/onion-port-range.txt`
Install path:
- `/etc/tor/cyberlux-nodes.conf`
- `/etc/nginx/cyberlux-server-common.inc`
- `/etc/nginx/cyberlux-onion-servers.inc`
- `/etc/nginx/sites-available/cyberlux-onion`
Runtime:
- Next.js: `127.0.0.1:3000`
- nginx onion vhosts: `127.0.0.1:80808122`
- Tor exposes the public `.onion` endpoints
## Manual ops
Install or refresh Tor/nginx config:
```bash
sudo bash scripts/install-tor-onion.sh
```
Back up onion keys:
```bash
sudo bash scripts/backup-onion-keys.sh
```
Restore missing onion keys:
```bash
sudo bash scripts/restore-onion-keys.sh
```
Local-only, skip Tor/nginx:
```bash
CYBERLUX_SKIP_TOR=1 ./start.sh
```
Start app without the helper:
```bash
npm run build
npm run start:onion
```
## Boot at startup (systemd)
Generate the unit with your Unix user and repo path:
## Boot at Startup (systemd)
```bash
sudo CYBERLUX_USER=$USER bash scripts/install-systemd.sh
sudo systemctl enable --now tor.service nginx.service cyberlux.service
# use `tor@default.service` instead of `tor.service` if your distro names it that way
```
The installer writes `/etc/systemd/system/cyberlux.service` and `/etc/default/cyberlux`. Legacy template notes live in `scripts/cyberlux.service` (prefer the generator).
Use `tor@default.service` instead of `tor.service` if your distro names it that way.
Tor + nginx must already be configured (`./start.sh` or `sudo bash scripts/install-tor-onion.sh` at least once).
Tor + nginx must already be configured (`./start.sh` or `sudo bash scripts/install-tor-onion.sh` first).
---
## Verification
@@ -202,67 +158,76 @@ Tor + nginx must already be configured (`./start.sh` or `sudo bash scripts/insta
npm run verify
```
Checks: onion config generation, TypeScript, shell syntax for boot/install/backup/restore scripts, full Next production build.
Checks: config generation, TypeScript compilation, shell syntax for all boot/install/backup/restore scripts, full Next.js production build.
## Common failure: `.next` permission hell
---
If you built with `sudo`, `.next` may be root-owned and Next fails with `EACCES`.
## Common Fixes
**`.next` permission error (built with sudo):**
```bash
sudo bash scripts/fix-next-perms.sh
./start.sh
```
## Security (read twice)
**Onion hostnames not showing up:**
CyberLux is hardened for a **demo stack**, not sold as magic invisibility.
```bash
sudo systemctl status tor
sudo ls -la /var/lib/tor/
# Wait ~30s after Tor starts for v3 descriptor publication
```
- Next and nginx bind to loopback only
- Tor exposes the onion endpoints
- do **not** publish `3000` or `80808122` to the public internet
- optional host firewall: `sudo bash scripts/classroom-ufw.sh`
- bad application logic stays bad behind Tor
- operational mistakes beat branding every time
**Port 3000 already in use:**
Tor obscures **reachability** better than raw-IP hosting. It does not forgive bad code, bad habits, or bad judgment.
## Site map
Core verticals:
- `/` hub storefront
- `/market` full catalog
- `/forum` Void Aggregate
- `/exchange` classifieds
- `/barter` Ash Pit
- `/search` Void Crawler
- `/hidden-wiki` wiki layer
- `/darknet-atlas` taxonomy / atlas
- `/syndicate` shell network
- `/dashboard` personal relay
- `/account/hidden-services` mirror map
Additional dedicated onions exist for many top-level routes beyond these.
## Stack
- Next.js `16`
- React `19`
- Tailwind CSS `4`
- nginx
- Tor hidden services
- generated route / host mapping
```bash
ss -ltnp | grep 3000
# Stop the conflicting process, then ./start.sh
```
---
## Final word
## Security
If you are running this, you are **past cosplay**. The stack exists to:
- Next.js and nginx bind to **loopback only** — they are never public
- Tor publishes the `.onion` endpoints
- Do **not** expose ports 3000 or 80808122 to the internet
- Harden with: `sudo bash scripts/classroom-ufw.sh`
- Tor obscures reachability — it does not forgive bad code or bad ops
- keep **onion identities** across rebuilds when you respect `torDir` names and backups
- expose **only** what Tor publishes — not your loopback to the raw internet
- fail **loud** in verification instead of silently rotting
Read `DEPLOY.md` before pointing real users at this stack.
Read **`DEPLOY.md`** before you point real people at it. **You** own jurisdiction, opsec, and what you ship. The network does not owe you anonymity; **you** owe the network discipline.
---
**This README is the products declaration of intent. The code is the rest.**
## Site Map
| Vertical | Path | Onion |
|---------|------|-------|
| Hub storefront | `/` | `cyberlux` |
| Forum (Void Aggregate) | `/forum` | `cyberlux_forum` |
| Exchange (classifieds) | `/exchange` | `cyberlux_exchange` |
| Market (full catalog) | `/market` | `cyberlux_market` |
| Barter (Ash Pit) | `/barter` | `cyberlux_barter` |
| Search (Void Crawler) | `/search` | `cyberlux_search` |
| Hidden Wiki | `/hidden-wiki` | `cyberlux_wiki` |
| Syndicate (shell net) | `/syndicate` | `cyberlux_syndicate` |
| Dashboard | `/dashboard` | `cyberlux_dashboard` |
| Account / mirror map | `/account` | `cyberlux_account` |
| + 33 more | see `ONION-URLS.md` | |
---
## Stack
- **Next.js 16** · React 19 · Tailwind CSS 4
- **nginx** reverse proxy (loopback vhosts)
- **Tor** v3 hidden services
- **BTCPay Server** (optional, on-chain + Lightning)
- Generated route / host mapping from single JSON source
---
> If you are running this, you are past cosplay.
> The network does not owe you anonymity — **you** owe the network discipline.
> Read `DEPLOY.md`. Own your jurisdiction.