Provider scoping (items 1/2/6): - Key visibility maps on (model_id.lower(), upstream_provider_id), matching refresh_model_maps, so a disable/override row on one provider never leaks onto another provider's model, and matching is case-insensitive. Data safety (items 3/5): - Degraded OpenRouter fetches (network error, 429, non-200, bad payload) return None (unknown) instead of []; a provider whose path set is unknown keeps its previously persisted rows instead of being wiped. - Endpoint payload parsing moved fully inside try, with a list guard, so endpoints:null or non-list shapes are swallowed as documented. - refresh with an empty live upstream list is a no-op; the unfiltered DELETE in the prune path is gone (prune now keys off enabled DB rows). Hot path (items 4/12/14): - Persist uses chunked bulk INSERTs (one statement per 500 rows) instead of per-row ORM adds; redundant ix_model_paths_model_id index dropped. - Read routes filter in SQL instead of materializing the whole table, and output ordering is deterministic (public id + path), independent of rowid. - Visibility no longer rebuilds fully priced Model objects per override row; it reads id/forwarded_model_id/canonical_slug straight off ModelRow. Path/id contract (items 7/8/9/11): - discovery_path_for_subprovider/discovery_base_paths hooks on BaseUpstreamProvider, overridden by OpenRouterUpstreamProvider, mirror _apply_provider_field so discovery and response stamping cannot drift (openrouter:OpenRouter now correctly maps to unknown). - openrouter_author_slug falls back to a slash-containing forwarded_model_id, so admin-created alias rows are discoverable. - public_model_id splits on the first slash, same as get_base_model_id, so discovery ids can be sent to chat completions verbatim. Lifecycle (items 10/13): - ENABLE_MODEL_PATHS_REFRESH kill switch; interval and flag re-read every loop iteration, and the task idles (not exits) while disabled. - First 429 latches and aborts the remaining fan-out for the cycle; a per-cycle cache dedupes fetches across providers sharing a base URL. - refresh_model_maps prunes paths of disabled/deleted providers so admin mutations take effect immediately; rows carry updated_at and both endpoints expose it. Tests (item 15) rewritten through the public refresh entry point with transport-level httpx.MockTransport fakes, FK enforcement on, and coverage for the periodic loop. Migration re-chained onto 9c4d8e2f1a6b.
8.7 KiB
Configuration
Routstr is configured primarily through the Admin Dashboard. All settings persist in the database and take effect immediately—no restarts required.
For automated deployments, you can optionally pre-configure settings via environment variables.
Initial Setup (.env file)
Before running your node, you should create a .env file in the project root. This file is used to bootstrap the initial configuration and store sensitive secrets.
Example .env
# Encrypts node secrets at rest. Optional — if unset, the node generates a key on
# first start and prints it once (back it up). Set it to manage the key yourself
# (recommended in production). See "Secrets at Rest" below.
ROUTSTR_SECRET_KEY=
# Node Identity
NAME="My AI Node"
DESCRIPTION="Fast access to models"
# Lightning Payouts
RECEIVE_LN_ADDRESS=yourname@wallet.com
Setting the UI Password
On first start the node generates an admin password and logs it once — read it from the container logs to sign in. You can then change it two ways:
- Via Dashboard: Once logged in, go to Settings → Security to update your password.
- Via Environment Variable (legacy seed): Setting
ADMIN_PASSWORDin.envbefore the first start seeds the initial password instead of generating one. It's read only once, for existing deployments; a value left in.envis ignored after the node has been configured.
Admin Dashboard (Primary)
Access the dashboard at /admin/ on your node.
Upstream Providers
Connect to your AI provider(s):
| Setting | Description |
|---|---|
| Upstream URL | API endpoint (e.g., https://api.openai.com/v1) |
| API Key | Your provider's API key |
Node Identity
How your node appears to clients:
| Setting | Description |
|---|---|
| Name | Display name (e.g., "Fast GPT-4 Node") |
| Description | Brief description of your service |
Pricing
Control your profit margins:
| Setting | Description | Default |
|---|---|---|
| Fixed Pricing | Charge flat rate per request vs. per-token | Off |
| Exchange Fee | Buffer for BTC volatility | 1.005 (0.5%) |
| Upstream Fee | Your profit markup | 1.10 (10%) |
See Pricing for detailed strategies.
Cashu Mints
Which mints to accept payments from:
| Setting | Description |
|---|---|
| Mints | List of trusted Cashu mint URLs |
Lightning Withdrawals
Automatic profit withdrawal:
| Setting | Description | Default |
|---|---|---|
| Lightning Address | Your LN address for withdrawals | — |
| Minimum Payout (sat) | Min available balance (in sats) before profit is paid out. Applies to both sat and msat mints (auto-converted). |
210 |
| Payout Interval (seconds) | How often the payout loop wakes up and checks balances | 900 |
All payout amounts must be positive. Set the minimums above your wallet's minimum-invoice constraint (typically 1 sat) and high enough to amortise routing fees.
Security
| Setting | Description |
|---|---|
| Admin Password | Password for dashboard access |
Nostr Discovery
Announce your node on the network:
| Setting | Description |
|---|---|
| Npub | Your Nostr public key |
| Nsec | Your Nostr private key (for signing) |
| Relays | Relays to publish announcements |
| Share Analytics | Publish aggregate usage stats to Nostr |
See Discovery for details.
Environment Variables (Optional)
Use environment variables for:
- Automated deployments (CI/CD, infrastructure-as-code)
- Secrets management (external secret stores)
- Initial bootstrap (set once, manage via dashboard later)
All Variables
| Variable | Description | Default |
|---|---|---|
UPSTREAM_BASE_URL |
Upstream API endpoint | — |
UPSTREAM_API_KEY |
Upstream API key | — |
ADMIN_PASSWORD |
Legacy seed for the dashboard password (otherwise generated + logged on first start) | (auto-generated) |
ROUTSTR_SECRET_KEY |
Master key encrypting node secrets at rest. Auto-generated to a key file if unset | (auto-generated) |
ROUTSTR_SECRET_KEY_FILE |
Path to the generated key file (used when ROUTSTR_SECRET_KEY is unset) |
routstr_secret.key beside the database |
DATABASE_URL |
Database connection string | sqlite+aiosqlite:///keys.db |
NAME |
Node display name | ARoutstrNode |
DESCRIPTION |
Node description | A Routstr Node |
NPUB |
Nostr public key (bech32) | — |
NSEC |
Legacy seed for the Nostr private key (otherwise set from the admin UI) | — |
ENABLE_ANALYTICS_SHARING |
Enable usage analytics sharing to Nostr | true |
CASHU_MINTS |
Comma-separated mint URLs | https://mint.minibits.cash/Bitcoin |
RECEIVE_LN_ADDRESS |
Lightning address for withdrawals | — |
MIN_PAYOUT_SAT |
Min payout balance in sats (applies to all mints) | 210 |
PAYOUT_INTERVAL_SECONDS |
Payout loop interval (seconds) | 900 |
TOR_PROXY_URL |
SOCKS5 proxy for Tor | socks5://127.0.0.1:9050 |
CORS_ORIGINS |
Allowed CORS origins | * |
RELAYS |
Nostr relays (comma-separated) | (default set) |
MODEL_PATHS_REFRESH_INTERVAL_SECONDS |
How often to refresh /v1/models/paths discovery data; set 0 to pause the refresh (previously discovered paths keep being served) |
600 |
ENABLE_MODEL_PATHS_REFRESH |
Kill switch for the background model-path refresh (OpenRouter endpoint fan-out) | true |
Priority
Environment variables are read on startup. Dashboard settings override them and persist in the database. Once you change a setting in the dashboard, the env var is ignored for that setting.
Secrets at Rest
The node's Nostr private key (nsec) is encrypted in the database using
ROUTSTR_SECRET_KEY. You don't have to set it: if it's unset, the node generates a
key on first start, writes it beside the database (the file named by
ROUTSTR_SECRET_KEY_FILE, default routstr_secret.key) so it persists on the same
volume as your data, and prints it once.
Back up that key — it lives on the same volume as your database, so include it
in your backups. If it is lost or changed, previously encrypted secrets can't be
decrypted and must be re-entered — there is no rotation. To keep the key off the
data volume, set ROUTSTR_SECRET_KEY explicitly (an env value always takes
precedence over the file). See also Deployment.
Models
Manage which AI models you offer:
- Go to Models in the dashboard
- Models are auto-discovered from your upstream
- For each model, you can:
- Enable/Disable — hide expensive models you don't want to serve
- Override pricing — set custom per-token rates
- Create aliases — friendly names for models
See Pricing for per-model pricing strategies.
Model path discovery is refreshed in the background and exposed through
/v1/models/paths. The response groups each client-visible model ID with the
provider paths that may appear in chat-completion response metadata. Tune the
refresh cadence with MODEL_PATHS_REFRESH_INTERVAL_SECONDS.