PyPaaS is a lightweight, developer‑friendly Platform‑as‑a‑Service engine that automates deployments from Git repositories. It builds Docker images, deploys containers, updates Nginx routing, and includes a self‑healing daemon to restart unhealthy apps. Inspired by Heroku and Kubernetes, PyPaaS brings Git‑Ops workflows, observability, and developer experience — without the complexity.
Perfect for:
- 🚀 Local development PaaS environments
- 🏠 Self‑hosted mini‑cloud deployments
- 📚 DevOps learning and experimentation
- 🔧 Deployment automation demonstrations
- 👥 Small team collaboration on shared infrastructure
📌 Current Status: Local-only deployment. AWS cloud deployment support is planned for future releases.
- ✅ Automated Git Deployments – Webhook‑driven builds and deploys from GitHub/GitLab
- ✅ Zero‑Downtime Routing – Nginx reverse proxy with atomic config swaps
- ✅ Self‑Healing Engine – Background daemon detects and restarts unhealthy containers
- ✅ Observability – Prometheus metrics for deployments, restarts, and active apps
- ✅ Interactive Dashboard – Web UI for app management and monitoring
- ✅ RESTful API – Full-featured API with OpenAPI/Swagger documentation
- ✅ Security First – API key authentication, HMAC webhook verification, rate limiting
- ✅ Extensible Configuration –
.env‑based setup with sensible defaults - ✅ Comprehensive Testing – 80%+ code coverage with unit and integration tests
- ✅ CI/CD Ready – GitHub Actions pipeline with linting, testing, and security scans
PyPaaS runs as a FastAPI service (default port 8080) backed by PostgreSQL and Nginx.
┌─────────────────────────────────────────────────────────────────┐
│ Git Webhook Event │
│ (GitHub/GitLab Push) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ FastAPI Server (:8080) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ • Webhook Handler (HMAC verification) │ │
│ │ • API Endpoints (Deploy, Status, Logs) │ │
│ │ • Dashboard UI │ │
│ │ • Prometheus Metrics │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Background Deployment Pipeline │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 1. Git Manager: Clone/Update Repository │ │
│ │ 2. Container Engine: Build Docker Image │ │
│ │ 3. Deploy: Run Container with Port Mapping │ │
│ │ 4. Proxy Manager: Update Nginx Configuration │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Running Containers │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ • App 1 (Port 8001) │ │
│ │ • App 2 (Port 8002) │ │
│ │ • App N (Port 800N) │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Nginx Reverse Proxy (:80) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Routes traffic to running containers │ │
│ │ http://localhost/app1 → Container 1 │ │
│ │ http://localhost/app2 → Container 2 │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Healer Daemon (Background) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ • Periodic Health Checks (every 30s) │ │
│ │ • Detect Unhealthy Containers │ │
│ │ • Automatic Restart/Recovery │ │
│ │ • Metrics Export │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Component | Technology |
|---|---|
| Backend | Python 3.12, FastAPI, Uvicorn |
| Database | PostgreSQL 15 (Dockerized) |
| Container Runtime | Docker Engine, Docker SDK |
| Reverse Proxy | Nginx |
| Observability | Prometheus, Loguru |
| Version Control | GitPython |
| Testing | Pytest, pytest-asyncio, pytest-cov |
| Code Quality | Black, isort, flake8, mypy, bandit |
| Containerization | Docker, Docker Compose |
- Docker Engine (20.10+) – Install Docker
- Docker Compose (2.0+) – Install Docker Compose
- Git – Install Git
- Python 3.12+ (optional, for local development) – Install Python
git clone https://github.com/AlinaSHforwork/git-deploy-healer.git
cd git-deploy-healercp .env.example .envEdit .env with your configuration:
# .env
DEPLOYMENT_MODE=local
APP_PORT=8080
# Database
POSTGRES_USER=pypaas_user
POSTGRES_PASSWORD=secure_password_here
POSTGRES_DB=pypaas
POSTGRES_HOST=db
POSTGRES_PORT=5432
DATABASE_URL=postgresql://pypaas_user:secure_password_here@db:5432/pypaas
# Security (Generate with: python -c "import secrets; print(secrets.token_urlsafe(32))")
API_KEY=your-secret-api-key-here
GITHUB_WEBHOOK_SECRET=your-webhook-secret-here
# Logging
LOG_LEVEL=INFO
# Self-Healing
ENABLE_HEALER=true
HEALER_INTERVAL=30docker-compose up --buildThis will start:
- FastAPI Server – http://localhost:8080
- PostgreSQL Database – localhost:5432
- Nginx Reverse Proxy – http://localhost:80
- Prometheus Metrics – http://localhost:8080/metrics
Open your browser and navigate to:
- Dashboard: http://localhost:8080/dashboard
- API Docs: http://localhost:8080/docs
- Metrics: http://localhost:8080/metrics
The monitoring stack (Prometheus + Grafana) starts automatically with the main stack:
- Prometheus UI: http://localhost:9090
- Grafana Dashboard: http://localhost:3000 (login:
admin/ password:admin)
curl -X POST "http://localhost:8080/api/deploy" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-secret-api-key-here" \
-d '{
"repo_url": "https://github.com/your-username/your-app.git",
"app_name": "my-app",
"branch": "main"
}'- Navigate to http://localhost:8080/dashboard
- Click "Deploy New App"
- Enter repository URL, app name, and branch
- Click "Deploy"
python main.py my-app /path/to/dockerfile/directory| Variable | Default | Description |
|---|---|---|
DEPLOYMENT_MODE |
local |
Deployment environment (local only) |
APP_PORT |
8080 |
FastAPI server port |
DATABASE_URL |
- | PostgreSQL connection string |
API_KEY |
- | API authentication key |
GITHUB_WEBHOOK_SECRET |
- | GitHub webhook secret |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, WARNING, ERROR) |
ENABLE_HEALER |
true |
Enable self-healing daemon |
HEALER_INTERVAL |
30 |
Health check interval (seconds) |
WEBHOOK_RATE_LIMIT |
10 |
Webhook rate limit (requests/minute) |
HEALTH_CHECK_TIMEOUT |
30 |
Container health check timeout (seconds) |
See .env.example for complete configuration options.
# Inside Docker
docker-compose exec app pytest tests/ -v
# Locally (with venv)
pip install -r requirements.txt
pytest tests/ -v# Unit tests only
pytest tests/unit/ -v
# Integration tests (requires RUN_INTEGRATION=1)
RUN_INTEGRATION=1 pytest tests/integration/ -v
# With coverage report
pytest tests/ --cov=core --cov=api --cov-report=htmlCurrent coverage: 80%+
View detailed coverage report:
open htmlcov/index.htmlAll API requests require the X-API-Key header:
curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/api/...POST /api/deploy
Content-Type: application/json
X-API-Key: your-secret-api-key-here
{
"repo_url": "https://github.com/user/repo.git",
"app_name": "my-app",
"branch": "main"
}Response:
{
"status": "success",
"app_name": "my-app",
"container_id": "abc123...",
"port": 8001,
"url": "http://localhost:8001"
}GET /api/apps/{app_name}
X-API-Key: your-secret-api-key-hereGET /api/apps
X-API-Key: your-secret-api-key-hereGET /api/apps/{app_name}/logs
X-API-Key: your-secret-api-key-hereGET /healthFor complete API documentation, visit: http://localhost:8080/docs
PyPaaS includes a built-in monitoring stack with Prometheus and Grafana that starts automatically with the main docker-compose.
┌──────────────────────────────────────────────────────────────┐
│ PyPaaS App (:8080) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ • Prometheus Metrics Endpoint (/metrics) │ │
│ │ • Deployment Counter │ │
│ │ • Active Containers Gauge │ │
│ │ • Container Restart Counter │ │
│ └────────────────────────────────────────────────────────┘ │
└────────────────┬─────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Prometheus (:9090) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ • Scrapes metrics every 5 seconds │ │
│ │ • Stores time-series data │ │
│ │ • Evaluates alert rules │ │
│ │ • Provides query API │ │
│ └────────────────────────────────────────────────────────┘ │
└────────────────┬─────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Grafana (:3000) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ • Auto-provisioned Prometheus datasource │ │
│ │ • PyPaaS Overview Dashboard │ │
│ │ • Alert visualization │ │
│ │ • Custom dashboard creation │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Once the stack is running:
-
Prometheus UI – http://localhost:9090
- Query metrics:
up{job="pypaas-app"} - View scrape targets: Status → Targets
- Check alert rules: Alerts
- Query metrics:
-
Grafana Dashboard – http://localhost:3000
- Login:
admin/admin - Pre-configured PyPaaS Overview dashboard
- Create custom dashboards
- Login:
| Metric | Type | Description |
|---|---|---|
up{job="pypaas-app"} |
Gauge | App availability (1=up, 0=down) |
deployment_counter_total |
Counter | Total deployments |
active_containers_gauge |
Gauge | Currently running containers |
container_restarts_total |
Counter | Total container restarts |
http_requests_total |
Counter | HTTP requests by status |
PyPaaS includes three pre-configured alert rules:
- Condition: App metrics endpoint unreachable for >1 minute
- Action: Immediate notification
- Query:
up{job="pypaas-app"} == 0
- Condition: Error rate >5% for >5 minutes
- Action: Warning notification
- Query:
rate(http_requests_total{status=~"5.."}[5m]) > 0.05
- Condition: Restart rate >0.1/min for >5 minutes
- Action: Warning notification
- Query:
rate(container_restarts_total[15m]) > 0.1
In api/server.py:
from prometheus_client import Counter, Gauge
# Define custom metric
custom_counter = Counter('custom_metric_total', 'Description')
# Use in your code
custom_counter.inc()Edit monitoring/alerts.yml:
groups:
- name: custom-alerts
interval: 30s
rules:
- alert: CustomAlert
expr: your_metric > threshold
for: 5m
labels:
severity: warning
annotations:
summary: "Alert summary"
description: "Alert description"Reload Prometheus:
curl -X POST http://localhost:9090/-/reload- Open Grafana: http://localhost:3000
- Click + → Dashboard
- Add panels with PromQL queries
- Save dashboard
Example queries:
# App uptime percentage
(1 - (rate(up{job="pypaas-app"}[5m]))) * 100
# Deployment rate
rate(deployment_counter_total[5m])
# Container count over time
active_containers_gauge
monitoring/
├── prometheus.yml # Prometheus config (scrape targets, rules)
├── alerts.yml # Alert rules
├── grafana-datasources.yml # Auto-provision Prometheus datasource
├── grafana-dashboards.yml # Auto-provision dashboard loader
└── pypaas-dashboard.json # Pre-built PyPaaS dashboard
# Check Prometheus targets
curl http://localhost:9090/api/v1/targets
# Verify app is exposing metrics
curl http://localhost:8080/metrics
# Check Prometheus logs
docker-compose logs prometheus# Verify Prometheus is running
docker-compose ps prometheus
# Check Grafana logs
docker-compose logs grafana
# Manually add datasource:
# 1. Grafana → Configuration → Data Sources
# 2. Add Prometheus: http://prometheus:9090# Check alert rules are loaded
curl http://localhost:9090/api/v1/rules
# Verify metric exists
curl 'http://localhost:9090/api/v1/query?query=up{job="pypaas-app"}'
# Check alert evaluation
docker-compose logs prometheus | grep -i alert- Go to your repository settings
- Navigate to Webhooks → Add webhook
- Configure:
- Payload URL:
http://your-domain:8080/webhook - Content type:
application/json - Secret: Use the value from
GITHUB_WEBHOOK_SECRETin.env - Events: Select "Push events"
- Payload URL:
- Click Add webhook
When you push to your repository, GitHub will send:
{
"ref": "refs/heads/main",
"repository": {
"url": "https://github.com/user/repo.git",
"name": "repo"
},
"pusher": {
"name": "username"
}
}PyPaaS will automatically:
- Verify the HMAC signature
- Extract repository URL and branch
- Trigger deployment
- Update Nginx routing
Error: psycopg2.OperationalError: could not connect to server
Solution:
# Check if db container is running
docker-compose ps
# Restart database
docker-compose restart db
# Verify DATABASE_URL in .env matches container configError: docker.errors.BuildError: ...
Solution:
# Check if target repository has valid Dockerfile
# Verify repository is accessible
# Check Docker daemon is running
docker ps
# View build logs
docker-compose logs appError: Unauthorized or Forbidden
Solution:
# Verify API_KEY in .env
# Verify X-API-Key header in request
# Check GITHUB_WEBHOOK_SECRET matches GitHub webhook configurationError: nginx: [emerg] ...
Solution:
# Check Nginx logs
docker-compose logs app | grep nginx
# Verify Nginx config syntax
docker-compose exec app nginx -t
# Restart Nginx
docker-compose exec app nginx -s reloadError: bind: address already in use
Solution:
# Change APP_PORT in .env
APP_PORT=8081
# Or kill process using the port
lsof -i :8080
kill -9 <PID># Create virtual environment
python3.12 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Install pre-commit hooks
pre-commit install
# Run tests
pytest tests/ -v
# Start development server
uvicorn api.server:app --reload --host 0.0.0.0 --port 8080# Format code
black .
isort .
# Lint
flake8 .
# Type checking
mypy core/ api/
# Security scan
bandit -r core/ api/
# All checks
pre-commit run --all-filesgit-deploy-healer/
├── api/ # FastAPI application
│ ├── auth.py # Authentication & rate limiting
│ ├── server.py # Main server & endpoints
│ ├── routes/
│ │ ├── webhook.py # GitHub webhook handler
│ │ └── management.py # App management endpoints
│ └── schemas.py # Pydantic models
├── core/ # Core business logic
│ ├── engine.py # Docker container management
│ ├── git_manager.py # Git operations
│ ├── healer.py # Self-healing daemon
| ├── proxy_manager.py # Nginx configuration
│ ├── network.py # Port management
│ ├── models.py # SQLAlchemy ORM models
│ ├── security.py # Security validation
│ └── secrets_manager.py # Secret management
├── tests/ # Test suite
│ ├── unit/ # Unit tests (88 tests)
│ ├── integration/ # Integration tests (34 tests)
│ └── conftest.py # Pytest configuration
├── templates/ # HTML templates
│ ├── dashboard.html # Web dashboard
│ └── app.conf.j2 # Nginx config template
├── config/ # Configuration files
│ └── local.yaml # Local environment config
├── docker-compose.yml # Docker Compose setup
├── Dockerfile # Container image
├── requirements.txt # Python dependencies
├── main.py # CLI entry point
└── README.md # This file
-
Docker Socket Access
- PyPaaS requires access to
/var/run/docker.sockto manage containers - This grants elevated privileges – only run on trusted systems
- Consider using rootless Docker for additional security
- PyPaaS requires access to
-
API Key Management
- Generate strong API keys:
python -c "import secrets; print(secrets.token_urlsafe(32))" - Never commit
.envfiles to version control - Rotate keys regularly in production
- Generate strong API keys:
-
Webhook Verification
- All webhooks are verified using HMAC-SHA256
- Ensure
GITHUB_WEBHOOK_SECRETis strong and kept secret
-
Database Security
- Use strong PostgreSQL passwords
- Consider using environment-specific credentials
- Enable SSL for database connections in production
-
Rate Limiting
- API endpoints are rate-limited to prevent abuse
- Webhook endpoints have per-IP rate limiting
- Configure limits via environment variables
-
Use smaller base images
FROM python:3.12-slim # Instead of python:3.12 -
Leverage Docker layer caching
COPY requirements.txt . RUN pip install -r requirements.txt COPY . .
-
Minimize image size
RUN pip install --no-cache-dir -r requirements.txt
# View metrics
curl http://localhost:8080/metrics
# Check container resource usage
docker stats
# View application logs
docker-compose logs -f app⚠️ Single-instance only – No horizontal scaling support yet⚠️ Local deployments only – AWS/cloud deployment planned for future⚠️ Sequential deployments – Builds run one at a time⚠️ No persistent volumes – Container data is lost on restart⚠️ Limited to 1000 apps – Port range 8000-9000
- Horizontal scaling with Redis
- AWS ECS/Fargate support
- Blue-green deployments
- Canary releases
- Multi-tenancy support
- Plugin system for extensibility
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please ensure:
- Tests pass:
pytest tests/ -v - Code is formatted:
black . && isort . - No linting errors:
flake8 . - Type hints are correct:
mypy core/ api/
MIT License – see LICENSE file for details.
- Inspired by Heroku, Kubernetes, and Dokku
- Built with FastAPI, Docker, and PostgreSQL
- Community contributions and feedback
Made with ❤️ by Alina Shvyryd