Skip to main content

Deploy web applications to VPS using Docker Compose with automatic SSL

Project description

DockLift

Deploy web applications to VPS using Docker Compose with automatic SSL via Caddy.

Features

  • Simple Configuration: Lightweight YAML configuration for all deployment settings
  • Automatic SSL: Automatic HTTPS certificates via Caddy's ACME integration
  • Multi-App Support: Deploy multiple applications to the same VPS, each with its own domain
  • Auto Port Assignment: Automatically assigns ports to applications (starts at 3000, increments)
  • Idempotent Operations: All commands can be run multiple times safely
  • Dependency Management: Built-in support for databases, caches, and other services
  • Type-Safe: Full type hints throughout the codebase
  • Beautiful CLI: Rich terminal output with progress indicators

Installation

Using UV (recommended):

uv tool install docklift

Using pip:

pip install docklift

Quick Start

1. Initialize Configuration

Run the interactive setup:

docklift init

Or provide values as arguments to skip prompts:

docklift init myapp --domain myapp.example.com --host 192.168.1.100

This creates a docklift.yml file. The wizard will prompt for:

  • Application name and domain
  • VPS host and SSH credentials
  • Application port
  • Email for SSL certificate notifications (optional)

2. Bootstrap VPS

First time setup - installs Docker, Caddy, and creates shared infrastructure:

docklift bootstrap

This step is idempotent. It will:

  • Install Docker and Docker Compose (if not present)
  • Create a shared network for all applications
  • Set up Caddy reverse proxy with automatic HTTPS

3. Deploy Application

docklift deploy

This will:

  • Upload your application code
  • Generate docker-compose.yml
  • Build the Docker image on the VPS
  • Start the application
  • Configure Caddy to route traffic
  • Test the deployment

Configuration

Create a docklift.yml file:

vps:
  host: 192.168.1.100
  user: root
  ssh_key_path: ~/.ssh/id_rsa
  port: 22
  email: admin@example.com  # Optional: for Let's Encrypt SSL notifications

application:
  name: myapp
  domain: myapp.example.com
  dockerfile: ./Dockerfile
  context: .
  # port: 3000  # Optional: auto-assigned if not specified

  environment:
    NODE_ENV: production
    DATABASE_URL: postgres://postgres:password@postgres:5432/myapp
    REDIS_URL: redis://redis:6379

  dependencies:
    postgres:
      image: postgres:16-alpine
      environment:
        POSTGRES_DB: myapp
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: changeme
      volumes:
        - postgres_data:/var/lib/postgresql/data

    redis:
      image: redis:7-alpine
      volumes:
        - redis_data:/data

Commands

Initialize

Create a new configuration file interactively:

docklift init

Or provide arguments to skip prompts:

docklift init myapp --domain app.example.com --host 192.168.1.100 --user deploy

Bootstrap

Set up VPS infrastructure (run once per VPS):

docklift bootstrap [--config docklift.yml]

Deploy

Deploy or update an application:

docklift deploy [--config docklift.yml] [--skip-bootstrap]

Status

Check application status:

docklift status [--config docklift.yml]

Remove

Remove an application:

docklift remove [--config docklift.yml] [--remove-volumes]

Environment Variables and Secrets

DockLift supports loading environment variables from .env files to keep secrets out of version control.

Using .env Files

  1. Create a .env file in your project:
# .env
DATABASE_PASSWORD=super-secret-password
API_KEY=sk-1234567890
STRIPE_SECRET=sk_test_abc123
  1. Reference it in docklift.yml:
application:
  environment:
    NODE_ENV: production
    DATABASE_URL: postgres://user:${DATABASE_PASSWORD}@postgres:5432/db
  env_file: .env  # Load additional variables from .env
  1. Add .env to .gitignore:
echo ".env" >> .gitignore

Precedence Rules

  • Variables defined in docklift.yml take precedence over .env file
  • This allows you to override secrets for specific environments
  • Use YAML for non-sensitive config, .env for secrets

Example

With this setup:

# docklift.yml
environment:
  NODE_ENV: production
  API_KEY: override-key
env_file: .env
# .env
API_KEY=secret-from-env
DATABASE_URL=postgres://localhost/db

The result will be:

  • NODE_ENV=production (from YAML)
  • API_KEY=override-key (YAML overrides .env)
  • DATABASE_URL=postgres://localhost/db (from .env)

How It Works

Architecture

DockLift creates the following structure on your VPS:

/opt/docklift/
├── caddy-compose.yml        # Caddy reverse proxy
├── Caddyfile                # Caddy configuration
└── apps/
    ├── app1/
    │   ├── docker-compose.yml
    │   └── [app files]
    └── app2/
        ├── docker-compose.yml
        └── [app files]

Network Architecture

  • All applications and Caddy share a Docker network called docklift-network
  • Caddy listens on ports 80 and 443
  • Applications expose their internal ports only to the shared network
  • Caddy routes traffic based on domain name to the appropriate application

SSL Certificates

  • Caddy automatically obtains SSL certificates via Let's Encrypt
  • Certificates are automatically renewed
  • HTTP traffic is automatically redirected to HTTPS

Port Management

  • Applications can specify a port or leave it blank for auto-assignment
  • Auto-assigned ports start at 3000 and increment for each new application
  • Ports are only exposed internally to the Docker network (no host port conflicts)
  • When redeploying an existing app, the same port is reused

Example: Django Application

vps:
  host: myserver.example.com
  user: deploy
  ssh_key_path: ~/.ssh/deploy_key
  port: 22
  email: admin@myserver.example.com

application:
  name: django-app
  domain: app.example.com
  dockerfile: ./Dockerfile
  context: .
  port: 8000

  environment:
    DJANGO_SETTINGS_MODULE: myapp.settings.production
    DATABASE_URL: postgres://django:secure_pass@postgres:5432/django_db
    REDIS_URL: redis://redis:6379/0
    SECRET_KEY: your-secret-key-here

  dependencies:
    postgres:
      image: postgres:16-alpine
      environment:
        POSTGRES_DB: django_db
        POSTGRES_USER: django
        POSTGRES_PASSWORD: secure_pass
      volumes:
        - postgres_data:/var/lib/postgresql/data

    redis:
      image: redis:7-alpine
      volumes:
        - redis_data:/data

Example: Node.js Application

vps:
  host: myserver.example.com
  user: deploy
  ssh_key_path: ~/.ssh/deploy_key
  port: 22
  email: admin@myserver.example.com

application:
  name: nodejs-app
  domain: app.example.com
  dockerfile: ./Dockerfile
  context: .
  port: 3000

  environment:
    NODE_ENV: production
    MONGODB_URL: mongodb://mongo:27017/myapp

  dependencies:
    mongo:
      image: mongo:7
      volumes:
        - mongo_data:/data/db

Requirements

  • Python 3.12+
  • SSH access to a VPS running a modern Linux distribution
  • Docker-compatible VPS (Ubuntu 20.04+, Debian 11+, etc.)
  • Domain name(s) pointed to your VPS

Development

Built with:

  • Python 3.12+ with type hints
  • UV for package management
  • Fabric for SSH operations
  • Rich for beautiful CLI output
  • Pydantic for configuration validation
  • Click for CLI framework

Setup Development Environment

# Clone the repository
git clone https://github.com/amirkarimi/docklift.git
cd docklift

# Install dependencies
uv sync

# Run in development mode
uv run docklift --help

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docklift-0.1.0.tar.gz (60.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

docklift-0.1.0-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

Details for the file docklift-0.1.0.tar.gz.

File metadata

  • Download URL: docklift-0.1.0.tar.gz
  • Upload date:
  • Size: 60.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for docklift-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9dddf14cb25af121958e5226d99ee087147cbf520b51bbf1bfaf9a22c3ba9204
MD5 1ce90f7510aaf506c370f23b4a60b4a4
BLAKE2b-256 16f5d074a846c16fc163154370675c30d6c96cd5fab57f244a078ac037aa3758

See more details on using hashes here.

Provenance

The following attestation bundles were made for docklift-0.1.0.tar.gz:

Publisher: publish.yml on amirkarimi/docklift

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file docklift-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: docklift-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for docklift-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f66b8ca1613b2eca704b6b61e3421582a85fc3884172260117e49f918b472ef6
MD5 fbd741f53a8e7f06bcb5025fa1e122fc
BLAKE2b-256 08e1952a6c8e04cae7855a609b911d8e8e0698bfdb4c4cbeb6385661353ee732

See more details on using hashes here.

Provenance

The following attestation bundles were made for docklift-0.1.0-py3-none-any.whl:

Publisher: publish.yml on amirkarimi/docklift

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page