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 --------------------------------------------------- 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/ 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. 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: