Rediacc can run entirely on your own infrastructure. The standalone Docker image includes the account server, web portal, marketing site, and CLI distribution endpoint. No external dependencies on Rediacc’s hosted services are required.
Docker Image
Pull the standalone image:
docker pull ghcr.io/rediacc/server:stable
Run with default settings:
docker run -p 80:80 -p 443:443 ghcr.io/rediacc/server:stable
The image serves:
- Account API at
/account/api/v1/ - Web portal at
/account/ - Marketing site at
/ - CLI artifacts at
/releases/ - Renet binaries at
/bin/
Installing the CLI from Your Server
Users can install the CLI directly from your on-premise server. The install script auto-detects the update channel and configures the CLI to check your server for updates.
curl -fsSL https://account.example.com/install.sh | \
REDIACC_SERVER_URL=https://account.example.com bash
This single command:
- Downloads the CLI binary from your server’s
/releases/endpoint - Queries
/account/api/v1/.well-known/server-infoto discover the update channel - Writes
server.jsonwith your server URL, update channel, and encryption keys - Configures
rdc updateto check your server for future updates
No REDIACC_CHANNEL variable is needed. The install script reads the channel from your server’s configuration automatically.
CLI Configuration with Named Configs
For users who connect to multiple servers (on-premise, production, edge), named configs keep each environment isolated:
# Create a config for your on-premise server
rdc config init --name myserver --server https://account.example.com
# Log in using that config
rdc --config myserver subscription login
# All commands with --config use the on-premise server
rdc --config myserver machine query --name prod-1
Each named config stores its own account server URL and subscription token. Switching configs switches the entire server context.
Air-Gapped Environments
For environments without internet access, set both the server URL and a custom releases URL:
curl -fsSL https://account.example.com/install.sh | \
REDIACC_SERVER_URL=https://account.example.com \
REDIACC_RELEASES_URL=https://account.example.com/releases \
bash
The CLI will check account.example.com/releases/cli/stable/manifest.json for updates instead of the public releases CDN.
If the server is completely offline, install the CLI via npm from the bundled tarball:
npm install -g https://account.example.com/npm/rediacc-cli-latest.tgz
Environment Variables Reference
| Variable | Used by | Purpose |
|---|---|---|
REDIACC_SERVER_URL | Install script | Account server URL. Auto-discovers channel and encryption keys. |
REDIACC_RELEASES_URL | Install script, CLI updater | Custom releases endpoint for CLI binaries. Default: https://releases.rediacc.com |
REDIACC_CHANNEL | Install script | Override the update channel. Auto-detected from server if not set. |
REDIACC_ACCOUNT_SERVER | CLI runtime | Override account server URL for all CLI commands. |
RDC_UPDATE_CHANNEL | CLI runtime | Override update channel for rdc update. |
Server Configuration
The on-premise Docker image uses the same ENVIRONMENT variable as the hosted service. Set it in your Docker environment or orchestration config:
ENVIRONMENT=production(default): standard limits, stable update channel recommended to clientsENVIRONMENT=edge: 2X Community limits, edge update channel recommended to clients
See Release Channels for details on what each environment provides.
What the Server Tells the CLI
When the CLI connects to your server, it queries /.well-known/server-info to discover:
- E2E encryption public key: for zero-knowledge config storage
- Minimum CLI version: blocks outdated CLIs from connecting
- Update channel: tells the CLI which release channel to use for updates
- Environment: whether this is a production or edge deployment
This auto-configuration means users only need the server URL. Everything else is discovered automatically.
Licensing for Air-Gapped Deployments
Air-gapped and self-hosted on-premise servers issue licenses locally using a delegation certificate signed by the upstream master key. The certificate constrains the on-premise server to its plan limits and creates a tamper-evident chain. See License Chain & Delegation for the cryptographic design (chain integrity, fork detection, audit proofs).
This section covers the operational setup: generating keys, requesting the cert, configuring auto-renew, and the offline (air-gapped) renewal flow.
One subscription, one on-premise install
A subscription may have at most one active delegation certificate at a time. Each on-premise install enforces per-month and per-machine limits against its own local issuance ledger, so multiple active certs would multiply the effective quota with no possible reconciliation.
If you need separate environments (production, staging, DR, multi-region), purchase one subscription per install. The single-active enforcement codifies this contract: an attempt to create a second active cert returns 409 DELEGATION_CERT_ALREADY_ACTIVE with the existing cert id and instructions to renew (preferred - preserves the chain) or revoke-and-create (resets the chain).
1. Generate the on-premise Ed25519 key pair
The on-premise server uses a separate Ed25519 key pair to sign licenses. The upstream’s delegation cert authorizes this specific public key.
# Generate a fresh keypair
openssl genpkey -algorithm Ed25519 -out onprem-private.pem
openssl pkey -in onprem-private.pem -pubout -out onprem-public.pem
# Convert to base64 (the format the on-premise expects in env vars)
ON_PREMISE_PRIVATE_KEY=$(openssl pkey -in onprem-private.pem -outform DER | base64 -w 0)
ON_PREMISE_PUBLIC_KEY=$(openssl pkey -in onprem-private.pem -pubout -outform DER | base64 -w 0)
Store the private key alongside your other secrets (for example, a Docker secret or Kubernetes Secret). It never leaves the on-premise box.
2. Request a delegation cert from the upstream
You can request the cert from the upstream account portal in three ways:
Option A - Customer self-service (recommended). Log into the upstream portal as an org owner or admin and navigate to /account/delegation-certs. Click Create New, paste the on-premise public key (base64 SPKI), choose a validity (or accept the per-plan default), and download the resulting .json file.
Option B - Admin (cross-customer). Rediacc support or the upstream system admin can use POST /admin/delegation-certs with the same parameters.
Option C - rdc CLI (planned). A future CLI command will wrap the portal flow.
The returned .json looks like:
{
"payload": "eyJ2ZXJzaW9uIjoxLCJzdWJzY3JpcHRpb25JZCI6...",
"signature": "...",
"publicKeyId": "..."
}
The cert’s validity is governed by the validity policy (per-plan defaults and ceilings, per-subscription override, capped at subscription end + 3 day grace). The response also includes effectiveDays and reason so you can see why it picked that value. See License Chain - Validity Policy for the full rules.
3. Install the cert on the on-premise server
Save the downloaded .json to a known path and point the on-premise to it:
DELEGATION_CERT_PATH=/etc/rediacc/delegation-cert.json
Or, for ephemeral / Docker-secrets workflows, embed the cert as base64 in an env var:
DELEGATION_CERT_BASE64=$(base64 -w 0 < delegation-cert.json)
4. Configure upstream verification + auto-renew (optional but recommended)
If your on-premise has outbound HTTPS access to the upstream, set up automatic renewal so the cert refreshes before expiry without manual intervention:
# Required for /onprem/cert-upload to verify uploaded certs against the upstream master key.
# Fails-fast at boot if UPSTREAM_API_KEY is set without this.
UPSTREAM_PUBLIC_KEY="<upstream master Ed25519 SPKI public key, base64>"
# Required for the auto-renew loop. Mint via the portal:
# Org owner/admin → /account/delegation-certs → "Get auto-renew token"
# This is the ONLY way to obtain a delegation:renew-scoped api token.
UPSTREAM_URL="https://www.rediacc.com"
UPSTREAM_API_KEY="rdt_..."
# Optional tuning (defaults shown).
AUTO_RENEW_INTERVAL_HOURS=24
RENEW_THRESHOLD_DAYS=14
The on-premise auto-renew loop runs once at boot and then on the configured interval. It uses an adaptive threshold (min(env.RENEW_THRESHOLD_DAYS, ceil(certValidityDays / 3))) so a 15-day COMMUNITY cert renews at 5 days remaining instead of triggering renewal on day 1. A 90-day BUSINESS cert renews at 14 days remaining (the env-configured ceiling).
If renewal fails, the cert stays in use until natural expiry. The failure backs off for 1 hour and is recorded in ${DELEGATION_CERT_PATH}.status.json plus exposed via GET /onprem/cert-status.
5. Air-gapped renewal (no outbound HTTPS)
If your on-premise cannot reach the upstream, use the manual transfer flow:
- Download a renewal request from the on-premise admin portal. As the on-premise system root, hit
GET /onprem/renewal-request. This returns a JSON manifest containing the local chain head, the delegated public key, and a tamper-evident Ed25519 signature from your on-premise private key. - Transfer the manifest to the upstream via USB, encrypted email, or any out-of-band channel. The manifest is small (a few KB) and contains no secrets.
- Process the manifest at the upstream. Org owner/admin opens /account/delegation-certs → Upload renewal request → selects the manifest file. The upstream verifies the manifest signature against the active cert’s
delegatedPublicKey(proves it came from a holder of the on-premise private key), checks anti-replay (manifests older than 7 days are rejected), then issues a fresh cert. - Download the new cert from the upstream portal as a
.jsonfile. - Transfer the cert back to the on-premise.
- Upload to the on-premise via the local admin portal (
POST /onprem/cert-upload). The on-premise verifies the new cert againstUPSTREAM_PUBLIC_KEYand validates that the cert’sgenesisSequencestill links to a chain entry in the local issuance ledger (sequence advancement during transit is supported - the chain extends naturally).
This entire loop never requires network egress from the on-premise.
Manifest failure modes
| Code | Cause | Fix |
|---|---|---|
NO_ACTIVE_CERT | Upstream has no active cert for this subscription | Issue a new cert via the create flow instead of renewing |
DELEGATED_KEY_MISMATCH | Manifest’s delegatedPublicKey differs from the active cert | The manifest may be a replay from a different on-prem install |
MANIFEST_SIGNATURE_INVALID | Signature doesn’t verify against the delegated public key | Manifest was tampered in transit, or you generated it on a different on-prem |
MANIFEST_EXPIRED | Manifest is more than 7 days old | Generate a fresh renewal request from the on-premise |
Cert upload failure modes
| Code | Cause | Fix |
|---|---|---|
CHAIN_HEAD_BEHIND | New cert’s genesisSequence is ahead of local chain head | Upstream is on a forked chain - investigate |
CHAIN_FORK_ON_UPLOAD | Chain hash at the cert’s genesisSequence doesn’t match local ledger | Local chain has diverged from upstream - investigate |
Signature verification failed | Cert isn’t signed by the configured UPSTREAM_PUBLIC_KEY | Check that UPSTREAM_PUBLIC_KEY matches the upstream master public key |
6. Status and monitoring
Query the on-premise local cert state at any time:
curl https://onprem.example.com/account/api/v1/onprem/cert-status \
-H "Cookie: <admin session>"
Returns the loaded cert’s subscriptionId, planCode, validUntil, daysUntilExpiry, plus the autoRenew block (enabled, lastSuccessAt, lastErrorAt, lastError). Wire this into your monitoring stack to alert on stale lastSuccessAt or non-null lastError.
For backup and audit, the on-premise admin can also download the currently loaded signed cert via GET /onprem/cert-current (requires elevated session).
Delegation cert env var reference
| Variable | Required? | Purpose |
|---|---|---|
ON_PREMISE_MODE | Yes | Set to true to enable the on-premise route subset |
ON_PREMISE_PRIVATE_KEY | Yes | Base64 PKCS8 Ed25519 private key for delegated signing |
ON_PREMISE_PUBLIC_KEY | Yes | Base64 SPKI Ed25519 public key (must match the cert’s delegatedPublicKey) |
DELEGATION_CERT_PATH | One of these | Filesystem path to the signed cert JSON |
DELEGATION_CERT_BASE64 | One of these | Base64-encoded cert JSON (alternative to file path) |
UPSTREAM_PUBLIC_KEY | Required if UPSTREAM_API_KEY is set, or for /onprem/cert-upload to work | Base64 SPKI of the upstream master public key. Fail-fast at boot if missing. |
UPSTREAM_URL | For auto-renew | Upstream account server base URL, e.g. https://www.rediacc.com |
UPSTREAM_API_KEY | For auto-renew | A delegation:renew-scoped api token. Mint via the portal - see Step 4. |
AUTO_RENEW_INTERVAL_HOURS | Optional | Default 24. How often to check whether the cert needs renewal. |
RENEW_THRESHOLD_DAYS | Optional | Default 14. Acts as a ceiling on the adaptive 1/3-of-validity threshold. |
Threat model summary
The delegation cert model defends against:
- Forged licenses: the on-premise can only sign within its plan limits; renet rejects anything outside the cert’s bounds.
- Cert sharing across deployments: chain divergence is detected at renewal (returns
CHAIN_FORK_DETECTED). - Quota bypass via multi-install: enforced at the upstream by single-active (one cert per subscription).
- Chain rollback: renet stores the highest-sequence-seen per subscription and rejects any blob with a lower sequence.
- Compromised upstream credentials: the bootstrap
delegation:renewtoken is mintable only via the dedicated portal endpoint and is admin-gated. The token grants only renewal - it cannot read or modify any other resource. - Replay attacks on manifests: manifests older than 7 days are rejected.
What it does not defend against:
- Compromised on-premise private key: a leaked private key lets an attacker sign licenses up to the cert’s
validUntil. Mitigation: rotate the keypair (revoke old cert + create new with new key) and treat all licenses signed by the old key as suspect. - Compromised upstream master key: this is the trust root. Rotation procedures are out of scope here.