Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/release-dashboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----------------------------------------------------------

Expand Down Expand Up @@ -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 ---------------------------------------------------

Expand Down
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
64 changes: 12 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
<div align="center">
<img src="lynx/dashboard/ui/public/logo.webp" alt="Lynx" width="140" /><br /><br />
# 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.**<br />
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)

<br />

[![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)

<br />

[Install](#-install) · [Architecture](#-architecture) · [vs Alternatives](#-vs-alternatives) · [Security](#-security)

</div>

---

> **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
Expand All @@ -36,7 +17,7 @@

---

## 🏗 Architecture
## Architecture

```
Dashboard VPS
Expand Down Expand Up @@ -89,7 +70,7 @@ Agent-2 never exposes public ports for the project. All traffic enters through A

---

## Install
## Install

### Dashboard

Expand Down Expand Up @@ -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

<details>
<summary><strong>Transport &amp; cryptography</strong></summary>
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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

<div align="center">
<br />
<sub>Made with ❤️ by <a href="https://github.com/Jaro-c">Jaroc</a></sub>
</div>
[Apache-2.0](LICENSE) — © 2026 Glyndor.
2 changes: 1 addition & 1 deletion lynx/dashboard/server/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
2 changes: 1 addition & 1 deletion lynx/dashboard/setup-dashboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lynx/dashboard/update-dashboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down