Coldtill Get Coldtill

Install and operations

Paste into Claude Code, Codex, Cursor or your favourite coding agent. View Markdown

This guide covers installing Coldtill on a Linux server, the first-run setup, and day-to-day operations: backups, upgrades, monitoring and key rotation.

Requirements

  • A Linux server with 2 GB of RAM or more. Any distribution with Docker works; these commands are for Ubuntu, Debian and Linux Mint.
  • A DNS name pointing at the server (for example pay.example.com), with ports 80 and 443 open. Caddy obtains the TLS certificate automatically.
  • For mainnet: an SMTP account for payout approval emails, and RPC endpoints you trust (see Nodes).

Install Docker and the Compose plugin:

sudo apt update
sudo apt install docker.io docker-compose-v2 git
sudo usermod -aG docker $USER   # log out and back in afterwards

Install

git clone git@github.com:rollounden/coldtill.git
cd coldtill/deploy
./install.sh --mode testnet --site-url https://pay.example.com

install.sh accepts --mode testnet|mainnet, --site-url URL and --no-build (use a prebuilt image set in COLDTILL_IMAGE). It:

  1. builds the coldtill:local image;
  2. runs coldtill init, which asks for a hot-wallet passphrase (at least 12 characters) and writes:
    • deploy/.env: mode, site URL, the server secret, the database password and the age recipient;
    • deploy/secrets/coldtill-identity.age: the hot-wallet identity, encrypted under your passphrase;
    • deploy/secrets/hot_passphrase: the passphrase, so the sweeper and payouts can restart unattended;
  3. starts PostgreSQL, the four Coldtill processes and Caddy with Docker Compose. Database migrations run automatically when the processes start.

For a local trial without DNS, use --site-url http://localhost:8080.

Running without a stored passphrase

If you'd rather not keep the passphrase on disk, initialise with coldtill init --store-passphrase=false (or delete deploy/secrets/hot_passphrase) and supply it each time you start the stack:

cd deploy
read -rs COLDTILL_HOT_PASSPHRASE && export COLDTILL_HOT_PASSPHRASE
docker compose up -d
unset COLDTILL_HOT_PASSPHRASE

Only the sweeper and payouts containers receive it. If either container restarts, it can't unlock the hot wallets until you run this again.

First-run setup

Open the site URL and create the root account (the first account becomes root). Then, in order:

  1. Account: enable two-factor authentication. Anything that moves or redirects money needs a fresh two-factor code, so most of the steps below require it.
  2. Nodes & networks: enable the networks you want, set confirmations, and add RPC nodes. Public defaults are rate limited and fine only for testing.
  3. Projects: rename the default project or add more. Each project is a shop with its own settings.
  4. Deposit wallets (per project):
    • Bitcoin: paste a BIP84 account xpub (zpub on mainnet, vpub on signet). The browser derives the first address; confirm it matches your wallet's first receive address.
    • EVM: connect a browser wallet (your "master" account) and enter your cold wallet. Deploy the deposit factory on each EVM network from the same master account; the factory address is the same on every chain.
    • Solana: connect a wallet, enter your treasury (a hardware wallet or a Squads vault address), save, then create the config by signing in your wallet. The browser checks the transaction before signing.
  5. Hot wallets (global admin): generate or import one EVM and one Solana key. Fund each with a little gas, then assign them to the project.
  6. Project settings: branding, sweep thresholds, payout limits and (optional) auto-convert. See Branding, Payouts and Auto-convert.
  7. API keys and webhooks: create an API key (project admin, with two-factor) and a webhook endpoint for your shop. See Merchant API and Webhooks.

Users and roles

  • Root: the first account. It can do everything, and is the only account that can disable admins.
  • Admin: global administrator. Manages nodes, networks, hot wallets and users.
  • Member: access only to the projects they are added to, with a project role:
    • project_admin: settings, deposit wallets, creating API keys, the address book, payouts and approvals;
    • developer: payments, webhooks, and revoking API keys, but not settings, payouts or creating keys;
    • read_only: view only.

Nodes and networks

Coldtill trusts RPC nodes to report deposits. A malicious node can't redirect funds, but it could report a deposit that never happened. For production:

  • run your own node, or use a paid provider (Alchemy, Infura, QuickNode, Helius, Blockstream) with an API key;
  • add more than one node per network, so failover works and decisions that ask every node (Solana payout re-signing, Bitcoin dropped deposits) have something to compare;
  • keep the default confirmation counts or raise them. Lowering them needs a two-factor code.

Backups

What to back up, and what losing it means:

Item Where If lost
Database pgdata Docker volume Payment history, settings, encrypted hot keys. Customer funds are safe on-chain, but you lose the records
deploy/.env Server The server secret: sessions, two-factor secrets and webhook secrets become unreadable
deploy/secrets/ Server The hot-wallet identity. You'd need to re-import or replace hot wallets
Cold wallet seed Offline, with you Everything swept so far. Coldtill can't help with this

Nightly database dump:

cd ~/coldtill/deploy
docker compose exec -T postgres pg_dump -U coldtill coldtill | gzip > ~/backups/coldtill-$(date +%F).sql.gz

Add it to cron with crontab -e:

15 3 * * * cd $HOME/coldtill/deploy && docker compose exec -T postgres pg_dump -U coldtill coldtill | gzip > $HOME/backups/coldtill-$(date +\%F).sql.gz

Copy deploy/.env and deploy/secrets/ to encrypted offline storage once, and again whenever they change.

Restore

cd ~/coldtill/deploy
docker compose up -d postgres
gunzip -c ~/backups/coldtill-2026-10-01.sql.gz | docker compose exec -T postgres psql -U coldtill coldtill
docker compose up -d

Restore .env and secrets/ from the same point in time as the dump.

Upgrades

cd ~/coldtill
git pull
cd deploy
docker compose build
docker compose up -d

Migrations run on start-up. Take a database dump first. Read the release notes before upgrading across major versions.

Never run make contracts on a live install: rebuilding the EVM contracts changes the factory bytecode, and with it every deposit address.

Monitoring

  • Health: https://pay.example.com/healthz returns ok. The api container has a Docker health check.

  • Logs are JSON, one line per event:

    docker compose logs -f --since 1h api watcher sweeper payouts
    docker compose logs sweeper | grep '"level":"WARN"'
    
  • Things to alert on:

    • "level":"ERROR" from any process;
    • conversion delivery mismatch, filled a nonce gap, sweep not possible, hot wallet … needs at least;
    • payouts in needs-review (they also send a payout.needs-review webhook);
    • a network's "last block processed" in Nodes & networks falling behind.
  • Hot wallet balances: shown under Hot wallets. Top them up before they run dry, or sweeps stop.

Rotating secrets

  • Hot wallet: add a new hot wallet, assign it to the project, move any remaining balance out of the old one with your own wallet, then delete the old one.
  • API key: create a new key, deploy it, then revoke the old one.
  • Webhook secret: create a new endpoint, switch your receiver, then delete the old endpoint.
  • Hot-wallet passphrase: re-run coldtill init --force in a scratch directory to create a new identity, then re-import the hot keys under the new identity. Plan this as a maintenance window.
  • COLDTILL_SECRET: changing it signs everyone out and makes stored two-factor and webhook secrets unreadable. Users must re-enrol two-factor and webhooks must be recreated. Only rotate it after a suspected compromise.

Moving to mainnet

Run a separate install with --mode mainnet. Mainnet requires an https:// site URL and SMTP settings (COLDTILL_SMTP_HOST, COLDTILL_SMTP_PORT, COLDTILL_SMTP_USERNAME, COLDTILL_SMTP_PASSWORD, COLDTILL_SMTP_FROM). Before taking real payments, work through the mainnet checklist in Audit preparation and the advice in How to get Coldtill audited.