Server Operator Guide¶
What The Server Operator Owns¶
tidal-server is the server operator CLI. It owns:
- Alembic migrations
- scanner execution
- optional kick daemon execution
- FastAPI serving
- API key management
- the canonical SQLite database
If this host does not have Tidal installed yet, start with Install.
The server should run close to both the database and the Ethereum RPC it depends on.
Recommended Deployment Shape¶
Minimal production deployment:
1 host / VM
- SQLite database file
- tidal-server scan daemon
- tidal-server api serve
- optional tidal-server kick daemon
Separate the CLI client wallet from this machine whenever possible.
First-Time Bootstrap¶
Install the tool, then scaffold the runtime home:
uv tool install /path/to/tidal
uv tool update-shell
tidal init
Then edit:
~/.tidal/config.yaml~/.tidal/.env~/.tidal/auction_pricing_policy.yaml
Then run:
tidal-server db migrate
tidal-server auth create --label cli-client-name
tidal-server scan run
tidal-server api serve
If you plan to reconcile receipts in the API process, set RPC_URL so the background reconciler can start.
Example Linux Deployment¶
One simple production shape is:
- host:
electro - user:
wavey - working directory:
/home/wavey/tidal - API bind:
127.0.0.1:8020 - reverse proxy: nginx terminating TLS at
api.tidal.wavey.info
Example ~/.tidal/.env:
RPC_URL=http://127.0.0.1:8545
TOKEN_PRICE_AGG_KEY=...
Example ~/.tidal/config.yaml overrides:
db_path: state/tidal.db
tidal_api_host: 127.0.0.1
tidal_api_port: 8020
scan_interval_seconds: 300
scan_auto_settle_enabled: false
Long-Running Commands¶
Scanner daemon:
tidal-server scan daemon --interval-seconds 300
Kick daemon:
tidal-server kick daemon --broadcast --sender 0xYourAddress --account wavey3
API:
tidal-server api serve
The API host and port normally come from ~/.tidal/config.yaml:
tidal_api_hosttidal_api_port
systemd Example¶
API service:
[Unit]
Description=Tidal API Server (FastAPI/uvicorn)
After=network.target
[Service]
Type=simple
User=wavey
Group=wavey
Environment=TIDAL_HOME=/home/wavey/.tidal
EnvironmentFile=/home/wavey/.tidal/.env
ExecStart=/home/wavey/.local/bin/tidal-server api serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Scanner oneshot service:
[Unit]
Description=Tidal Scan (oneshot)
After=network.target
[Service]
Type=oneshot
User=wavey
Group=wavey
Environment=TIDAL_HOME=/home/wavey/.tidal
EnvironmentFile=/home/wavey/.tidal/.env
ExecStart=/home/wavey/.local/bin/tidal-server scan run
Pair the scan oneshot with a systemd timer or external scheduler.
Adjust /home/wavey/.local/bin/tidal-server to whatever command -v tidal-server returns on the target host.
Reverse Proxy Example¶
Minimal nginx shape:
server {
listen 80;
listen [::]:80;
server_name api.tidal.wavey.info;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.tidal.wavey.info;
location / {
proxy_pass http://127.0.0.1:8020;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
DNS And TLS¶
For the API hostname, point an A record at your server before requesting certificates:
api.tidal.wavey.info A <server-ip>
Then issue the certificate with your normal ACME flow, for example certbot --nginx.
API Key Management¶
Create:
tidal-server auth create --label alice
List:
tidal-server auth list
Revoke:
tidal-server auth revoke alice
The API stores only SHA-256 hashes of keys. The plaintext key is shown once at creation time.
Database Notes¶
SQLite is the canonical datastore for this repo.
Runtime behavior:
- journal mode: WAL
- busy timeout: 30 seconds
- synchronous mode: NORMAL
That configuration is set in tidal/persistence/db.py.
Operational implications:
- keep the database on local disk
- avoid multiple independent writers outside the app
- expect occasional lock retries under write pressure
- back up the
.db,.db-wal, and.db-shmfiles consistently
Also ignore runtime data directories in git. A server-local data/ directory should never be committed.
With the current layout, the canonical runtime home is ~/.tidal/, not a repo-local data/ directory.
Auth Model¶
Public endpoints:
- dashboard
- logs
- kick inspect
- deploy defaults
- AuctionScan lookups
- health
Authenticated endpoints:
- kick prepare
- auction prepare routes
- action audit routes
Authentication is bearer-token based. Operator identity is currently the API key label.
Monitoring And Troubleshooting¶
Useful commands:
tidal-server logs scans
tidal-server logs kicks
tidal-server logs show <run_id>
Command Reference¶
Use these pages for the exact server operator command surfaces:
- Server Operator CLI Overview
- Server Operator:
tidal-server db - Server Operator:
tidal-server scan - Server Operator:
tidal-server api - Server Operator:
tidal-server auth - Server Operator:
tidal-server kick - Server Operator:
tidal-server auction - Server Operator:
tidal-server logs
Useful symptoms:
- no candidates: check scanner freshness, token prices, and auction mappings
- repeated
database is locked: investigate overlapping long-lived writes - API 503
No API keys configured: create at least one key withtidal-server auth create - missing receipt reconciliation: verify
RPC_URLis present in the API process environment
Useful logs:
journalctl -u tidal-api -f
journalctl -u tidal-scan -f
Deployment Boundaries¶
Do not point multiple CLI clients directly at the SQLite database. The intended model is:
- server owns DB and preparation logic
- CLI client talks over HTTP
- CLI client signs locally
That keeps schema changes and audit behavior centralized.