Deployment
Deploy ezAuth to production on a VPS with Caddy, PostgreSQL, and Redis.
Requirements
- A Linux VPS (Debian/Ubuntu recommended)
- Python 3.11+
- PostgreSQL 16+
- Redis 7+
- A domain name with DNS configured
Stack
| Component | Role |
|---|---|
| Caddy | Reverse proxy with automatic TLS (Let's Encrypt) |
| Uvicorn | ASGI application server |
| PostgreSQL | Primary database |
| Redis | Caching, rate limiting, session state |
| systemd | Process management |
1. Install Dependencies
# PostgreSQL
sudo apt install postgresql
# Redis
sudo apt install redis
# Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy.gpg
echo "deb [signed-by=/usr/share/keyrings/caddy.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main" | sudo tee /etc/apt/sources.list.d/caddy.list
sudo apt update && sudo apt install caddy
2. Set Up the Database
sudo -u postgres createuser ezauth
sudo -u postgres createdb ezauth -O ezauth
sudo -u postgres psql -c "ALTER USER ezauth PASSWORD 'your-secure-password';"
3. Deploy the Application
# Copy files to the server
rsync -avz --exclude .git --exclude __pycache__ ./ user@server:/opt/ezauth/
# On the server: install Python dependencies
cd /opt/ezauth
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
# Run migrations
alembic upgrade head
4. Configure Environment
Create /opt/ezauth/.env with your production settings:
DATABASE_URL=postgresql+asyncpg://ezauth:password@localhost:5432/ezauth
REDIS_URL=redis://localhost:6379/0
SES_REGION=us-east-1
[email protected]
[email protected]
SESSION_COOKIE_SECURE=true
5. Configure Caddy
Edit /etc/caddy/Caddyfile:
# Global options: on-demand TLS for customer custom domains
{
on_demand_tls {
ask http://127.0.0.1:8001/internal/domain-check
}
}
# Primary API domain
api.ezauth.org {
reverse_proxy 127.0.0.1:8001
}
# Catch-all for customer custom domains (CNAME → api.ezauth.org)
https:// {
tls {
on_demand
}
reverse_proxy 127.0.0.1:8001
}
When a customer sets a CNAME from their domain (e.g. auth.customer.com) to api.ezauth.org,
Caddy will automatically provision a TLS certificate for it via Let's Encrypt. The ask endpoint
ensures certificates are only issued for verified domains in the database.
sudo systemctl reload caddy
6. Create systemd Service
Create /etc/systemd/system/ezauth.service:
[Unit]
Description=EZAuth
After=network.target postgresql.service redis.service
[Service]
Type=simple
User=ezauth
WorkingDirectory=/opt/ezauth
EnvironmentFile=/opt/ezauth/.env
ExecStart=/opt/ezauth/.venv/bin/uvicorn ezauth.main:app --host 127.0.0.1 --port 8001
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable ezauth
sudo systemctl start ezauth
7. Verify
# Check the service is running
sudo systemctl status ezauth
# Check the API responds
curl https://auth.yourdomain.com/docs
Updating
# Sync new code
rsync -avz --exclude .git --exclude __pycache__ ./ user@server:/opt/ezauth/
# On the server
cd /opt/ezauth
source .venv/bin/activate
pip install -e .
alembic upgrade head
sudo systemctl restart ezauth