What this guide covers
This guide covers a FastAPI deployment flow where Pystrano clones your Git repository into a timestamped release directory, installs Python dependencies, links shared files, optionally runs Alembic migrations and static asset commands, updates the current symlink, restarts a systemd service, and prunes old releases.
Server assumptions
- You have a VPS-style Linux server where you can SSH as
rootfor setup. - The server can reach your Git repository over SSH.
- System packages can be installed with
apt. - Uvicorn is managed by a systemd service file that you provide or generate with
pystrano init. - Database, TLS, firewall, backups, and monitoring are handled outside Pystrano.
FastAPI project assumptions
- Your repository contains a dependency file such as
uv.lockorrequirements.txt. - Your FastAPI app can be served by Uvicorn from the module path used in your systemd service.
- Your production settings read environment variables from the environment Pystrano loads from your dotenv file.
- If you enable migrations, Alembic is available or
migration_commandpoints to the command your app uses.
Example deployment config
config_version: 2
common:
source_code_url: "git@github.com:example/example-fastapi-app.git"
framework: "fastapi"
project_root: "apps/example-fastapi-app"
project_user: "deploy"
venv_dir: ".venv"
package_manager: "uv"
dependency_file: "uv.lock"
keep_releases: 5
system_packages: |
libpq-dev
python3-dev
build-essential
env_file: "./deploy/example_fastapi_app/production/.env"
ssh_known_hosts: "github.com"
service_file: "./deploy/example_fastapi_app/production/uvicorn.service"
secrets: "./deploy/example_fastapi_app/production/app-secret.txt"
branch: "main"
clone_depth: 1
migration_command: "/home/deploy/.venv/bin/alembic upgrade head"
servers:
- host: "app1.example.com"
port: 22
run_migrations: true
collect_static_files: false
Uvicorn and systemd notes
When service_file is configured, setup copies it to /etc/systemd/system/<service_file_name>, reloads systemd, and enables the service. Deploy restarts that service after promoting the new release.
pystrano init can generate a starter uvicorn.service. Review the module path, environment variables, worker settings, and socket or port binding before using it for production traffic.
Dependency installation
The example uses package_manager: uv with dependency_file: uv.lock. Pystrano ensures uv exists in the virtualenv, then runs a frozen uv sync against that virtualenv. FastAPI apps can also use package_manager: pip with requirements.txt, or dependency_install_command for a custom install flow.
Running migrations
Set run_migrations: true on the server that should run FastAPI migrations. By default Pystrano runs:
/home/deploy/.venv/bin/alembic upgrade head
Set migration_command when your app uses a different Alembic path, Python module invocation, or migration system.
Static asset commands
FastAPI does not have a built-in static collection command. If a server has collect_static_files: true, set static_files_command to the exact command Pystrano should run during deploy.
Deploying
Preview first:
pystrano deploy production example_fastapi_app --dry-run
Deploy when ready:
pystrano deploy production example_fastapi_app
Rolling back
Pystrano keeps timestamped release directories and promotes a release by updating the current symlink. It does not currently include a rollback CLI command. Keep keep_releases high enough for your recovery window and document a tested manual rollback procedure for your servers.
Troubleshooting
- Use
--dry-runbefore live changes to inspect remote commands. - Use
--verbosewhen Fabric, Invoke, or Paramiko output is needed. - Confirm the server can clone the repository and reach the configured Git host.
- Confirm uv, Alembic, and any custom static build commands are available after dependency installation.
- Confirm local paths referenced by
env_file,service_file, andsecretsexist before running setup or deploy.