No description
  • TypeScript 95%
  • CSS 2.2%
  • Dockerfile 2%
  • JavaScript 0.5%
  • HTML 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Vladimir Zhukov 3ab72ed5e0
Some checks failed
CI / ci (push) Has been cancelled
Container images / publish (push) Has been cancelled
feat: enhance security and permissions for Docker deployment
- Updated `compose.linux.yml` to set user and group IDs for the wg-agent service, ensuring effective NET_ADMIN capabilities while maintaining proper Unix DAC.
- Adjusted directory and socket permissions to 0770 and 0660 respectively, allowing shared GID access.
- Modified Dockerfile to reflect new permissions and ownership settings for runtime directories.
- Updated documentation to clarify access models and required environment variables.
- Enhanced tests to validate new permission settings and ensure security posture.
2026-09-16 10:34:50 +03:00
.forgejo/workflows feat: add privilege-separated Docker deployment 2026-09-16 09:05:29 +03:00
apps feat: enhance security and permissions for Docker deployment 2026-09-16 10:34:50 +03:00
config feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
docs feat: enhance security and permissions for Docker deployment 2026-09-16 10:34:50 +03:00
infrastructure feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
packages feat: enhance security and permissions for Docker deployment 2026-09-16 10:34:50 +03:00
.dockerignore feat: add privilege-separated Docker deployment 2026-09-16 09:05:29 +03:00
.env.example feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
.gitignore feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
.prettierignore feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
.prettierrc.json feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
AGENTS.md feat: add privilege-separated Docker deployment 2026-09-16 09:05:29 +03:00
compose.linux.yml feat: enhance security and permissions for Docker deployment 2026-09-16 10:34:50 +03:00
compose.yaml feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
Dockerfile feat: enhance security and permissions for Docker deployment 2026-09-16 10:34:50 +03:00
eslint.config.js feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
package.json feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
pnpm-lock.yaml feat: add privilege-separated Docker deployment 2026-09-16 09:05:29 +03:00
pnpm-workspace.yaml feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
README.md feat: prepare secure Docker observe-only deployment 2026-09-16 09:27:14 +03:00
tsconfig.base.json feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00
vitest.config.ts feat: initial observe-only monitoring 2026-09-16 08:29:24 +03:00

Shoshskie Sasy

Self-hosted open-source control plane for monitoring (and later recovering) WireGuard / AmneziaWG tunnels between arbitrary nodes.

The app is topology-agnostic: you define nodes and links in configuration. It does not assume home routers, a specific VPS, geography, or a fixed tunnel direction.

v0.1 is observe-only. It reads WireGuard state, stores history, and shows a dashboard. It does not change ports, firewalls, routers, or interfaces.

How WireGuard health is determined

A successful UDP probe is NOT considered proof that a WireGuard tunnel is healthy.

The primary signal is a fresh authenticated WireGuard handshake on the configured peer:

Status Meaning
healthy Handshake age ≤ staleAfterSeconds
stale Handshake exists but is older than the threshold
never_connected Handshake epoch is 0 / absent
error Interface unreadable, expected peer missing, or other read failure

Health is always computed from the link’s endpoints.observed interface and the peer matching peerPublicKey (exact match, never by dump index).

Architecture

apps/server   Fastify API + polling + (production) static UI
apps/web      React + Vite dashboard (dev server / built assets)
packages/*    config, core, wireguard, storage
  • Backend = control plane; Linux/WireGuard kernel = data plane.
  • No WireGuard protocol implementation in JavaScript.
  • Production prefers one Node process serving API + built UI.

Requirements

  • Node.js ≥ 22
  • pnpm ≥ 9 (pnpm 11+: allowBuilds in pnpm-workspace.yaml)
  • Linux + wireguard-tools (wg) for provider: linux

Configuration precedence

  1. SHOSHSKIE_SASY_CONFIG (absolute path recommended) — preferred in production
    Legacy alias: SHOSHSKIE_CONFIG
  2. config/config.local.yaml if present (gitignored)
  3. config/config.example.yaml — development only

With NODE_ENV=production, missing a real config is a startup error. The app will not silently use the example file.

Create a private config:

cp config/config.local.template.yaml config/config.local.yaml
# edit placeholders — never commit this file
links:
  tunnel-a:
    name: Example Tunnel
    endpoints:
      observed:
        node: observe-host
        interface: wg0
        peerPublicKey: REPLACE_WITH_PEER_PUBLIC_KEY
      peer:
        node: edge-a
    health:
      staleAfterSeconds: 180

peerPublicKey is a WireGuard public key (not a secret) and is required on the observed endpoint.

SQLite path:

app:
  databasePath: /var/lib/shoshskie-sasy/shoshskie-sasy.db

Self-hosted Git / Forgejo

Shoshskie Sasy does not depend on a specific Git hosting provider. A private Forgejo (or any other Git host) works without application changes.

  • Clone, build, and deploy from any Git remote.
  • Optional CI: .forgejo/workflows/ci.yml runs install/build/typecheck/test/lint via Forgejo Actions (no deploy, no secrets).
  • Adjust the workflow runs-on label if your Forgejo runners use a different name than docker.

Local development

pnpm install
pnpm build
pnpm test
pnpm typecheck
pnpm lint
pnpm diagnose
pnpm dev
  • API/UI (dev): Vite on :5173 proxies /api → Fastify :8787
  • Fake provider is the default in config.example.yaml

Observe-only deployment

Recommended: Docker Compose with privilege-separated wg-agent — see docs/docker.md.

Alternative: native/systemd (infrastructure/systemd/shoshskie-sasy.service.example).

Docker + agent Native / systemd
Pros Reproducible images, app isolation, clean upgrades Direct wg access, fewer moving parts
Cons Host-network agent needs CAP_NET_ADMIN Host Node/runtime deps

Native flow

  1. Clone the Git repository on the Linux VPS
  2. pnpm install && pnpm build
  3. Create private config
  4. NODE_ENV=production + SHOSHSKIE_SASY_CONFIG=...
  5. pnpm diagnose
  6. pnpm start / systemd

Docker flow (summary)

# Safe fake demo
docker compose up --build -d

# Linux production (private config required)
cp config/docker.local.template.yaml config/docker.local.yaml
cp .env.example .env   # SHOSHSKIE_CONFIG_FILE=./config/docker.local.yaml
# edit docker.local.yaml — do not commit
docker compose -f compose.yaml -f compose.linux.yml build
docker compose -f compose.yaml -f compose.linux.yml run --rm --no-deps --entrypoint node app dist/data-preflight-cli.js
docker compose -f compose.yaml -f compose.linux.yml run --rm --no-deps --entrypoint node wg-agent dist/index.js --preflight
docker compose -f compose.yaml -f compose.linux.yml up -d

Host publish: 127.0.0.1:8787 only. Details: docs/docker.md.

Secrets: wg show … dump private keys / PSKs are stripped inside wg-agent and must never appear in the agent protocol, API, SQLite, or logs.

Linux WireGuard agent currently requires rootful Docker (host network + CAP_NET_ADMIN).

Forgejo Container Registry (optional)

Workflow: .forgejo/workflows/container.yml (tag v* / manual).

Configure:

Name Type Purpose
DOCKER_REGISTRY variable Registry hostname (optional; defaults to Forgejo host)
REGISTRY_USER secret Registry username
REGISTRY_TOKEN secret Token with package write scope

Images: shoshskie-sasy-app, shoshskie-sasy-agent. Registry may be disabled on some Forgejo instances — local docker compose build still works.

Permissions

wg show <interface> dump is read-only, but access control is distro-specific.

Typical options (choose one; do not run the whole app as root unless you have proven it is required):

  • Run the service user in a group that can read WireGuard state (if your distro provides one)
  • Use file capabilities / policy carefully if your environment requires it
  • Document the chosen approach in your private runbook

Shoshskie Sasy never calls wg set, wg-quick, iptables/nft, or interface mutations in v0.1.

Security

  • Observe-only; no mutation commands
  • execFile with argument arrays (no shell string building)
  • Interface names and link IDs come from validated config only
  • Bind loopback by default
  • Do not log private keys / PSKs / credentials
  • Domain events ≠ technical logs

Diagnostics

pnpm diagnose

Checks config load, database path, wg binary (for linux provider), and each link’s interface/peer/handshake — without changing anything.

API (read-only)

Method Path Purpose
GET /api/healthz Process / DB liveness (Docker HEALTHCHECK)
GET /api/health Aggregate WireGuard link health
GET /api/system Version, build metadata, paths, counts, uptime
GET /api/nodes Nodes
GET /api/links Links + last health
GET /api/links/:id Link details
GET /api/links/:id/history Samples + events
GET /api/events Event feed

Roadmap

Version Focus
v0.1 Monitoring / observe-only
v0.2 Manual recovery + dry-run
v0.3 Automatic port rotation
v0.4 Keenetic adapter
v0.5 Notifications

License

To be chosen before the first public release.