Server & IT Setup
This guide walks through deploying the receiver, provisioning user tokens, and verifying the installation.
Step 1: Download the receiver binary
Download the latest release from GitHub Releases:
# Linux x86_64
wget https://github.com/Psy-Fer/ccflux/releases/latest/download/ccflux-receiver-linux-x86_64
chmod +x ccflux-receiver-linux-x86_64
Or build from source:
cd receiver
cargo build --release
# binary is at target/release/ccflux-receiver
Step 2: Configure the receiver
All configuration is via environment variables. Minimum required:
DATABASE_PATH=/var/lib/ccflux/ccflux.db \
LISTEN_ADDR=127.0.0.1:8080 \
ADMIN_TOKEN="$(openssl rand -hex 32)" \
./ccflux-receiver
The receiver creates the SQLite database and schema on first start. On startup it prints all resolved configuration values:
ccflux-receiver config:
DATABASE_PATH = /var/lib/ccflux/ccflux.db
LISTEN_ADDR = 127.0.0.1:8080
ACCESS_TOKEN_EXPIRY_SECS = 28800
REFRESH_TOKEN_ROLLING_DAYS = 90
RATE_LIMIT_PER_MINUTE = 30
BODY_LIMIT_KB = 64
REQUIRE_SIGNATURES = false
ADMIN_TOKEN = set
COOKIE_SECURE = false
ccflux-receiver listening on 127.0.0.1:8080
See Configuration Reference for all available variables.
Step 3: Put it behind a reverse proxy
The receiver speaks plain HTTP. Always put it behind a TLS-terminating reverse proxy in production.
nginx example
server {
listen 443 ssl;
server_name ccflux.example.org;
ssl_certificate /etc/letsencrypt/live/ccflux.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ccflux.example.org/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Caddy example
ccflux.example.org {
reverse_proxy 127.0.0.1:8080
}
Caddy handles certificate provisioning automatically.
Step 4: Run as a systemd service
# /etc/systemd/system/ccflux-receiver.service
[Unit]
Description=ccflux receiver
After=network.target
[Service]
Type=simple
User=ccflux
WorkingDirectory=/var/lib/ccflux
Environment=DATABASE_PATH=/var/lib/ccflux/ccflux.db
Environment=LISTEN_ADDR=127.0.0.1:8080
Environment=ADMIN_TOKEN=your-strong-admin-token-here
Environment=COOKIE_SECURE=1
Environment=REQUIRE_SIGNATURES=false
ExecStart=/usr/local/bin/ccflux-receiver
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now ccflux-receiver
Step 5: Verify the deployment
curl https://ccflux.example.org/health
# {"status":"ok","db":"ok"}
If the database is unreachable the response will be 503 with {"status":"degraded","db":"error"}.
Step 6: Provision user refresh tokens
Each user needs a personal long-lived refresh token. Insert one row per user:
sqlite3 /var/lib/ccflux/ccflux.db
INSERT INTO refresh_tokens (token, email, division, expires_at)
VALUES (
'rtok_abc123...', -- generate with: openssl rand -hex 32
'jsmith@example.org',
'engineering', -- optional group label
datetime('now', '+365 days')
);
Generate tokens securely:
openssl rand -hex 32
Important: use one token per person. Sharing tokens prevents per-user attribution.
Token lifecycle
- Tokens are long-lived (default: 1 year at issuance)
- Each successful use automatically extends expiry by
REFRESH_TOKEN_ROLLING_DAYS(default 90) - Active users never need a new token issued — they roll automatically
- Inactive users (no activity for > 90 days) will need a new token from IT
Step 7: Send tokens to users
Give each user:
- Their personal refresh token
- Your receiver URL (e.g.
https://ccflux.example.org/report) - A link to the User Setup guide
Direct them to configure both values in the plugin settings. That's all users need to do.
Revoking access
Revoke a user immediately
UPDATE refresh_tokens SET revoked = 1 WHERE email = 'jsmith@example.org';
The user's next turn will receive a 401 and the binary will log the error silently. No CC interruption.
Revoke a specific device (e.g. lost laptop)
Find the device's public key in the admin dashboard under Device Keys, then:
UPDATE device_keys SET revoked = 1 WHERE public_key = '<base64-public-key>';
Or use the Revoke button in the admin dashboard directly. The device goes silent on its next turn. The user's other devices and their refresh token are unaffected.
Re-provision a user after revocation
Delete the revoked refresh token and insert a new one:
DELETE FROM refresh_tokens WHERE email = 'jsmith@example.org' AND revoked = 1;
INSERT INTO refresh_tokens (token, email, expires_at)
VALUES ('rtok_newtoken...', 'jsmith@example.org', datetime('now', '+365 days'));
Send the new token to the user. They update it in the plugin settings. The binary will pick it up on the next turn.
Enabling signature enforcement
Once your initial users have set up the plugin, you can enforce signatures permanently:
REQUIRE_SIGNATURES=1
You do not need to toggle this flag for new users. REQUIRE_SIGNATURES only applies to /report. The key registration endpoint (/register-key) has no signature requirement — it only needs a valid access token. A new user's first turn registers their key via /register-key, and only then do signed reports flow to /report. If registration takes more than one turn (e.g. a temporary network failure), reports queue locally and are sent signed once registration succeeds.
The only case where enabling this flag causes a hard failure is a binary version that predates signing support (before v0.1.0). Check the admin dashboard's Device Keys table to confirm existing devices have registered before enabling, then leave it on permanently.