Configuration
env files and console settings.
Where each setting lives: server settings in the server env file, public build settings in VITE_* variables, and everything that changes behaviour day to day in the operator console.
01Three places, one rule
| Where | What goes there | A change needs |
|---|---|---|
Server env (apps/server/.env, /etc/mikodes-checkout/server.env or deploy/.env) | RPC URLs, fee addresses, operator key, console key, URLs, paths | A server restart |
VITE_* at build time | API origin, public RPC, Base router address for the browser | Rebuilding the web apps |
| Operator console | Fees, tiers, fee credit, referral, branding, legal, checkout behaviour, chains and assets, onboarding, webhooks, sanctions mode, integrations | Save in the console. No restart. |
Everything in a VITE_* variable is compiled into JavaScript that every visitor downloads. Never put a paid RPC key, an API key or any secret there. The browser gets a read-only proxy (/public/solana/prep/:id) so your RPC URL stays on the server.
02Server env
Template: apps/server/.env.example (Docker: deploy/.env.example). Keys and addresses have no defaults; empty means disabled. The server refuses to start with an invalid value and names it.
| Variable | Purpose | Default |
|---|---|---|
SOLANA_RPC_URL Required | Your Solana RPC. Enables Solana. | empty |
SOLANA_CHAIN | solana-devnet or solana-mainnet: which network that RPC serves. | solana-devnet |
OPERATOR_SOLANA_ADDRESS | Where your fee goes on Solana (public address). Empty = no fee on Solana. | empty |
BASE_RPC_URL, BASE_CHAIN | Your Base RPC; base-sepolia or base-mainnet. | empty, base-sepolia |
BASE_ROUTER_ADDRESS | Your deployed MikodesPayRouter. Required when BASE_RPC_URL is set (how). | empty |
BASE_CONFIRMATIONS | Blocks before a Base payment counts as confirmed. | 12 |
OPERATOR_BASE_ADDRESS | Where your fee goes on Base. Empty = no fee on Base. | empty |
OPERATOR_ADMIN_KEY | Operator API key, at least 32 characters. Empty disables every /v1/operator endpoint. Generated by the setup script. | empty |
ADMIN_SECRET_KEY | 32 bytes (openssl rand -hex 32). Encrypts console secrets (Telegram token, SMTP URL) at rest. Empty = console off. | empty |
PUBLIC_CHECKOUT_URL | Checkout base URL; invoices get checkoutUrl = <this>/pay/<id>. | empty |
PUBLIC_ADMIN_URL | Base URL of the portal, used in invite, verification and Telegram texts. | empty |
CORS_ORIGINS | Comma-separated browser origins allowed to call the API (checkout, admin, landing). | empty |
PORT, HOST | Where the server listens. 127.0.0.1 behind a reverse proxy, 0.0.0.0 in a container. | 8787, 127.0.0.1 |
TRUST_PROXY | true only behind a reverse proxy you control (uses X-Forwarded-For for rate limits). | false |
DATABASE_PATH | SQLite file. | ./data/checkout.sqlite |
ADMIN_DATABASE_PATH | Console storage. | admin.sqlite next to DATABASE_PATH |
ADMIN_UI_DIR, OPS_UI_DIR | Built console and product pages, if not next to the server. | found automatically |
SANCTIONS_LIST_PATH | Sanctions address list (how). Empty = screening disabled, with a warning at every start. | empty |
DEMO_MODE | true enables POST /demo/invoices (testnets only, labelled DEMO). Keep false in production. | false |
WATCH_INTERVAL_MS | Chain watcher poll interval (250 to 60000). | 2000 |
WEBHOOK_ALLOW_PRIVATE | true only for local development with a webhook receiver on localhost (turns off SSRF protection). Never in production. | empty |
SESSION_COOKIE_INSECURE | Local development over plain http only: drops the Secure flag of portal session cookies. | empty |
TELEGRAM_BOT_TOKEN, SMTP_URL, MAIL_FROM | Notifications. You can also set them in Console → Integrations (stored encrypted); MAIL_FROM is required with SMTP. | empty |
LOG_LEVEL | fatal … trace, or silent. | info |
Demo only (read by scripts/demo-reset.mjs): DEMO_MERCHANT_SOLANA_ADDRESS, DEMO_MERCHANT_BASE_ADDRESS.
03Web app build settings
| Variable | App | Purpose |
|---|---|---|
VITE_API_URL | checkout, portal, interim portal | API origin. Empty = same origin (behind Caddy). |
VITE_SOLANA_RPC_URL | checkout, portal | Optional public, keyless Solana RPC for the browser: pre-sign simulation in the checkout, refund signing in the portal. |
VITE_BASE_ROUTER_ADDRESS | checkout | Same router address as the server. Empty = Base wallet pay off. |
VITE_WALLETCONNECT_PROJECT_ID | checkout | Optional. Empty = WalletConnect not offered; injected wallets (MetaMask, Rabby …) and Coinbase Wallet still work. Enabling it also needs @walletconnect/ethereum-provider, which you install and licence-check yourself. |
VITE_MOCK | checkout | Local development only (mock API and wallet). A production build refuses it. |
VITE_CHECKOUT_URL, VITE_BASE | portal | Public checkout origin for links; optional sub-path such as /portal/. |
Templates: apps/checkout/.env.example, apps/portal/.env.example.
04Caddy settings
Read from the Caddy env file (bare metal) or deploy/.env (Docker), documented in the header of deploy/caddy/Caddyfile:
| Variable | Purpose |
|---|---|
PAY_DOMAIN Required | Checkout, public API and merchant API, e.g. pay.example.com. |
ADMIN_DOMAIN | Console (/admin, /ops), operator API and the interim merchant portal. Unset = internal port 8082 only. |
ADMIN_ALLOW_IPS | Space-separated CIDRs allowed on the admin domain. Default: everyone. |
SITE_DOMAIN | Landing page. Unset = internal port 8083 only. |
API_UPSTREAM, WEB_ROOT | Server address (127.0.0.1:8787 or server:8787) and the folder with checkout/, admin/, landing/. |
05Settings in the console
Everything else is edited in the operator console and applies without a restart: Operator console lists every section and field. Money fields start off: the default fee is 0 bps, tiers are empty and the referral share is 0.