Upstream panels (Remnawave and friends) pin a subscription to one device
through the x-hwid header. Prizma holds that HWID per source, presents it on
every upstream fetch, and hands out its own link that any number of devices
may use. Everything else — the client's User-Agent, the response body, the
profile-title / subscription-userinfo / announce headers — is proxied through
untouched.
Two link kinds behind /sub/{token}:
source byte-for-byte proxy of one upstream, format chosen by the client
group several sources merged into one link: parallel fetch, parse, regex
filtering by node name and by node content, protocol allow-list,
dedupe, rename template, rendered in the negotiated format
Formats parse and render both ways: URI lists, base64, Clash/Mihomo YAML,
sing-box JSON, and Xray JSON including the Happ-style array of whole configs.
A node keeps the raw payload it was born from, so same-format rendering is
byte-identical and no vendor-specific field is ever dropped.
Access control is HWID-based and self-switching: an empty whitelist means
everyone passes except banned devices; whitelisting a single device locks the
links to the whitelist. Every device that fetches a link is recorded with its
UA, IP, hit count and timestamps, and can be banned, whitelisted or labelled
from the panel.
Ships as one static binary with the React admin panel embedded (CGO-free, so
linux/amd64+arm64, windows and darwin cross-compile from anywhere), as a
docker image, and with Gitea CI that gates releases on the test suite.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
73 lines
3.0 KiB
Bash
73 lines
3.0 KiB
Bash
# Prizma configuration — copy to .env and edit.
|
|
#
|
|
# cp .env.example .env
|
|
#
|
|
# Every key Prizma reads is listed here with its built-in default. A key you
|
|
# leave commented out keeps that default; there is no separate config file.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Network
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Listen address, "host:port". Leave the host empty to bind every interface.
|
|
# Put Prizma behind a TLS reverse proxy in production — it speaks plain HTTP.
|
|
PRIZMA_ADDR=:8080
|
|
|
|
# Public base URL of THIS Prizma, without a trailing slash. Only used to print
|
|
# ready-to-copy subscription links in the admin panel, so a wrong value costs
|
|
# you nothing but wrong-looking links.
|
|
PUBLIC_URL=https://sub.example.com
|
|
|
|
# Honour X-Forwarded-For / X-Real-IP when determining the client IP.
|
|
# Turn this on ONLY behind a reverse proxy you control: with a direct-to-Internet
|
|
# listener any client can forge the header, and the IP ends up in the client list
|
|
# and in the synthetic-HWID fingerprint.
|
|
TRUST_PROXY=false
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Storage
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# SQLite database path. The parent directory must be writable by the process.
|
|
# In the Docker image this is /data/prizma.db on the persistent volume.
|
|
PRIZMA_DB=data/prizma.db
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Admin authentication
|
|
# ---------------------------------------------------------------------------
|
|
|
|
ADMIN_USER=admin
|
|
|
|
# CHANGE THIS. The default is "admin" and Prizma warns loudly at startup while
|
|
# it stays that way — the panel holds every upstream subscription URL you own.
|
|
ADMIN_PASSWORD=change-me-please
|
|
|
|
# HS256 signing key for admin session tokens. Leave empty and Prizma generates
|
|
# one on first start and persists it in the DB `settings` table, so sessions
|
|
# survive restarts. Set it explicitly when you run several replicas off one DB,
|
|
# or when you want to invalidate every issued token by rotating it.
|
|
# openssl rand -hex 32
|
|
JWT_SECRET=
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Upstream fetching
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Seconds an upstream response is reused before Prizma refetches it.
|
|
# This is what protects the upstream panel from your device fan-out: 40 clients
|
|
# refreshing hourly still cost the upstream one request per CACHE_TTL.
|
|
# A per-source override exists in the panel; 0 there means "use this value".
|
|
CACHE_TTL=300
|
|
|
|
# Seconds before an upstream request is abandoned. A source that times out is
|
|
# marked failed; inside a group it is skipped, and the group still renders from
|
|
# the members that answered.
|
|
UPSTREAM_TIMEOUT=20
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Logging
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# debug | info | warn | error
|
|
LOG_LEVEL=info
|