Django app for VPS hosting — manage Proxmox VMs and containers via REST API.
Project description
Inveterate
An open-source Proxmox provisioning engine for VPS & game-server hosts. Inveterate is a Django app that turns a Proxmox cluster into a REST API: spin up KVM/LXC instances from cloud-init, hand customers a browser console, meter their bandwidth, and manage IPs and NAT port-forwarding — all in ~15 seconds per deploy.
Try it in 60 seconds
No Proxmox required to look around — docker compose up boots the full stack
(Postgres + Redis + Django + Celery) and seeds a demo catalog of plans, OS
templates, and app profiles:
git clone https://github.com/hosler/inveterate.git
cd inveterate
cp .env.example .env
docker compose up -d --build
Then open:
| URL | What |
|---|---|
| http://localhost:8000/api/v1/docs/ | Swagger UI — every endpoint, try-it-out |
| http://localhost:8000/api/v1/plans/ | Browsable API with the seeded catalog |
| http://localhost:8000/admin/ | Django admin — log in with admin / admin |
To actually provision VMs, point it at a Proxmox cluster (see Connecting Proxmox below).
Features
- VM/LXC Provisioning — automated cloud-init provisioning, cross-node cloning, resource management
- App Profiles — pre-configured cloud-init templates (Docker, Nginx, …) selectable at deploy time
- Browser Console — terminal in the browser via a WebSocket proxy to Proxmox VNC
- Networking — IP pool management, NAT port-forwarding via Nginx Proxy Manager, domain routing with SSL
- Inventory — automatic capacity calculation per plan/node (CPU, RAM, disk, IPs, bandwidth)
- Bandwidth Metering — per-service usage tracking with monthly renewal and overage suspension
- SSH Keys — deploy and update keys on running KVM services via cloud-init
- Multi-Cluster — manage multiple Proxmox clusters from one installation
Connecting Proxmox
Set the Proxmox variables in .env, then create the cluster record:
# .env
PROXMOX_HOST=pve.example.com
PROXMOX_USER=root@pam
PROXMOX_KEY=your-api-token-value
docker compose exec web python manage.py init_cluster
From there, add nodes, IP pools, and templates via the admin or API, then POST /api/v1/services/ to provision. See the Swagger docs for the full surface.
Use as a Django app
Inveterate is packaged as django-inveterate and can be embedded in an existing
Django project instead of run standalone:
pip install django-inveterate
# settings.py
INSTALLED_APPS = [
...
"inveterate",
]
# urls.py
urlpatterns = [
path("api/v1/", include("inveterate.urls")),
]
It requires Postgres, Redis, and a Celery worker. The optional extras pull in
what each surface needs: django-inveterate[docs] (Swagger), [cors],
[websocket] (browser console), or [all].
API Reference
Public (anonymous)
| Endpoint | Method | Description |
|---|---|---|
/plans/ |
GET | List available plans |
/templates/ |
GET | List OS templates |
/apps/ |
GET | List app profiles |
/inventory/ |
GET | Available capacity per plan/node |
Customer (authenticated)
| Endpoint | Method | Description |
|---|---|---|
/services/ |
GET/POST | List or create services |
/services/{id}/ |
GET | Service detail |
/services/{id}/{start,shutdown,stop,reboot,cancel}/ |
POST | Power / lifecycle actions |
/services/{id}/status/ |
POST | Live VM status |
/services/{id}/console/ |
GET | Console credentials |
/services/{id}/ssh_keys/ |
POST | Update SSH keys |
/portforwards/ |
GET/POST/DELETE | CRUD NAT port-forward rules |
/domainroutes/ |
GET/POST/DELETE | CRUD domain routes |
/tasks/{task_id}/ |
GET | Poll async task status |
Admin
Full CRUD on clusters, nodes, node disks, IP pools, IPs, services, plans,
templates, and app profiles. Full interactive reference at /api/v1/docs/.
Scheduled Tasks
Configure these periodic tasks via django-celery-beat (the beat service in
the compose file runs the scheduler):
| Task | Interval | Description |
|---|---|---|
inveterate.tasks.meter_bandwidth |
5–15 min | Track VM bandwidth usage |
inveterate.tasks.calculate_inventory |
1 hour | Update available capacity |
inveterate.tasks.cleanup_console_users |
Daily | Remove orphaned Proxmox console users |
inveterate.tasks.cleanup_orphaned_ips |
Daily | Release IPs from destroyed services |
Production
The included Dockerfile runs Gunicorn (gevent worker) by default. Run the web,
celery, and beat services behind a reverse proxy, set a real SECRET_KEY,
a generated FIELD_ENCRYPTION_KEY, and DJANGO_SETTINGS_MODULE=config.settings.production.
Built With
Django + Django REST Framework · Celery · proxmoxer · PostgreSQL · Redis
License
Inveterate is licensed under the GNU AGPLv3 (see LICENSE.txt).
You can self-host it freely, including to run your own hosting business, as long
as you comply with the AGPL's network-source-disclosure terms. A separate
commercial license is available for proprietary / closed-source use — see
COMMERCIAL.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_inveterate-1.0.0.tar.gz.
File metadata
- Download URL: django_inveterate-1.0.0.tar.gz
- Upload date:
- Size: 104.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4af9943e1fac88d8f2c461dac628a36755e3a70d6f2f09e95d11a33e5de7637
|
|
| MD5 |
4be79b0ae39a686a96f2939934921538
|
|
| BLAKE2b-256 |
ec39fd90b2752cb6fa0434e8e070c927f6e8c0025c88783848017bd3bdd75a40
|
File details
Details for the file django_inveterate-1.0.0-py3-none-any.whl.
File metadata
- Download URL: django_inveterate-1.0.0-py3-none-any.whl
- Upload date:
- Size: 141.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6ec0d445cfe651dafbce55636333a0c81e67450e58394b9c4c831aa5167bea4
|
|
| MD5 |
40927fd9d0682371447de4217938cff0
|
|
| BLAKE2b-256 |
0fb50e4747df915a8ffe2b94e9337c489460e120f98cba583d8a3fb813e3e818
|