Skip to main content

Modular Django deployment system based on pyinfra

Project description

djaploy

PyPI Version Python Versions License Last Commit

A modular Django deployment system based on pyinfra, designed to standardize and simplify infrastructure management across Django projects.

Features

  • Modular Architecture — Extensible plugin system for deployment components
  • Django Integration — Seamless integration via Django management commands
  • Multiple Deployment Modes — Support for --local, --latest, and --release deployments
  • Infrastructure as Code — Define infrastructure using Python with pyinfra
  • Git-based Artifacts — Automated artifact creation from git repository
  • SSL Management — Built-in support for SSL certificates and Let's Encrypt
  • Python Compilation — Optionally compile Python from source for specific versions

Installation

pip install djaploy

Or with Poetry:

poetry add djaploy

Optional extras

pip install djaploy[certificates]   # Let's Encrypt / certbot support
pip install djaploy[bunny]          # Bunny DNS certbot plugin

Quick Start

1. Add to Django settings

INSTALLED_APPS = [
    # ...
    "djaploy",
]

# Required paths
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_DIR = BASE_DIR
GIT_DIR = PROJECT_DIR.parent
DJAPLOY_CONFIG_DIR = PROJECT_DIR / "infra"

2. Create project structure

your-django-project/
├── manage.py
├── your_app/
│   └── settings.py
└── infra/                          # Deployment configuration
    ├── config.py                   # Main configuration
    ├── inventory/                  # Host definitions per environment
    │   ├── production.py
    │   └── staging.py
    └── deploy_files/               # Environment-specific files
        ├── production/
        │   └── etc/systemd/system/app.service
        └── staging/

3. Configure deployment

infra/config.py:

from djaploy.config import DjaployConfig
from pathlib import Path

config = DjaployConfig(
    project_name="myapp",
    djaploy_dir=Path(__file__).parent,
    manage_py_path=Path("manage.py"),

    python_version="3.11",
    app_user="app",
    ssh_user="deploy",

    modules=[
        "djaploy.modules.core",
        "djaploy.modules.nginx",
        "djaploy.modules.systemd",
    ],

    services=["myapp", "myapp-worker"],
)

4. Define inventory

infra/inventory/production.py:

from djaploy.config import HostConfig

hosts = [
    HostConfig(
        name="web-1",
        ssh_host="192.168.1.100",
        ssh_user="deploy",
        app_user="app",
        env="production",
        services=["myapp", "myapp-worker"],
    ),
]

5. Deploy files

Place environment-specific configuration files in deploy_files/ — these are copied to the server during deployment:

# deploy_files/production/etc/systemd/system/myapp.service
[Unit]
Description=My Django App
After=network.target

[Service]
Type=simple
User=app
WorkingDirectory=/home/app/apps/myapp
ExecStart=/home/app/.local/bin/poetry run gunicorn config.wsgi
Restart=on-failure

[Install]
WantedBy=multi-user.target

Usage

Configure a server

python manage.py configureserver --env production

Sets up the application user, installs Python and Poetry, and prepares the directory structure.

Deploy

# Deploy local changes (development)
python manage.py deploy --env production --local

# Deploy latest git commit
python manage.py deploy --env production --latest

# Deploy a specific release
python manage.py deploy --env production --release v1.0.0

Deployment flow:

  1. Creates a tar.gz artifact from git
  2. Uploads to servers
  3. Extracts application code
  4. Copies environment-specific deploy files (nginx, systemd, etc.)
  5. Installs dependencies via Poetry
  6. Runs migrations
  7. Collects static files
  8. Restarts services

Certificate management

python manage.py update_certs           # Update certificate definitions
python manage.py sync_certs --env production  # Sync certificates

Verify configuration

python manage.py verify --verbose

Modules

djaploy uses a modular architecture — each component is a separate module that can be enabled or disabled per project.

Built-in modules

Module Description
djaploy.modules.core Core setup: users, Python, Poetry, artifact deployment, migrations
djaploy.modules.nginx Nginx web server configuration
djaploy.modules.systemd Systemd service management
djaploy.modules.sync_certs SSL certificate syncing
djaploy.modules.cert_renewal Certificate renewal automation
djaploy.modules.litestream Litestream database replication
djaploy.modules.rclone Rclone-based backups
djaploy.modules.tailscale Tailscale networking

Custom modules

Extend BaseModule to create project-specific deployment logic:

from djaploy.modules.base import BaseModule

class MyModule(BaseModule):
    def configure_server(self, host):
        # Server configuration logic
        pass

    def deploy(self, host, artifact_path):
        # Deployment logic
        pass

Add it to your config:

config = DjaployConfig(
    modules=[
        "djaploy.modules.core",
        "myproject.infra.modules.custom",
    ],
)

Project Customization

prepare.py

Projects can include a prepare.py file for local build steps that run before deployment:

# prepare.py
from djaploy.prepare import run_command

def prepare():
    run_command("npm run build")
    run_command("python manage.py collectstatic --noinput")

Custom deploy files

Projects can include environment-specific configuration files in a deploy_files/ directory that will be copied to the server during deployment. The directory structure mirrors the target filesystem layout (e.g. deploy_files/production/etc/nginx/sites-available/myapp gets copied to /etc/nginx/sites-available/myapp on the server).

Release Notifications & Versioning

djaploy includes built-in support for semantic versioning, changelog generation, and deployment notifications. When enabled, deployments automatically:

  • Calculate the next semantic version based on git tags
  • Generate a changelog from commit messages (simple or AI-powered)
  • Send notifications to Slack or custom webhooks
  • Create and push git tags after successful deployments
  • Deploy a VERSION file to the server

Enabling the feature

Add the versioning module to your config and configure notifications:

# infra/config.py
from djaploy.config import DjaployConfig

config = DjaployConfig(
    project_name="myapp",
    # ...

    modules=[
        "djaploy.modules.core",
        "djaploy.modules.nginx",
        "djaploy.modules.systemd",
        "djaploy.modules.versioning",  # Enable versioning
    ],

    module_configs={
        "versioning": {
            "tag_environments": ["production"],  # Create tags only for these envs
            "increment_type": "patch",           # Default: patch (v1.0.0 -> v1.0.1)
            "push_tags": True,                   # Push tags to remote
        },
        "notifications": {
            "display_name": "My App",            # Name shown in notifications
            "notify_environments": ["production", "staging"],
            "notify_on_failure": True,
            "changelog_generator": "llm",        # "simple" or "llm"
            "changelog_config": {
                "api_key": "op://vault/mistral/api-key",  # 1Password reference or plain key
                "model": "devstral-small-latest",
                "api_url": "https://api.mistral.ai/v1/chat/completions",
            },
            "backend_config": {
                "webhook_url": "op://vault/slack/webhook-url",
            },
        },
    },
)

Configuration options

Versioning (module_configs["versioning"])

Option Default Description
tag_environments ["production"] Environments that create git tags
increment_type "patch" Default version bump: major, minor, or patch
push_tags True Push created tags to remote
version_file_path "VERSION" Path for VERSION file on server

Notifications (module_configs["notifications"])

Option Default Description
display_name project_name Name shown in notification messages
notify_environments tag_environments Environments that send notifications
notify_on_failure True Send notification on deployment failure
changelog_generator "simple" Generator type: simple or llm
changelog_config {} Config passed to changelog generator
backend_config.webhook_url Slack webhook URL (required)

Changelog generators

Simple — Concatenates commit messages into a brief summary:

"changelog_generator": "simple"

LLM — Uses an AI model to generate natural language summaries:

"changelog_generator": "llm",
"changelog_config": {
    "api_key": "your-api-key",           # Required
    "api_url": "https://api.mistral.ai/v1/chat/completions",  # OpenAI-compatible
    "model": "devstral-small-latest",
}

Version bump override

Override the default increment type per deployment:

python manage.py deploy --env production --bump-major   # v1.0.0 -> v2.0.0
python manage.py deploy --env production --bump-minor   # v1.0.0 -> v1.1.0
python manage.py deploy --env production --bump-patch   # v1.0.0 -> v1.0.1 (default)

How it works

Deploy to dev (tag_environments: ["production"])
├─ Calculates version from commits since last tag
├─ Generates changelog
├─ Sends notification ✓
└─ Does NOT create tag (dev not in tag_environments)

Deploy to production
├─ Same version/changelog calculation
├─ Sends notification ✓
├─ Creates tag v1.0.5 and pushes to remote ✓
└─ Deploys VERSION file to server

When redeploying the same version (no new commits), the changelog is extracted from the existing git tag message to ensure consistent notifications across environments.

VERSION file

The versioning module deploys a VERSION file to the server containing:

VERSION=v1.0.5
COMMIT=abc1234
DEPLOYED_AT=2024-01-15T10:30:00Z
ENVIRONMENT=production

Development

git clone https://github.com/Technology-Company/djaploy.git
cd djaploy
poetry install

To use a local development copy in another project:

pip install -e /path/to/djaploy

License

MIT

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

djaploy-0.8.1.tar.gz (65.2 kB view details)

Uploaded Source

Built Distribution

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

djaploy-0.8.1-py3-none-any.whl (69.8 kB view details)

Uploaded Python 3

File details

Details for the file djaploy-0.8.1.tar.gz.

File metadata

  • Download URL: djaploy-0.8.1.tar.gz
  • Upload date:
  • Size: 65.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for djaploy-0.8.1.tar.gz
Algorithm Hash digest
SHA256 fba5f37f5dcb32f92ef60841dad6b72ea8e0e92565ba492ef3a59bdd7e7c4473
MD5 57ff2450386c2cd6033b9af156dc5737
BLAKE2b-256 c90f0ba051ed31aac707ddd397f4867e288b17f8264a1da3150e9696f8f5db1a

See more details on using hashes here.

File details

Details for the file djaploy-0.8.1-py3-none-any.whl.

File metadata

  • Download URL: djaploy-0.8.1-py3-none-any.whl
  • Upload date:
  • Size: 69.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for djaploy-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5692941ea37c4894a48bc8eae630653e88f7f3085dd4459d0b6f351931836e95
MD5 6874b417548beb5acb87f3cf6870fc8d
BLAKE2b-256 3bc6eb5233cff75baa0d4b04de73d876520f4a09716abf54301544ab4ae3687c

See more details on using hashes here.

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