From 247d2a02eaa8b9829084a51b5626d40c8c9e1247 Mon Sep 17 00:00:00 2001 From: Jaro-c <75870284+Jaro-c@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:36:40 -0500 Subject: [PATCH 1/4] Ignore agent/AI-tool artifacts (zero AI trace) The synced .claude/ agent symlinks and agent-tool scratch (.playwright-mcp/ etc.) were protected only by a machine-global gitignore, so a clone or CI without it could commit them and leak an AI trace. Ignoring them in-repo makes the protection portable; the private ai-context repo is the only place these belong. --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 728efed..b4b9f25 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,12 @@ target/ # Editor *.swp *.swo + +# Agent / AI-tool artifacts — never commit (zero AI trace). +.claude/ +.agents/ +.cursor/ +.aider* +.continue/ +.playwright-mcp/ +**/*-mcp/ From c3180b911e6ad0654795e2b1b733b6d7002dcbb7 Mon Sep 17 00:00:00 2001 From: Jaro-c <75870284+Jaro-c@users.noreply.github.com> Date: Sat, 4 Jul 2026 10:22:36 -0500 Subject: [PATCH 2/4] docs: remove advertising-style content from the README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub flagged the org for content resembling advertising — links, promotional keywords, repeated calls to action. Removes the decorative hero block, third-party badges, external nav-bar CTAs, and any competitor sales-comparison table; keeps the technical description, install/quick-start instructions, and doc links. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com> --- README.md | 64 +++++++++++-------------------------------------------- 1 file changed, 12 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index d2c7526..7607dd3 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,12 @@ -
- Lynx

+# Lynx - # Lynx +Self-hosted VPS and container hosting panel: containers, firewall and a +WireGuard VPN, managed from one dashboard across any number of servers. One +binary per VPS, no Docker daemon required. - **Self-hosted VPS & container manager.**
- Containers · Firewall · VPN — from one dashboard, across any number of servers. +[![CI — Dashboard](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml/badge.svg)](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml) -
- - [![CI — Dashboard](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml/badge.svg)](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml) - ![Rust](https://img.shields.io/badge/Agent-Rust-orange?logo=rust) - ![Next.js](https://img.shields.io/badge/Dashboard-Next.js-black?logo=next.js) - -
- - [Install](#-install) · [Architecture](#-architecture) · [vs Alternatives](#-vs-alternatives) · [Security](#-security) - -
- ---- - -> **The cPanel/Plesk/Coolify alternative built for people who care about security.** -> One binary per VPS. All traffic encrypted over WireGuard. No SaaS. No cloud lock-in. No Docker daemon. - ---- - -## ✨ Features +## Features **📦 Containers** — Podman rootless, per-organization isolation, survive VPS reboots without Lynx running **🔥 Firewall** — Full nftables control from the dashboard, three-layer hierarchy, atomic apply, auto-restore on any tampering @@ -36,7 +17,7 @@ --- -## 🏗 Architecture +## Architecture ``` Dashboard VPS @@ -89,7 +70,7 @@ Agent-2 never exposes public ports for the project. All traffic enters through A --- -## ⚡ Install +## Install ### Dashboard @@ -124,23 +105,7 @@ The installer handles everything: --- -## 🆚 vs Alternatives - -| | **Lynx** | Coolify | Dokploy | cPanel / Plesk | -|---|---|---|---|---| -| Container runtime | Podman (rootless) | Docker | Docker | varies | -| Firewall management | ✅ Full nftables | ❌ | ❌ | Partial | -| VPN between servers | ✅ WireGuard | ❌ | ❌ | ❌ | -| Encryption at rest | ✅ AES-256 (pg_tde) | ❌ | ❌ | ❌ | -| Per-user encryption | ✅ KEK/DEK | ❌ | ❌ | ❌ | -| Signed binary updates | ✅ Ed25519 | ❌ | ❌ | ❌ | -| Runtime dependencies | None | Docker Engine | Docker Engine | Heavy | -| Pricing | Free / self-hosted | Free tier + paid | Free / self-hosted | Paid license | -| SaaS / cloud | Never | Optional | Optional | Optional | - ---- - -## 🔐 Security +## Security
Transport & cryptography @@ -174,7 +139,7 @@ the [security architecture](docs/security-architecture.md) for threat modeling. --- -## 🛠 Development +## Development Contribution model, branch flow and code style live in the [organization contributing guide](https://github.com/Glyndor/.github/blob/main/CONTRIBUTING.md). @@ -238,11 +203,6 @@ Changes in these areas require local VMs — note in your PR which scenarios you --- -## 📄 License - -[Apache-2.0](LICENSE) — © 2026 [Glyndor](https://github.com/Glyndor) +## License -
-
- Made with ❤️ by Jaroc -
+[Apache-2.0](LICENSE) — © 2026 Glyndor. From 914ae8c20ca3c024d247f19cd5a5ee82a054e14e Mon Sep 17 00:00:00 2001 From: Jaro-c <75870284+Jaro-c@users.noreply.github.com> Date: Sat, 4 Jul 2026 14:26:36 -0500 Subject: [PATCH 3/4] ci(release): rename the signing secret to GLYNDOR_RELEASE_ED25519_KEY Matches the org-wide rename already done in podup's release workflow after the Ed25519 key rotation; the old RELEASE_SIGN_KEY name is retired here too. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com> --- .github/workflows/release-dashboard.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release-dashboard.yml b/.github/workflows/release-dashboard.yml index c82b30f..f1b13da 100644 --- a/.github/workflows/release-dashboard.yml +++ b/.github/workflows/release-dashboard.yml @@ -250,13 +250,13 @@ jobs: - name: Sign backend binary working-directory: ${{ github.workspace }} env: - RELEASE_SIGN_KEY: ${{ secrets.RELEASE_SIGN_KEY }} + GLYNDOR_RELEASE_ED25519_KEY: ${{ secrets.GLYNDOR_RELEASE_ED25519_KEY }} run: | pip install --quiet cryptography BINARY="lynx/target/${{ matrix.rust-target }}/release/lynx-dashboard-server" ARTIFACT="lynx-dashboard-backend-linux-${{ matrix.arch }}" cp "$BINARY" "$ARTIFACT" - python3 .github/scripts/sign.py "$RELEASE_SIGN_KEY" "$ARTIFACT" + python3 .github/scripts/sign.py "$GLYNDOR_RELEASE_ED25519_KEY" "$ARTIFACT" # --- Frontend ----------------------------------------------------------- @@ -325,14 +325,14 @@ jobs: - name: Sign frontend artifacts working-directory: ${{ github.workspace }} env: - RELEASE_SIGN_KEY: ${{ secrets.RELEASE_SIGN_KEY }} + GLYNDOR_RELEASE_ED25519_KEY: ${{ secrets.GLYNDOR_RELEASE_ED25519_KEY }} run: | cp "lynx/dashboard/ui/lynx-dashboard-frontend-linux-${{ matrix.arch }}" . cp "lynx/dashboard/ui/lynx-dashboard-frontend-assets-linux-${{ matrix.arch }}.tar.gz" . BIN="lynx-dashboard-frontend-linux-${{ matrix.arch }}" ASSETS="lynx-dashboard-frontend-assets-linux-${{ matrix.arch }}.tar.gz" - python3 .github/scripts/sign.py "$RELEASE_SIGN_KEY" "$BIN" - python3 .github/scripts/sign.py "$RELEASE_SIGN_KEY" "$ASSETS" + python3 .github/scripts/sign.py "$GLYNDOR_RELEASE_ED25519_KEY" "$BIN" + python3 .github/scripts/sign.py "$GLYNDOR_RELEASE_ED25519_KEY" "$ASSETS" # --- Upload artifacts --------------------------------------------------- From 8b53f6723e36dad00f03a5c1f0124208b298fece Mon Sep 17 00:00:00 2001 From: Jaro-c <75870284+Jaro-c@users.noreply.github.com> Date: Sat, 4 Jul 2026 15:48:03 -0500 Subject: [PATCH 4/4] security(release): rotate the Ed25519 release signing key Unifies the signing key with podup, helmly-agent and unitpm for the first time -- despite the documented shared-key design, this repo had drifted onto a different embedded key than podup's. Every binary from before this rotation cannot update in-band; reinstall required. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com> --- lynx/dashboard/server/src/update.rs | 2 +- lynx/dashboard/setup-dashboard.sh | 2 +- lynx/dashboard/update-dashboard.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lynx/dashboard/server/src/update.rs b/lynx/dashboard/server/src/update.rs index 8a87771..3844e7a 100644 --- a/lynx/dashboard/server/src/update.rs +++ b/lynx/dashboard/server/src/update.rs @@ -380,7 +380,7 @@ fn verify_signature(binary: &[u8], sig_bytes: &[u8]) -> Result<()> { .context("Ed25519 signature invalid") } -const RELEASE_VERIFY_KEY_B64: &str = "APh+kh61dJeT0HzG+KQXELzDjK4ccvqY9K+FptOZ3+Y="; +const RELEASE_VERIFY_KEY_B64: &str = "HFv7vg5FCY7YyKUDbJhaQSfB9SboJGSblJtFbLmLHzM"; fn load_release_verify_key() -> Result<[u8; 32]> { use base64ct::{Base64, Encoding}; diff --git a/lynx/dashboard/setup-dashboard.sh b/lynx/dashboard/setup-dashboard.sh index b231f2b..d277d1c 100644 --- a/lynx/dashboard/setup-dashboard.sh +++ b/lynx/dashboard/setup-dashboard.sh @@ -599,7 +599,7 @@ done log_section "Downloading core binaries" GITHUB_REPO="Glyndor/panel" -RELEASE_VERIFY_KEY_B64="APh+kh61dJeT0HzG+KQXELzDjK4ccvqY9K+FptOZ3+Y=" +RELEASE_VERIFY_KEY_B64="HFv7vg5FCY7YyKUDbJhaQSfB9SboJGSblJtFbLmLHzM" _ARCH=$(uname -m) case "$_ARCH" in diff --git a/lynx/dashboard/update-dashboard.sh b/lynx/dashboard/update-dashboard.sh index a732143..c1a7578 100644 --- a/lynx/dashboard/update-dashboard.sh +++ b/lynx/dashboard/update-dashboard.sh @@ -142,7 +142,7 @@ _verify_release_sig() { import sys, base64 from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey -pub_b64 = "APh+kh61dJeT0HzG+KQXELzDjK4ccvqY9K+FptOZ3+Y=" +pub_b64 = "HFv7vg5FCY7YyKUDbJhaQSfB9SboJGSblJtFbLmLHzM" pub_key = Ed25519PublicKey.from_public_bytes(base64.b64decode(pub_b64 + "==")) with open(sys.argv[1], "rb") as f: