4.8 KiB
Self-Hosting
tono can be self-hosted on any server with Python 3.10+ and Node.js 18+.
Quick start
git clone https://github.com/VIPQualityPost/tono.git && cd tono
python -m venv .venv && source .venv/bin/activate
pip install -e .
cd frontend && npm ci && npm run build && cd ..
TONO_HOST=0.0.0.0 python -m backend.main
The server will be available at http://<your-server-ip>:8188.
Running as a system service
To keep tono running in the background and auto-restart on reboot, create a systemd service.
Create a service user
sudo useradd --system --create-home --shell /bin/false tono
sudo mkdir -p /var/lib/tono
sudo chown tono:tono /var/lib/tono
Clone and install
sudo git clone https://github.com/VIPQualityPost/tono.git /opt/tono
sudo chown -R tono:tono /opt/tono
sudo -u tono bash -c 'cd /opt/tono && python3 -m venv .venv && source .venv/bin/activate && pip install -e .'
sudo -u tono bash -c 'cd /opt/tono/frontend && npm ci && npm run build'
Create the unit file
Save as /etc/systemd/system/tono.service:
[Unit]
Description=tono
After=network.target
[Service]
Type=simple
User=tono
WorkingDirectory=/opt/tono
ExecStart=/opt/tono/.venv/bin/python -m backend.main
Environment=TONO_HOST=127.0.0.1
Environment=TONO_PORT=8188
Environment=TONO_APPDATA=/var/lib/tono
Environment=TONO_UPDATE_CHECK=off
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable and start
sudo systemctl daemon-reload
sudo systemctl enable tono
sudo systemctl start tono
sudo systemctl status tono # verify it's running
Useful commands
sudo journalctl -u tono -f # follow logs
sudo systemctl restart tono # restart after updates
HTTPS with Certbot
After setting up nginx (see Reverse proxy below), use Certbot to get a free TLS certificate from Let's Encrypt.
Install Certbot
# Ubuntu/Debian
sudo apt install nginx certbot python3-certbot-nginx
Get a certificate
Point your domain's DNS A record at your server's IP, then:
sudo certbot --nginx -d tono.yourdomain.com
Certbot will automatically:
- Obtain a certificate
- Configure nginx to use it
- Set up auto-renewal (certificates renew every 90 days)
You can verify auto-renewal works with:
sudo certbot renew --dry-run
Environment variables
| Variable | Default | Description |
|---|---|---|
TONO_HOST |
127.0.0.1 |
Bind address. Set to 0.0.0.0 for remote access. |
TONO_PORT |
8188 |
Listen port. |
TONO_APPDATA |
Platform-dependent | Data directory for sessions and uploads. |
TONO_PLUGINS |
0 (web mode) |
Set to 1 to enable the plugin system. Warning: plugins execute arbitrary Python code. |
TONO_SESSION_TTL |
60 |
Seconds to wait after a user disconnects before cleaning up their session data. Set to 0 to disable cleanup. |
TONO_UPDATE_CHECK |
(enabled) | Set to off to disable the GitHub release update checker. |
Reverse proxy
You will almost certainly want to run tono behind a reverse proxy for TLS termination. The key requirement is proxying WebSocket connections on /ws.
nginx
server {
listen 443 ssl;
server_name tono.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:8188;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_read_timeout 86400;
client_max_body_size 100M;
}
}
Caddy
tono.example.com {
reverse_proxy localhost:8188
}
Caddy handles TLS, WebSocket upgrades, and headers automatically.
Health check
GET /health returns {"status": "ok"} and can be used by load balancers or monitoring tools.
Authentication
tono does not include built-in authentication. For access control, use your reverse proxy:
- nginx: HTTP basic auth (
auth_basic) or integrate with an auth provider - Caddy:
basicauthdirective or forward auth - Cloudflare Access, Authelia, Authentik: external identity-aware proxies
Session lifecycle
Each browser tab creates an isolated session with its own uploaded files, execution engine, and cache. When a user closes their tab (WebSocket disconnects) and does not reconnect within TONO_SESSION_TTL seconds, the server automatically cleans up:
- Execution engine and cached results
- Uploaded files on disk
- Pending downloads and rate limit state
Set TONO_SESSION_TTL=0 to disable automatic cleanup (useful for single-user deployments).