OpenFlux controlplane auto-deployer - fork of p1neappleXpress/OpenFlux
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
sidylink2 f683f94711 Scope the RST-drop iptables rule to exempt the raw socket's own packets
The old rule dropped every outbound TCP RST unconditionally, including the
raw socket's own legitimate resets (openflux-server now sets SO_MARK 0x2547
on them) - not just the kernel's unwanted auto-RST it was meant to suppress.
Confirmed live via "[RAW-NIC2] Sendto failed: operation not permitted".

Removes the old unscoped rule on redeploy (if present) before adding the
mark-scoped one, so an existing install actually picks up the fix instead of
the stale rule shadowing it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 19:15:11 +03:00
.gitignore Initial import from p1neappleXpress/OpenFlux (fork) 2026-09-10 21:18:47 +03:00
COPYRIGHT Initial import from p1neappleXpress/OpenFlux (fork) 2026-09-10 21:18:47 +03:00
install.sh Scope the RST-drop iptables rule to exempt the raw socket's own packets 2026-09-19 19:15:11 +03:00
LICENSE Initial import from p1neappleXpress/OpenFlux (fork) 2026-09-10 21:18:47 +03:00
NOTICE Initial import from p1neappleXpress/OpenFlux (fork) 2026-09-10 21:18:47 +03:00
README.md Expose the exit node's port-range-size as a configurable env var 2026-09-19 15:20:22 +03:00
README.ru.md Expose the exit node's port-range-size as a configurable env var 2026-09-19 15:20:22 +03:00

OpenFlux deployer

English | Русский

A fork of p1neappleXpress/OpenFlux. This repo holds install.sh: a script that asks a handful of questions and rolls out openflux-server's controlplane — Postgres, the systemd service, Nginx, and an HTTPS certificate (Let's Encrypt) with auto-renewal — on a fresh Debian/Ubuntu or AlmaLinux/RHEL-family VPS.

Usage

Run it directly on the target VPS, as root:

curl -fsSL https://raw.githubusercontent.com/wlruscfd/openflux-deploy/main/install.sh | sudo bash

(Not orchestrated remotely over SSH from your own machine - simpler and more robust to just run it where it's actually provisioning things.)

It will ask for:

  • Which openflux-server repo/branch to deploy (defaults to the wlruscfd one, override for your own fork).
  • TLS mode: domain (standard Let's Encrypt via certbot's Nginx plugin - you'll need a domain already pointed at this server's IP, plus an email for the Let's Encrypt account) or ip (no domain needed; attempts Let's Encrypt's short-lived IP-address certificate, falling back to a self-signed certificate - with a clear warning - if that doesn't succeed, so the panel is still reachable over HTTPS either way).
  • An admin token (or press Enter to generate one) - this is what you'll paste into the admin panel at https://<your-domain-or-ip>/admin/ afterwards.
  • For domain/ip mode: which HTTPS port to use (default 443) - only worth changing if something else on the server already owns it.
  • For domain/ip mode: whether to reserve port 80 for another service on this machine (default no - normal Let's Encrypt issuance/renewal, which needs port 80 reachable). Say "y" only if something else on this server needs port 80 for itself; this skips Let's Encrypt entirely and uses a self-signed certificate on the HTTPS port only, with nginx never listening on 80 at all.
  • Whether to install the full SvelteKit web panel (requires Bun; default yes): it serves the dashboard at /admin/ behind Nginx next to controlplane's /v1/*. Say "n" and you get the original, self-contained panel that's embedded inside the controlplane binary itself (still served at /admin/). Saying "y" here never breaks an install — if Bun can't be installed or the panel fails to build, the script degrades to the embedded panel and says so.
  • Whether to register a first exit node right away.

If that node runs here (RUN_NODE_HERE, raw mode), its outbound-ports-per-key setting defaults to 96 and is set via the NODE_PORT_RANGE_SIZE env var - not an interactive prompt, and remembered across redeploys the same way CONTROLPLANE_PORT is. Lower it to fit more keys on this one node; raise it if a single key's traffic needs more than ~96 simultaneous outbound connections at once (observed in practice: Telegram opens quite a few while loading media in an active chat).

At the end it prints the panel URL, the admin token (save it - it's stored hashed and can't be recovered from the server afterwards), and, if you registered one, the first exit node's token and the exact flags to hand to whoever runs that exit node:

./universal-bypass-tool --exit-node --managed \
    --control-url "https://<your-domain-or-ip>" \
    --node-token "<node token>"

Re-running the script later redeploys a newer branch/tag of openflux-server in place.

Redeploys preserve your data

Re-running install.sh on a server it's already set up (upgrading to a newer openflux-server, or just via the app's "Deploy again") keeps the existing database, admin token, and token pepper - every key, node, and ingest token you've already issued keeps working. Before touching anything, it also dumps the database to /opt/openflux/backups/<timestamp>/openflux.sql (plus a copy of the env file) as a just-in-case safety net. A first-time install has nothing to preserve or back up yet, so none of this applies to it.

Non-interactive / automated use

Every prompt is skipped if its variable is already set in the environment (REPO_URL, GIT_REF, TLS_MODE, DOMAIN, LE_EMAIL, SERVER_IP, HTTPS_PORT, RESERVE_PORT_80, ADMIN_TOKEN, DB_PASSWORD, REGISTER_NODE, NODE_NAME, NODE_MAX_KEYS, WEB_PANEL - the exact names used inside the script), so it can be driven without a human at the keyboard. RESERVE_PORT_80 (default n, domain/ip modes only) - set to y to skip Let's Encrypt entirely and use a self-signed certificate with no port-80 listener at all, so port 80 stays free for another service on the same machine:

REPO_URL=https://github.com/wlruscfd/openflux-server.git GIT_REF=main \
TLS_MODE=domain DOMAIN=panel.example.com LE_EMAIL=you@example.com \
ADMIN_TOKEN="$(openssl rand -hex 32)" DB_PASSWORD="$(openssl rand -hex 24)" \
REGISTER_NODE=y NODE_NAME=node-1 NODE_MAX_KEYS=500 WEB_PANEL=y \
bash install.sh

This is exactly what the openflux-app Android app's Deploy tab does over SSH, so you never see a prompt when deploying from the app. Non-interactive callers that don't pre-set WEB_PANEL get the embedded panel - the script does not prompt where stdin isn't interactive.

What it sets up

  • openflux system user, /opt/openflux/{bin,server,web}, /etc/openflux/controlplane.env (mode 600, holds the DB URL / token pepper / admin token).
  • A local Postgres role + database.
  • openflux-controlplane.service (systemd unit, embedded in install.sh), enabled and started.
  • With the web panel: Bun at /opt/openflux/bun, the built SvelteKit app at /opt/openflux/web, and openflux-web.service (bun server.js on 127.0.0.1:3000, CONTROLPLANE_UPSTREAM holding the controlplane address it forwards /v1/* to).
  • Nginx: /admin/ → the web panel (or controlplane's embedded panel, when Bun was skipped), /v1/ + /healthz → controlplane on 127.0.0.1:8080 (override with the CONTROLPLANE_PORT env var if something else on the server already holds 8080 - a redeploy remembers whatever port was used last time), all over TLS per the mode above. In http mode without a web panel the split doesn't apply and controlplane answers directly.

Honesty about the IP-certificate path

Let's Encrypt's short-lived certificates for bare IP addresses are newer and less battle-tested than the domain path, and need a recent certbot (--ip-address needs 5.3+, webroot support for it needs 5.4+) - the certbot package in Debian/Ubuntu's apt or AlmaLinux's EPEL is normally far older than that and doesn't support IP certificates at all, so this script installs certbot via snap specifically to get a current enough one. That said, this is still a newer Let's Encrypt capability with its own moving parts; if issuance still fails for you, the script notices and falls back to a self-signed certificate rather than leaving the install half-finished. If you can get a domain pointed at the server instead, that path is the well-trodden one.