Deployment
Deploy your Soli applications to remote servers with a single command. Blue-green deployments via soli-proxy, or bundle your app into a single binary for zero-dependency deployment.
Parallel Deployment
Deploy to multiple servers simultaneously with automatic git pull and blue-green switching.
Quick Start
Create a deploy.toml file in your project root:
git_url = "https://github.com/your-org/your-project.git"
git_branch = "main"
git_folder = "www/"
[[servers]]
name = "prod-1"
username = "deploy"
ip = "192.168.1.100"
folder = "/var/www/myapp"
api_key = "your-api-key"
proxy_url = "https://proxy.example.com"
[[servers]]
name = "prod-2"
username = "deploy"
ip = "192.168.1.101"
folder = "/var/www/myapp"
api_key = "your-api-key"
proxy_url = "https://proxy.example.com"
Then run:
soli deploy
Configuration
Global Settings
git_url— Git repository URL (required)git_branch— Branch to deploy (default:main)git_folder— Subfolder to deploy, e.g.www/(default:/)
Server Settings
name— Server identifier for loggingusername— SSH usernameip— Server IP addressfolder— Deployment path on serverapi_key— soli-proxy API keyproxy_url— soli-proxy base URL
Deployment Flow
Deployment happens in two phases:
Phase 1: Sync Code (parallel)
All servers sync code simultaneously via SSH:
- SSH connect to
username@ip - Git clone (first deploy) or git pull (subsequent)
Phase 2: Migrations (first server only)
Database migrations run only on the first server to avoid conflicts:
- SSH to first server
- Run
soli db:migrate up
Phase 3: Deploy (parallel)
All servers trigger blue-green deployment simultaneously:
- POST to soli-proxy deploy API
- Automatic health checks and traffic switch
Asset cache during deploys
In production mode the server snapshots every .css and .js file under public/ into memory at boot. If new asset bytes land on disk before the binary restarts, the running process keeps serving its frozen snapshot — preventing the classic mismatch where in-flight HTML references one asset version while the disk has another. The next binary start reloads from disk. See Production Mode for details.
Requirements
- SSH key-based authentication (keys must be added to ssh-agent)
- The
solibinary must be in your PATH - soli-proxy running on each target server
- Valid API keys configured in soli-proxy
Usage
# Deploy from current directory
soli deploy
# Deploy from specific folder
soli deploy --folder /path/to/project
# Short form
soli deploy -f /path/to/project
Output Example
Deploying from /path/to/project...
Phase 1: Syncing code to all servers...
[prod-1] Connecting to [email protected]...
[prod-1] Folder exists, pulling latest changes...
[prod-1] Code synced ✓
[prod-2] Connecting to [email protected]...
[prod-2] Folder exists, pulling latest changes...
[prod-2] Code synced ✓
[prod-1] Running database migrations...
[prod-1] soli db:migrate up
[prod-1] Migrations completed ✓
Phase 2: Triggering blue-green deploy on all servers...
[prod-1] Triggering blue-green deploy...
[prod-1] Deploy started on slot green ✓
[prod-2] Triggering blue-green deploy...
[prod-2] Deploy started on slot blue ✓
✓ 2/2 servers deployed successfully
Bundle Deployment
For simpler, dependency-free deployment, bundle your application into a single .soli file. No source files needed on the server — only the soli binary and the bundle.
# Build the bundle
soli build my_app
# Deploy just the .soli file
scp my_app.soli deploy@server:/opt/my_app/
# Run from the bundle
ssh deploy@server "soli serve /opt/my_app/my_app.soli"
Bundle mode in deploy.toml
The soli deploy command supports mode = "bundle" to automatically SCP the bundle to all servers:
mode = "bundle"
bundle_source = "./my_app.soli"
[[servers]]
name = "prod-1"
username = "deploy"
ip = "192.168.1.100"
folder = "/opt/myapp"
proxy_url = "https://proxy.example.com"
How it works
soli build collects all .sl, .slv, .yml, .css, .js files into a single .soli bundle. When you run soli serve app.soli, the bundle is extracted to /tmp/soli_PID and the server boots normally. On the proxy side, set start_script = "soli serve /opt/myapp/my_app.soli --port $PORT --workers $WORKERS" in the app's app.infos. Migrations should be run locally before bundling — auto-migration is not supported in bundle mode.