Metadata-Version: 2.3
Name: aayi
Version: 0.2.0
Summary: Deploy Docker apps to any server with zero downtime and automatic HTTPS
Author: Ahmed
Author-email: Ahmed <thlurte@gmail.com>
Requires-Dist: asyncssh>=2.14.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: pydantic>=2.7.0
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: rich>=13.7.0
Requires-Dist: typer>=0.12.0
Requires-Python: >=3.13
Description-Content-Type: text/markdown

<p align="center">
  <img src="assets/banner.jpeg" alt="Aayi - Modern Cloud Deployment Dev Tool" width="100%">
</p>

<h1 align="center">Aayi</h1>

<p align="center">
  <strong>Deploy Docker apps to any server with zero downtime and automatic HTTPS.</strong>
</p>

<p align="center">
  <a href="https://pypi.org/project/aayi/"><img src="https://img.shields.io/pypi/v/aayi.svg?color=blue&style=flat-square" alt="PyPI version"></a>
  <a href="https://pypi.org/project/aayi/"><img src="https://img.shields.io/pypi/pyversions/aayi.svg?style=flat-square" alt="Python Versions"></a>
  <a href="https://github.com/thlurte/aayi/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/thlurte/aayi/ci.yml?branch=main&label=CI&style=flat-square" alt="CI Status"></a>
  <a href="https://github.com/thlurte/aayi/releases"><img src="https://img.shields.io/github/v/release/thlurte/aayi?style=flat-square&color=success" alt="GitHub Release"></a>
  <a href="https://github.com/thlurte/aayi/stargazers"><img src="https://img.shields.io/github/stars/thlurte/aayi?style=flat-square&logo=github" alt="GitHub stars"></a>
  <a href="https://github.com/thlurte/aayi/blob/main/LICENSE"><img src="https://img.shields.io/github/license/thlurte/aayi.svg?style=flat-square" alt="License: MIT"></a>
</p>

<p align="center">
  <a href="#quickstart">Quickstart</a> &bull;
  <a href="#features">Features</a> &bull;
  <a href="#why-aayi-vs-kamal">Why Aayi vs. Kamal?</a> &bull;
  <a href="#command-reference">Commands</a> &bull;
  <a href="#architecture">Architecture</a>
</p>

---

## Features

- **Zero-Downtime Container Swaps**: Seamlessly switches traffic between revisions via Caddy's dynamic in-memory Admin API (`:2019`) with active health checks.
- **Automatic HTTPS**: TLS certificates via Let's Encrypt / ZeroSSL managed automatically by Caddy without external cert-bot scripts.
- **Docker Compose & Multi-Container**: Deploy multi-service setups directly from `docker-compose.yml` or multi-service `deploy.yml`.
- **Public vs. Private Containers**:
  - **Public**: Dedicated subdomains per service (`app.example.com`, `api.example.com`) with automatic TLS.
  - **Private**: Background workers, redis, databases on isolated internal network `aayi-net` with zero exposed host ports.
- **Concurrent SSH Execution**: Asynchronous, parallel multi-server deployment fleet powered by AsyncSSH.
- **Type-Safe Declarative Config**: Strict validation of `config/deploy.yml` with friendly Pydantic error diagnostics and `${ENV_VAR:-default}` substitution.
- **Remote Builds Without Registry**: Build directly on remote servers using in-memory tar stream (`--remote-build`) without needing Docker Hub or AWS ECR.
- **Instant Rollback**: Revert traffic to previous healthy container in milliseconds with `aayi rollback`.
- **Stateful Accessories**: Spin up databases (PostgreSQL, MySQL, Redis) with persistent Docker volumes and loopback host protection.

---

## Why Aayi vs. Kamal?

| Feature | Kamal | Aayi |
| :--- | :--- | :--- |
| **Runtime & Dependencies** | Ruby & Bundler | Python 3.13+ or standalone binary (0 dependencies) |
| **Reverse Proxy** | Traefik / Kamal Proxy | **Caddy** (In-memory API reload, zero drop connections, automatic TLS) |
| **Multi-Service / Compose** | Separate configs / accessories | **First-class multi-service** & `docker-compose.yml` conversion |
| **Ephemeral Remote Build** | Requires Docker Registry | **Optional `--remote-build`** (streams code archive directly over SSH) |
| **Target Fleet Concurrency** | SSHKit threads | **AsyncSSH** event loop (lightweight, non-blocking) |
| **Configuration Engine** | ERB YAML templates | **Pydantic v2 Models** with strict schema checks |

---

## Architecture

```
                                 [ CLI: aayi ]
                               (Typer + Rich UI)
                                       │
                              [ Config: deploy.yml ]
                               (Pydantic v2 Models)
                                       │
                      ┌────────────────┴────────────────┐
                      ▼                                 ▼
             [ Local Builder ]                 [ AsyncSSH Fleet ]
           (docker buildx push)             (Parallel Multi-Server Pool)
                                                        │
                              ┌─────────────────────────┴─────────────────────────┐
                              ▼                                                   ▼
                       [ Web Server(s) ]                                   [ Worker Server(s) ]
                     ┌───────────────────┐                               ┌────────────────────┐
                     │ Caddy (Port 80/443│                               │ Worker Container   │
                     │  Admin API :2019) │                               └────────────────────┘
                     └─────────┬─────────┘
                               │ (Dynamic Route)
                     ┌─────────┴─────────┐
                     │ App Container     │
                     │ (Port: 8000/8001) │
                     └───────────────────┘
```

---

## Quickstart

### 1. Installation

**One-line standalone installer (Zero dependencies, no Python or pip needed):**
```bash
curl -fsSL https://raw.githubusercontent.com/thlurte/aayi/main/install.sh | bash
```

**Or run instantly with uvx (no installation required):**
```bash
uvx aayi --help
```

**Or install via uv tool or pip:**
```bash
uv tool install aayi
# or
pip install aayi
```

### 2. Initialize Your Project

Generate starter `config/deploy.yml` and an optimized multi-stage `Dockerfile`:
```bash
aayi init
```

### 3. Configure `config/deploy.yml`

```yaml
service: myapp
image: your-docker-user/myapp

servers:
  web:
    - 192.168.1.10
  workers:
    - 192.168.1.11
  user: ubuntu          # Default SSH user (e.g. root, ubuntu, ec2-user, debian)
  ssh_port: 22          # Optional: custom SSH port
  
  # Option A: SSH Key / AWS .pem file
  ssh_key: ~/.ssh/my-server-key.pem

  # Option B: SSH Password (supports env var substitution)
  # ssh_password: ${SSH_PASSWORD}

  # Option C: Passphrase (if your private key is encrypted)
  # passphrase: ${SSH_KEY_PASSPHRASE}

registry:
  server: docker.io
  username: your-docker-user
  password: ${DOCKER_REGISTRY_PASSWORD}

# Global proxy config (for single-container apps)
proxy:
  domain: app.example.com
  app_port: 8000
  healthcheck_path: /healthz
  drain_timeout: 10
  tls: true
  email: admin@example.com

env:
  clear:
    PORT: "8000"
    ENVIRONMENT: production
  secret:
    - SECRET_KEY
    - DATABASE_URL
```

#### Or Multi-Service Configuration (Define Public vs. Private in Config)

You can define multiple services in `config/deploy.yml`, specifying exactly which ones are **public** with their own domain/subdomain, and which ones are **private**:

```yaml
services:
  # Public web frontend with its own subdomain & automatic HTTPS
  web:
    image: your-docker-user/myweb
    public: true
    domain: app.example.com
    app_port: 3000
    roles: [web]

  # Public API microservice with a separate subdomain
  api:
    image: your-docker-user/myapi
    public: true
    domain: api.example.com
    app_port: 8000
    roles: [web]

  # Private background worker (no domain, zero open ports, internal aayi-net only)
  worker:
    image: your-docker-user/myworker
    public: false
    command: python -m worker
    roles: [workers]
    depends_on: [api]
```

### 4. Setup Target Servers

Ensures official Docker CE and Caddy are running on all target hosts:
```bash
aayi setup
```

### 5. Deploy with Zero Downtime

Builds the image with `docker buildx`, pushes to your registry, boots a new container, runs health checks, and smoothly switches Caddy upstream traffic:
```bash
aayi deploy
```

---

## Advanced Workflows

### 1. Docker Compose Integration

If your application is already defined in a `docker-compose.yml`, Aayi can parse and convert it directly into a zero-downtime, multi-service deployment setup:

```bash
# Convert docker-compose.yml into config/deploy.yml
aayi compose convert --output config/deploy.yml
```

Or deploy directly from compose without generating files:
```bash
aayi deploy --compose docker-compose.yml
```

- **Public Web Services**: Services with exposed ports (e.g. `80:8000`) get automatic Caddy routes, domains, and HTTPS certificates.
- **Private Microservices & Workers**: Services without host ports (e.g., Celery, Redis, background jobs) are isolated on the secure `aayi-net` bridge network so they communicate internally with zero external exposure.
- **Dependencies (`depends_on`)**: Preserves startup order so databases/caches boot before dependent web servers.

### 2. Override Domain and Public/Private Visibility from CLI

You can override any container's public domain or switch it between public and private directly when deploying from the terminal:

```bash
# Expose container on a specific subdomain with automatic TLS:
aayi deploy --domain api.example.com --public

# Deploy a specific microservice with its own subdomain:
aayi deploy --service analytics --domain stats.example.com --public

# Force a container to be completely private (isolated to internal network):
aayi deploy --service worker --private
```

### 3. Registry Options: Cloud, Local/Self-Hosted, or Registry-Free

Aayi supports three flexible registry modes:

#### Cloud Registries (Docker Hub, GitHub GHCR, AWS ECR, GCP Artifact Registry)
```yaml
registry:
  server: ghcr.io  # or docker.io, 123456789.dkr.ecr.us-east-1.amazonaws.com
  username: your-username
  password: ${REGISTRY_TOKEN}
```

#### Self-Hosted & Local Private Registries (`registry:2` on LAN or VPN)
If you run a local Docker registry inside your private network or on a local server (e.g. `192.168.1.50:5000` or `registry.internal:5000`):
```yaml
image: registry.internal:5000/myapp
registry:
  server: registry.internal:5000
  # Username/password can be omitted if your internal registry requires no auth:
  username: null
  password: null
```

#### Zero-Registry Mode (Ephemeral Remote Build)
Don't want to run or pay for any container registry? Deploy code directly over SSH:
```bash
aayi deploy --remote-build
```
Aayi packages your code directory into an in-memory tar stream, pipes it across the AsyncSSH tunnel directly to the target server's Docker daemon, and builds it on-server without ever uploading an image to the internet.

---

## Command Reference

| Command | Description |
| :--- | :--- |
| `aayi init` | Scaffolds `config/deploy.yml`, `Dockerfile`, and `.dockerignore`. |
| `aayi setup` | Installs Docker CE (if missing) and boots Caddy reverse proxy on all hosts. |
| `aayi deploy` | Full zero-downtime deployment (build, push, boot, healthcheck, swap Caddy traffic). |
| `aayi redeploy` | Redeploy an existing image tag on remote servers without rebuilding locally. |
| `aayi rollback` | Atomically revert Caddy upstream to the previous healthy container. |
| `aayi logs` | Real-time multi-host unified log streaming with colored host labels. |
| `aayi exec <cmd>` | Execute an ad-hoc command or interactive shell inside running container. |
| `aayi proxy status` | Inspect current live Caddy routing state and upstreams. |
| `aayi proxy reload` | Force Caddy to route traffic to a specific container port. |
| `aayi accessory boot <name>` | Start an accessory (e.g. Postgres, Redis) with persistent volumes. |
| `aayi accessory stop <name>` | Stop an accessory container. |
| `aayi accessory logs <name>` | View or follow logs for an accessory container. |
| `aayi compose convert` | Convert an existing `docker-compose.yml` to native `config/deploy.yml`. |
| `aayi ci init` | Generates `.github/workflows/deploy.yml` for automated GitHub Actions CI/CD. |
| `aayi version` | Display current installed version of Aayi. |

---

## Contributing & Development

```bash
# Clone the repository
git clone https://github.com/thlurte/aayi.git
cd aayi

# Sync virtual environment & dependencies
uv sync

# Run tests
uv run pytest -v
```

---

## License

MIT
