Skip to content

Deploy a project

This guide assumes your Compose project already builds locally and has a valid tarsail.yml.

For the shortest setup path, read Quick start first.

Run Compose config from the project root:

Terminal window
docker compose -p my-app -f compose.yaml config

If you configured compose.env_file.source, test with the same file:

Terminal window
docker compose -p my-app --env-file .deploy/prod.env -f compose.yaml config

Look for:

  • every service has an image value;
  • required environment variables are present;
  • bind mount paths make sense from the remote target path;
  • published ports match the intended public access path.

With default SSH configuration:

Terminal window
tarsail doctor

With a config file:

Terminal window
tarsail --config tarsail.production.yml doctor

With a specific private key:

Terminal window
tarsail --identity-file ~/.ssh/my-app-deploy-key doctor

With password authentication:

Terminal window
tarsail --ask-password doctor

doctor checks local readiness and remote readiness. It does not create a release bundle or start the app.

Terminal window
tarsail --identity-file ~/.ssh/my-app-deploy-key deploy

--ssh-key is an alias for --identity-file:

Terminal window
tarsail --ssh-key ~/.ssh/my-app-deploy-key deploy

Use key authentication for routine deployments when possible. It is easier to automate and usually more reliable.

Terminal window
tarsail --ask-password deploy

Tarsail prompts once:

SSH password for deploy@example.com:

The password is kept in memory for the current command and reused for SSH commands and file uploads in that run. Tarsail does not store it.

Password mode requires the host key to be trusted in your local known_hosts file. If the host is new, connect once with the system SSH client:

Terminal window
ssh deploy@example.com

Verify the host key before accepting it, then rerun Tarsail.

The deploy command prints eight major steps:

1/8 Checking local environment
2/8 Checking remote server
3/8 Building images
4/8 Creating bundle
5/8 Uploading bundle
6/8 Loading images
7/8 Starting Compose app
8/8 Reading status

The important behavior:

  • local Compose build runs before bundling;
  • configured env and secret files are uploaded to shared/;
  • the bundle is uploaded to incoming/;
  • the bundle is extracted into a new release directory;
  • images are loaded with docker load;
  • current points to the new release before Compose starts;
  • Compose receives current/.tarsail.env and any configured shared env file.

Use Tarsail:

Terminal window
tarsail status
tarsail logs --tail 100
tarsail logs --tail 100 web

Or inspect directly on the server:

Terminal window
ssh deploy@example.com
cd /opt/my-app
docker compose -p my-app --env-file current/.tarsail.env --env-file shared/.env -f current/compose.yaml ps

When no compose.env_file is configured, omit --env-file shared/.env.

Default config and SSH key:

Terminal window
tarsail --identity-file ~/.ssh/my-app-deploy-key deploy

Production config and SSH key:

Terminal window
tarsail --config tarsail.production.yml --identity-file ~/.ssh/my-app-deploy-key deploy

Production config and password:

Terminal window
tarsail --config tarsail.production.yml --ask-password deploy

Windows PowerShell with a binary variable:

Terminal window
& $TARSAIL --config .\tarsail.production.yml --ask-password deploy

If Compose startup fails after current has been updated, Tarsail reports:

Deployment failed after activation.
Run "tarsail rollback" to restore the previous release.

Run:

Terminal window
tarsail rollback

Then inspect logs and remote status:

Terminal window
tarsail logs --tail 300
tarsail status

Before a production deployment, confirm:

  • the target host and path are correct;
  • the Compose file is the intended production file;
  • compose.env_file.source points to an ignored local file;
  • real secrets are not committed;
  • remote Docker and Compose are installed;
  • required public ports are open in the OS firewall and cloud provider rules;
  • DNS points to the expected server when a domain is used;
  • database migrations are understood;
  • rollback limitations are acceptable.