Heroku-style container deployments made simple.
Pvdify is a lightweight, self-hosted PaaS (Platform as a Service) that brings Heroku-style deployments to your own infrastructure. Deploy any Docker/OCI container with zero configuration, automatic HTTPS, and a clean web dashboard.
- Zero-Config Deployments - Deploy any container image with a single command
- Automatic HTTPS - Free SSL certificates via Let's Encrypt or Cloudflare
- Custom Domains - One-click Cloudflare DNS integration
- Config Vars - Secure environment variable management (12-factor style)
- Release Management - Version tracking with instant rollbacks
- Process Scaling - Scale dynos horizontally as needed
- Web Dashboard - Modern, mobile-friendly admin interface
- RESTful API - Full-featured API for automation and integrations
- CLI Tool - Heroku-compatible command-line interface
- GitHub Integration - Deploy directly from GitHub Actions
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| RAM | 2 GB | 4+ GB |
| Storage | 20 GB SSD | 50+ GB SSD |
| Network | 100 Mbps | 1 Gbps |
| Component | Version | Purpose |
|---|---|---|
| Operating System | AlmaLinux 8+, RHEL 8+, Ubuntu 22.04+ | Host OS |
| Go | 1.21+ | Build pvdifyd and CLI |
| Node.js | 18+ LTS | Build admin UI |
| Podman | 4.0+ | Container runtime (rootless supported) |
| SQLite | 3.35+ | Application database |
| Systemd | 239+ | Service management |
| Port | Protocol | Purpose |
|---|---|---|
| 80 | TCP | HTTP redirect to HTTPS |
| 443 | TCP | HTTPS (Admin UI, API, App traffic) |
| 9443 | TCP | Internal API (localhost only) |
| Service | Purpose |
|---|---|
| Cloudflare | DNS management, SSL, CDN, DDoS protection |
| Let's Encrypt | Free SSL certificates (if not using Cloudflare) |
| Container Registry | Docker Hub, GitHub Container Registry, or private |
┌─────────────────────────────────────────────────────────────────────┐
│ Internet │
└───────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Cloudflare (Optional) │
│ DNS, SSL Termination, CDN, WAF │
└───────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Reverse Proxy Layer │
│ (Caddy / LiteSpeed / Nginx) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────────┐ │
│ │ admin.*.win │ │ app1.*.win │ │ app2.*.win │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────────┬──────────────┘ │
└──────────┼────────────────┼────────────────────────┼────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Pvdify Stack │
├─────────────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────────┐ │
│ │ Admin UI │ │ Pvdify CLI │ │ GitHub Extension │ │
│ │ (SvelteKit) │ │ (Go) │ │ (gh-pvdify) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────────┬──────────────┘ │
│ │ │ │ │
│ └────────────────┼────────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ pvdifyd (Go) │ │
│ │ Control Plane Daemon │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ REST │ │ SQLite │ │ Podman │ │ Systemd │ │ │
│ │ │ API │ │ DB │ │ Client │ │ Generator │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Container Runtime (Podman) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ App 1 │ │ App 2 │ │ App 3 │ │ App N │ │ │
│ │ │ :3000 │ │ :3001 │ │ :3002 │ │ :300N │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
| Component | Technology | Description |
|---|---|---|
| pvdifyd | Go 1.21+ | Control plane daemon - REST API, SQLite database, container orchestration |
| admin-ui | SvelteKit 2 + Tailwind CSS | Responsive web dashboard for app management |
| cli | Go + Cobra | Heroku-compatible command-line interface |
| gh-pvdify | Bash | GitHub CLI extension for CI/CD pipelines |
- User Request → Cloudflare (DNS/SSL) → Reverse Proxy → pvdifyd API
- App Traffic → Cloudflare → Reverse Proxy → Container (via port mapping)
- Deployment → CLI/API → pvdifyd → Podman → Systemd unit → Running container
pvdify apps:create my-apppvdify deploy my-app --image nginx:latestpvdify domains:add my-app myapp.example.comYour app is live at https://my-app.yourdomain.com
# Download latest release
curl -fsSL https://github.com/Philoveracity/pvdify.win/releases/latest/download/pvdify-linux-amd64 -o pvdify
chmod +x pvdify
sudo mv pvdify /usr/local/bin/# Set API endpoint
export PVDIFY_API_URL="https://your-pvdify-server.com"
# Set authentication token (if enabled)
export PVDIFY_TOKEN="your-api-token"| Flag | Environment Variable | Description |
|---|---|---|
--api-url |
PVDIFY_API_URL |
Pvdify API endpoint |
--token |
PVDIFY_TOKEN |
Authentication token |
# List all apps
pvdify apps
# Create a new app
pvdify apps:create NAME [-e environment]
-e, --environment Environment: production (default), staging
# Show app details
pvdify apps:info NAME
# Delete an app (requires confirmation)
pvdify apps:delete NAME# Deploy a container image
pvdify deploy NAME --image IMAGE
-i, --image Container image to deploy (required)
# Examples:
pvdify deploy my-app --image nginx:latest
pvdify deploy my-app --image ghcr.io/myorg/myapp:v1.2.3
pvdify deploy my-app --image my-registry.com/app:latest
# List releases
pvdify releases NAME
# Rollback to previous release
pvdify rollback NAME# Show all config vars (values hidden)
pvdify config NAME
# Set one or more config vars
pvdify config:set NAME KEY=VALUE [KEY=VALUE...]
# Examples:
pvdify config:set my-app DATABASE_URL=postgres://...
pvdify config:set my-app NODE_ENV=production PORT=3000
# Unset config vars
pvdify config:unset NAME KEY [KEY...]# List domains for an app
pvdify domains NAME
# Add a custom domain
pvdify domains:add NAME DOMAIN
# Remove a domain
pvdify domains:remove NAME DOMAIN
# Example workflow:
pvdify domains:add my-app app.example.com
# Then add CNAME record: app.example.com → my-app.pvdify.win# List processes (dynos)
pvdify ps NAME
# Scale processes
pvdify ps:scale NAME TYPE=COUNT [TYPE=COUNT...]
# Examples:
pvdify ps:scale my-app web=3 # Scale web to 3 instances
pvdify ps:scale my-app worker=2 # Scale workers
# Restart all processes
pvdify ps:restart NAME# View recent logs
pvdify logs NAME
# View more lines
pvdify logs NAME -n 500
# Stream logs in real-time
pvdify logs NAME -fhttps://your-pvdify-server.com/api/v1
If authentication is enabled, include the token in the Authorization header:
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/api/v1/appsGET /health{
"status": "ok",
"version": "0.1.0"
}| Method | Endpoint | Description |
|---|---|---|
GET |
/apps |
List all apps |
POST |
/apps |
Create a new app |
GET |
/apps/{name} |
Get app details |
PATCH |
/apps/{name} |
Update app settings |
DELETE |
/apps/{name} |
Delete an app |
curl -X POST https://api.example.com/api/v1/apps \
-H "Content-Type: application/json" \
-d '{"name": "my-app", "environment": "production"}'{
"name": "my-app",
"environment": "production",
"status": "created",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}| Method | Endpoint | Description |
|---|---|---|
GET |
/apps/{name}/releases |
List all releases |
POST |
/apps/{name}/releases |
Create release (deploy) |
GET |
/apps/{name}/releases/{version} |
Get specific release |
POST |
/apps/{name}/rollback |
Rollback to previous |
curl -X POST https://api.example.com/api/v1/apps/my-app/releases \
-H "Content-Type: application/json" \
-d '{"image": "nginx:latest"}'| Method | Endpoint | Description |
|---|---|---|
GET |
/apps/{name}/config |
Get all config vars |
PUT |
/apps/{name}/config |
Set config vars |
DELETE |
/apps/{name}/config/{key} |
Unset a config var |
| Method | Endpoint | Description |
|---|---|---|
GET |
/apps/{name}/domains |
List domains |
POST |
/apps/{name}/domains |
Add a domain |
DELETE |
/apps/{name}/domains/{domain} |
Remove a domain |
| Method | Endpoint | Description |
|---|---|---|
GET |
/apps/{name}/ps |
List processes |
POST |
/apps/{name}/ps/scale |
Scale processes |
POST |
/apps/{name}/ps/restart |
Restart processes |
| Method | Endpoint | Description |
|---|---|---|
GET |
/apps/{name}/logs |
Get application logs |
The web dashboard provides a visual interface for all operations.
| Route | Description |
|---|---|
/ |
Dashboard - View all apps with status |
/apps/new |
Create a new application |
/apps/{name} |
App details with tabs |
/status |
System health monitoring |
Overview
- Process/dyno status with scaling controls
- Latest release information
- Quick stats (releases, config vars, domains, dynos)
Deploy
- CLI deployment instructions
- Full release history
- One-click rollback
Config
- View/hide sensitive config values
- Add/remove environment variables
Settings
- App metadata and timestamps
- Domain management with Cloudflare integration
- Danger zone (delete app)
Pvdify integrates with Cloudflare for DNS management and SSL.
- API Token: Create a Cloudflare API token with Zone:DNS:Edit permissions
- Configure: Set
CLOUDFLARE_API_TOKENenvironment variable on your Pvdify server - Use: The admin UI will show "Connect to Cloudflare" buttons for domain management
- One-Click DNS: Add CNAME records directly from the dashboard
- Automatic SSL: Cloudflare provides free SSL certificates
- Proxy Mode: Enable Cloudflare proxy for CDN and DDoS protection
| Field | Type | Description |
|---|---|---|
name |
string | Unique identifier (lowercase, alphanumeric, hyphens) |
environment |
string | production or staging |
status |
string | created, running, stopped, failed, deleting |
image |
string | Current container image |
bind_port |
int | Container port to expose |
resources |
object | CPU/memory limits |
healthcheck |
object | Health check configuration |
created_at |
datetime | Creation timestamp |
updated_at |
datetime | Last modification |
| Field | Type | Description |
|---|---|---|
version |
int | Sequential release number |
image |
string | Container image for this release |
status |
string | pending, deploying, current, rolled_back |
created_at |
datetime | Deployment timestamp |
| Field | Type | Description |
|---|---|---|
type |
string | Process type (e.g., web, worker) |
count |
int | Number of instances |
command |
string | Override command (optional) |
- Run pvdifyd on localhost only (use reverse proxy for external access)
- Enable HTTPS via Cloudflare or Let's Encrypt
- Use firewall rules to restrict port access
- Enable API token authentication in production
- Use environment variables for sensitive configuration
- Rotate tokens periodically
- Run containers as non-root users
- Use read-only root filesystems where possible
- Scan images for vulnerabilities before deployment
- Use private registries for proprietary images
- Config vars are stored encrypted at rest
- Database file permissions should be restricted
- Regular backups recommended
pvdify.win/
├── pvdifyd/ # Control plane daemon (Go)
│ ├── cmd/pvdifyd/ # Main entry point
│ └── internal/
│ ├── api/ # REST API handlers
│ ├── config/ # Configuration management
│ ├── db/ # SQLite database layer
│ ├── models/ # Data structures
│ ├── podman/ # Container runtime client
│ └── systemd/ # Unit file generator
├── cli/ # Command-line tool (Go)
│ ├── cmd/pvdify/ # CLI commands
│ └── internal/client/ # API client library
├── admin-ui/ # Web dashboard (SvelteKit)
│ ├── src/routes/ # Page components
│ └── src/app.css # Tailwind styles
├── gh-pvdify/ # GitHub CLI extension
├── .gitignore
├── LICENSE
└── README.md
- Go 1.21+
- Node.js 18+ LTS
- Podman 4.0+
# Build control plane daemon
cd pvdifyd && go build -o pvdifyd ./cmd/pvdifyd
# Build CLI
cd cli && go build -o pvdify ./cmd/pvdify
# Build admin UI
cd admin-ui && npm install && npm run build# Start pvdifyd in dev mode
./pvdifyd --dev
# Access:
# - Admin UI: http://localhost:9443
# - API: http://localhost:9443/api/v1# AlmaLinux/RHEL
sudo dnf install -y podman sqlite
# Ubuntu/Debian
sudo apt install -y podman sqlite3# Download and install binaries
sudo cp pvdifyd /usr/local/bin/
sudo cp pvdify /usr/local/bin/
# Create data directory
sudo mkdir -p /var/lib/pvdify# /etc/systemd/system/pvdifyd.service
[Unit]
Description=Pvdify Control Plane Daemon
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/pvdifyd
Restart=always
RestartSec=5
Environment=PVDIFY_STATIC_DIR=/opt/pvdify/admin-ui/dist
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now pvdifydCaddy (Recommended)
your-domain.com {
reverse_proxy localhost:9443
}
Nginx
server {
listen 443 ssl;
server_name your-domain.com;
location / {
proxy_pass http://localhost:9443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
go test ./...) - Commit (
git commit -m 'Add amazing feature') - Push (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE for details.