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
+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.
+[](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml)
-
-
- [](https://github.com/Glyndor/panel/actions/workflows/dashboard-server.yml)
- 
- 
-
-
-
- [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: