Introduction
usulnet is a self-hosted Docker management platform built with Go. It ships as a single binary (~70 MB) with 46 backend services, 46 database migrations, and 144+ embedded application templates across 10 categories. It provides a unified web interface for managing containers, images, volumes, networks, stacks, security scanning, monitoring, reverse proxy, DNS server, backups, remote desktop (RDP/VNC), registry browsing, developer tools, operations calendar, GitOps, and multi-node deployments.
Designed for sysadmins, DevOps engineers, and platform teams who need a production-grade, self-hosted alternative to Portainer and cloud-native container management solutions — without vendor lock-in, telemetry, or external dependencies.
v26.2.7 is the latest public release. Report issues on GitHub.
Key Highlights
- Single binary — No runtime dependencies. Templ templates and Tailwind CSS compiled at build time. ~70 MB.
- Multi-node — Master/agent architecture with NATS JetStream, mTLS, and persistent event logging.
- Security-first — Trivy CVE scanning, CIS benchmarks, SBOM generation, RBAC (46 permissions), TOTP 2FA, LDAP/OIDC, AES-256-GCM encrypted secrets.
- Full-stack — Containers, images, stacks, proxies, backups (with full stack restore), SSH, remote desktop (RDP/VNC via Guacamole), Git, registry browsing, 144+ templates — all in one UI.
- No telemetry — Zero usage data collected. Community Edition validates licenses fully offline with an RSA-4096 public key embedded in the binary. Paid editions require a one-time online activation and 6-hour check-ins for instance binding; only the license ID and an opaque instance fingerprint are transmitted — no usage or behavioral data.
- REST API — Full CRUD API at
/api/v1with OpenAPI 3.0 spec, Swagger UI, and WebSocket real-time streams. - Observable — Prometheus
/metricsendpoint, OpenTelemetry tracing, structured JSON logging (zap).
Tech Stack
| Component | Technology |
|---|---|
| Language | Go 1.25+ |
| Web Framework | Chi router (go-chi/chi/v5) |
| Templates | Templ (compile-time, type-safe) |
| Styling | Tailwind CSS + Alpine.js + HTMX |
| Database | PostgreSQL with pgx/v5 + sqlx |
| Cache / Sessions | Redis 8 (TLS by default) |
| Messaging | NATS with JetStream |
| Security Scanning | Trivy |
| Reverse Proxy | Nginx (built-in) |
| DNS Server | miekg/dns (embedded, authoritative) |
| Terminal | xterm.js + Monaco Editor + Neovim |
| Charts | Chart.js (vendored UMD) |
| Observability | OpenTelemetry + Prometheus + zap |
| Remote Desktop | Apache Guacamole (guacd + WebSocket) |
Quick Deploy
Deploy usulnet in one command. All secrets (database passwords, JWT keys, encryption keys) are generated automatically.
bashcurl -fsSL https://raw.githubusercontent.com/fr4nsys/usulnet/main/deploy/install.sh | bash
This will:
- Download the production Docker Compose configuration
- Auto-generate secure database passwords, JWT secrets, and encryption keys
- Start usulnet with PostgreSQL, Redis, NATS, Nginx, and Guacamole
- Be ready in under 60 seconds (pre-built images)
Access at https://your-server-ip:7443. Default credentials: admin / usulnet. Change the password immediately after first login.
Manual Installation
For more control over the deployment, install manually with Docker Compose:
bash# Create installation directory
mkdir -p /opt/usulnet && cd /opt/usulnet
# Download production files
curl -fsSL https://raw.githubusercontent.com/fr4nsys/usulnet/main/deploy/docker-compose.prod.yml -o docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/fr4nsys/usulnet/main/deploy/.env.example -o .env
# Generate secrets (or edit .env manually)
sed -i "s|CHANGE_ME_GENERATE_RANDOM_PASSWORD|$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)|" .env
sed -i "s|CHANGE_ME_GENERATE_WITH_OPENSSL_RAND_HEX_32|$(openssl rand -hex 32)|" .env
# Start
docker compose up -d
Docker Compose Example
yamlservices:
usulnet:
image: ghcr.io/fr4nsys/usulnet:latest
ports:
- "8080:8080" # HTTP
- "7443:7443" # HTTPS (auto-TLS)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- usulnet-data:/var/lib/usulnet
- nginx-conf:/etc/nginx/conf.d/usulnet # Shared: nginx config
- nginx-certs:/etc/usulnet/certs # Shared: TLS certificates
- acme-webroot:/var/lib/usulnet/acme # Shared: ACME challenges
environment:
- USULNET_DATABASE_URL=postgres://usulnet:${DB_PASSWORD}@postgres:5432/usulnet?sslmode=require
- USULNET_REDIS_URL=rediss://redis:6379/0
- USULNET_NATS_URL=nats://nats:4222
- USULNET_SECURITY_JWT_SECRET=${JWT_SECRET}
- USULNET_SECURITY_CONFIG_ENCRYPTION_KEY=${ENCRYPTION_KEY}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
nginx:
image: nginx:1.28-alpine
ports:
- "80:80" # Public HTTP (ACME + redirect)
- "443:443" # Public HTTPS (reverse proxy)
volumes:
- nginx-conf:/etc/nginx/conf.d/usulnet:ro
- nginx-certs:/etc/usulnet/certs:ro
- acme-webroot:/var/lib/usulnet/acme:ro
guacd:
image: guacamole/guacd:1.6.0
restart: unless-stopped # RDP/VNC gateway for remote desktop
Build from Source
Prerequisites: Go 1.25+, Make, Docker.
bashgit clone https://github.com/fr4nsys/usulnet.git
cd usulnet
# Full build (templ + tailwind css + go build)
make build
# Run locally
make run
# Or build and run with Docker Compose
docker compose -f docker-compose.dev.yml build
docker compose -f docker-compose.dev.yml up -d
Makefile Targets
| Command | Description |
|---|---|
make build | Full build (templ + CSS + Go binary) |
make templ | Generate Go code from .templ files |
make css | Compile Tailwind CSS |
make run | Run the application |
make test | Run tests with race detection and coverage |
make lint | Run golangci-lint |
make dev-up | Start dev environment (PostgreSQL, Redis, NATS, MinIO) |
make dev-down | Stop dev environment |
make migrate | Run database migrations up |
Configuration
usulnet is configured via config.yaml and environment variables. Environment variables override config file values using the pattern USULNET_<SECTION>_<KEY>.
Server & TLS
yamlserver:
host: "0.0.0.0"
port: 8080
https_port: 7443
read_timeout: "30s"
write_timeout: "30s"
idle_timeout: "120s"
shutdown_timeout: "10s"
tls:
enabled: true # HTTPS on port 7443 (auto self-signed cert)
auto_tls: true # Auto-generate from internal CA
# cert_file: "" # Custom certificate path
# key_file: "" # Custom private key path
When TLS is enabled, the server listens on both :8080 (HTTP) and :7443 (HTTPS). The auto-generated self-signed certificate is suitable for internal use. For production with a public domain, use the built-in Nginx reverse proxy for Let's Encrypt certificates.
Database
yamldatabase:
# sslmode=require — TLS-encrypted, no CA verification (default; works with self-signed cert).
# Use sslmode=verify-full and USULNET_DATABASE_SSL_ROOTCERT for full cert verification.
url: "postgres://usulnet:password@postgres:5432/usulnet?sslmode=require"
max_open_conns: 25
max_idle_conns: 10
conn_max_lifetime: "30m"
conn_max_idle_time: "5m"
Environment variable: USULNET_DATABASE_URL
All provided Docker Compose files enable PostgreSQL TLS by default. A self-signed ECDSA P-256 certificate is generated automatically on every container startup — no external certificate files or init containers needed. The default sslmode=require encrypts the connection without requiring a CA certificate. For full certificate verification, set sslmode=verify-full and provide the CA certificate path via the USULNET_DATABASE_SSL_ROOTCERT environment variable, mounting the CA cert into the usulnet container.
Redis
yamlredis:
url: "rediss://redis:6379" # rediss:// = TLS enabled (note double 's')
# tls_enabled: true # Auto-enabled when using rediss:// URL scheme
# tls_skip_verify: true # Skip CA verification (default for self-signed)
# tls_ca_file: "" # CA certificate for server verification
# tls_cert_file: "" # Client certificate (optional, for mTLS)
# tls_key_file: "" # Client private key (optional, for mTLS)
Used for session management, caching, and real-time pub/sub. Environment variable: USULNET_REDIS_URL
All provided Docker Compose files enable Redis TLS by default. A self-signed ECDSA P-256 certificate is generated automatically on every container startup — no external certificate files or init containers needed. The rediss:// URL scheme (note the double 's') enables TLS automatically. To use your own certificate, mount redis-server.crt and redis-server.key into the Redis container at /certs-src/. To verify the server certificate, set tls_ca_file and disable tls_skip_verify.
NATS
yamlnats:
url: "nats://nats:4222"
name: "usulnet"
jetstream:
enabled: true
# tls:
# enabled: false
# cert_file: "" # Client certificate (mTLS)
# key_file: "" # Client private key
# ca_file: "" # CA certificate
# skip_verify: false
NATS with JetStream provides inter-node communication in multi-node deployments. In master mode, it is used for internal event streaming, backup scheduling, and agent coordination.
For multi-node deployments, enable NATS TLS to encrypt agent-to-master communication. The tls block accepts client certificate and CA certificate paths for mutual TLS (mTLS). In Docker Compose, certificates can be auto-provisioned by the usulnet PKI system.
Security
yamlsecurity:
jwt_secret: "..." # openssl rand -hex 32
jwt_expiry: "24h"
refresh_expiry: "168h"
config_encryption_key: "..." # openssl rand -hex 32 (64 hex chars)
cookie_secure: true # Set to false only for HTTP-only development
cookie_samesite: "lax"
password_min_length: 8
Generate unique secrets for production. Never use the default values from config.yaml. Use openssl rand -hex 32 to generate random keys.
Storage & Backups
yamlstorage:
type: "local" # "local" or "s3"
path: "/app/data"
backup:
compression: "gzip" # "gzip" or "zstd"
default_retention_days: 30
# S3-compatible storage (MinIO, AWS S3, etc.)
minio:
endpoint: "minio:9000"
access_key: "minioadmin"
secret_key: "minioadmin"
bucket: "usulnet-backups"
use_ssl: false
Docker
yamldocker:
host: "unix:///var/run/docker.sock" # Docker daemon socket
version: "" # Docker API version (auto-detect)
tls_verify: false
cert_path: ""
usulnet connects to the Docker daemon via the socket. In production, mount it read-only (/var/run/docker.sock:/var/run/docker.sock:ro). For remote Docker hosts, configure the host with a TCP address and enable TLS verification.
Nginx Reverse Proxy
yamlnginx:
acme_email: "" # Required for Let's Encrypt certificates
config_dir: "/etc/nginx/conf.d/usulnet" # Shared volume with nginx container
cert_dir: "/etc/usulnet/certs" # Certificate storage
acme_web_root: "/var/lib/usulnet/acme" # ACME challenge webroot
acme_account_dir: "/app/data/acme" # ACME account key storage
listen_http: ":80" # Nginx HTTP listen address
listen_https: ":443" # Nginx HTTPS listen address
usulnet manages nginx configuration files via shared Docker volumes. When you add a proxy host, usulnet generates the nginx config, writes it to the shared volume, and triggers nginx -s reload via the Docker API. The nginx container runs as a separate service in Docker Compose, serving as the public-facing reverse proxy.
Set acme_email to enable automatic certificate provisioning via Let's Encrypt. HTTP-01 challenges are served through the nginx ACME webroot. For wildcard certificates (*.example.com), configure a DNS provider (Cloudflare) for DNS-01 challenges.
DNS Server
yamldns:
enabled: true # Enable the embedded DNS server
listen_addr: ":53" # UDP/TCP listen address
forwarders: # Upstream servers for recursive queries
- "1.1.1.3" # Cloudflare malware-blocking DNS
- "1.0.0.3"
usulnet includes an embedded authoritative DNS server powered by miekg/dns (the Go DNS library behind CoreDNS). It runs in-process as part of the usulnet binary, serving zones managed from the web UI.
Zones and records are stored in PostgreSQL (source of truth). On every change, the full dataset is synced to the in-memory DNS server. Queries for managed zones are answered authoritatively; all other queries are forwarded to the configured upstream resolvers.
| Variable | Config Path | Default |
|---|---|---|
USULNET_DNS_ENABLED | dns.enabled | true |
USULNET_DNS_LISTEN_ADDR | dns.listen_addr | :53 |
Service Discovery
usulnet can automatically register running containers as DNS records by listening to the Docker event stream. Containers appear as A records under a configurable domain, with optional SRV records for exposed ports. Records are added on container start and removed on container stop in real time.
yamldns:
service_discovery:
enabled: true
domain: "containers.local"
ttl: 30
create_srv: true
| Variable | Config Path | Default |
|---|---|---|
USULNET_DNS_SD_ENABLED | dns.service_discovery.enabled | true |
USULNET_DNS_SD_DOMAIN | dns.service_discovery.domain | containers.local |
USULNET_DNS_SD_TTL | dns.service_discovery.ttl | 30 |
USULNET_DNS_SD_CREATE_SRV | dns.service_discovery.create_srv | true |
Remote Desktop (Guacamole)
yamlguacamole:
enabled: true
host: "guacd" # guacd container hostname
port: 4822 # guacd native protocol port
The guacd sidecar container handles RDP, VNC, and SSH protocol translation. usulnet communicates with guacd over its native protocol and exposes sessions to the browser via WebSocket. No external ports are required.
Observability
yamlmetrics:
enabled: true
path: "/metrics" # Prometheus scrape endpoint
observability:
tracing:
enabled: false
endpoint: "" # OTLP endpoint (e.g., "localhost:4317")
sampling_rate: 0.1 # 10% sampling rate
service_name: "usulnet"
logging:
level: "info" # debug, info, warn, error, fatal
format: "json" # "json" (production) or "console" (development)
output: "stdout" # "stdout" or "file"
file: "" # Log file path (when output=file)
The /metrics endpoint exposes Prometheus-compatible metrics (requires admin JWT). A pre-built Grafana dashboard is available at deploy/grafana/. OpenTelemetry tracing sends spans via OTLP gRPC to any compatible collector (Jaeger, Tempo, etc.).
Environment Variables
All configuration values can be overridden via environment variables using the format USULNET_<SECTION>_<KEY>:
| Variable | Config Path | Example |
|---|---|---|
USULNET_DATABASE_URL | database.url | postgres://user:pass@host:5432/db |
USULNET_REDIS_URL | redis.url | redis://host:6379 |
USULNET_NATS_URL | nats.url | nats://host:4222 |
USULNET_SECURITY_JWT_SECRET | security.jwt_secret | 64 hex characters |
USULNET_SECURITY_CONFIG_ENCRYPTION_KEY | security.config_encryption_key | 64 hex characters |
USULNET_MODE | mode | master, agent |
USULNET_SERVER_PORT | server.port | 8080 |
USULNET_SERVER_HTTPS_PORT | server.https_port | 7443 |
USULNET_LOGGING_LEVEL | logging.level | info, debug, warn |
USULNET_METRICS_ENABLED | metrics.enabled | true / false |
USULNET_STORAGE_TYPE | storage.type | local / s3 |
USULNET_NGINX_ACME_EMAIL | nginx.acme_email | [email protected] |
USULNET_NGINX_CONFIG_DIR | nginx.config_dir | /etc/nginx/conf.d/usulnet |
USULNET_DNS_ENABLED | dns.enabled | true |
USULNET_DNS_LISTEN_ADDR | dns.listen_addr | :53 |
USULNET_DNS_SD_ENABLED | dns.service_discovery.enabled | true |
USULNET_DNS_SD_DOMAIN | dns.service_discovery.domain | containers.local |
USULNET_DNS_SD_TTL | dns.service_discovery.ttl | 30 |
USULNET_DNS_SD_CREATE_SRV | dns.service_discovery.create_srv | true |
USULNET_GUACAMOLE_HOST | guacamole.host | guacd |
USULNET_GUACAMOLE_PORT | guacamole.port | 4822 |
Containers
Full container lifecycle management with a rich set of operations available from the web UI and API.
- Lifecycle — Create, start, stop, restart, pause, unpause, kill, remove
- Bulk operations — Select multiple containers and apply actions in batch
- Real-time stats — CPU, memory, network I/O, disk I/O via WebSocket
- Exec terminal — Open a shell inside any running container (xterm.js)
- Filesystem browser — Browse, edit, upload, download files inside containers
- Settings editor — Modify environment variables, labels, restart policy without recreating
- Logs — Real-time log streaming with search and filtering
Images
Complete Docker image management with update detection and registry browsing.
- Browse and search — List local images, search Docker Hub, filter by repository, tag, or size
- Pull and push — Pull images from any registry (with stored credentials). Push images to private registries
- Update detection — Automatic digest comparison against Docker Hub, GHCR, and generic v2 registries. Detects when a newer version of a tag is available
- Image history — View the full layer history and Dockerfile instructions for any image
- Dangling cleanup — Identify and remove unused images (dangling and unreferenced) to reclaim disk space
- Bulk operations — Select multiple images for batch removal
- SBOM export — Generate Software Bill of Materials in CycloneDX and SPDX formats via Trivy
Volumes & Networks
Manage Docker volumes and networks directly from the web UI.
Volumes
- Create and remove — Named volumes with driver options (local, NFS, CIFS, etc.)
- Browse contents — Inspect files inside volumes via the filesystem browser
- Usage tracking — See which containers reference each volume
- Backup integration — Volumes are included in container and stack backups (AES-encrypted, compressed)
Networks
- Create and remove — Bridge, overlay, macvlan, and host networks with custom IPAM configuration
- Connect / disconnect — Attach and detach running containers to networks
- Inspect — View connected containers, subnet, gateway, and driver options
- Interactive topology graph — D3.js force-directed visualization of all networks and containers. Drag nodes, zoom/pan, hover to highlight connections, click for details. Networks color-coded by driver, containers by state. Fullscreen mode for large topologies. JSON API at
/topology/api
Stacks / Compose
Deploy and manage Docker Compose stacks directly from the web UI.
- Visual editor — Write docker-compose.yml with syntax highlighting
- Environment variables — Manage .env files per stack
- Git-based deploys — Pull stacks from Git repositories with auto-deploy on push
- Stack catalog — One-click deployment of popular applications
- Monitoring — View container status, logs, and resource usage per stack
Template Catalog
usulnet ships with a built-in application template catalog — 144+ ready-to-deploy templates across 10 categories, embedded directly in the binary.
Categories
| Category | Examples |
|---|---|
| Databases | PostgreSQL, MySQL, MariaDB, MongoDB, Redis, CockroachDB, InfluxDB |
| CMS | WordPress, Ghost, Strapi |
| Monitoring | Grafana, Prometheus, Uptime Kuma, Netdata |
| Development | Gitea, GitLab, Drone CI, code-server |
| Storage | MinIO, Nextcloud, Seafile |
| Networking | Pi-hole, AdGuard Home, WireGuard, Traefik, Caddy |
| Communication | Mattermost, Rocket.Chat, Matrix Synapse |
| Security | Vaultwarden, Keycloak, Authelia |
| Home Automation | Home Assistant, Node-RED, Mosquitto MQTT, Zigbee2MQTT |
| Media | Jellyfin, Plex, PhotoPrism, Immich, Navidrome |
| Tools | n8n, Outline, BookStack, Wiki.js, IT-Tools, Stirling PDF |
Features
- One-click deploy — Select a template, customize environment variables, and deploy as a stack
- Search and filter — Find templates by name, category, or keyword
- Custom templates — Add your own templates with docker-compose.yml definitions
- Import / Export — Export templates as JSON for sharing across instances. Import Portainer-compatible template JSON files
API Endpoints
httpGET /api/v1/templates # List all templates (with ?category= filter)
GET /api/v1/templates/:id # Get template by ID
POST /api/v1/templates # Create custom template
PUT /api/v1/templates/:id # Update custom template
DELETE /api/v1/templates/:id # Delete custom template
POST /api/v1/templates/import # Import templates from JSON
GET /api/v1/templates/export # Export all templates as JSON
GET /api/v1/templates/categories # List available categories
The import endpoint accepts Portainer v2 template JSON format, automatically converting templates to usulnet's native format. This makes migration from Portainer straightforward.
Security Scanning
Integrated security scanning powered by Trivy.
- CVE scanning — Detect vulnerabilities in container images and filesystems
- CIS Docker Benchmark — Evaluate Docker host configuration against CIS standards
- SBOM generation — Software Bill of Materials in CycloneDX and SPDX formats
- Security scoring — Composite 0-100 score per container and across infrastructure
- Trend tracking — Monitor security posture over time
- Actionable remediation — Specific guidance on how to fix each finding
Monitoring & Alerts
Real-time metrics and alerting system with multiple notification channels.
- Metrics — CPU, memory, network, disk I/O per container and host (WebSocket live updates)
- Alert rules — Threshold-based alerts with states: OK → Pending → Firing → Resolved
- 11 notification channels — Email, Slack, Discord, Telegram, Gotify, ntfy, PagerDuty, Opsgenie, Teams, Webhook, Custom
- Prometheus endpoint — Native
/metricsendpoint for external scrapers (admin JWT required) - Grafana dashboard — Pre-built dashboard at
deploy/grafana/for visualizing usulnet metrics - Prometheus alerting — Pre-configured alert rules at
deploy/prometheus/ - OpenTelemetry — Distributed tracing via OTLP gRPC (configurable sampling rate)
- Event stream — Real-time Docker events with filtering via WebSocket
Reverse Proxy
Built-in Nginx reverse proxy fully managed from the usulnet UI.
- Nginx reverse proxy — Automatic config generation, reload, and rollback. HSTS support.
- Let's Encrypt — HTTP-01 and DNS-01 (Cloudflare) challenges. Wildcard certificate support.
- Certificate management — Auto-renewal, custom certificates, expiration alerts
- Custom certificates — Upload your own certificates or use self-signed for internal services
DNS Server
Embedded authoritative DNS server powered by miekg/dns, the Go DNS library behind CoreDNS. Fully managed from the usulnet web UI.
- Authoritative DNS — Serves managed zones over UDP and TCP. Non-authoritative queries forwarded to upstream resolvers (Cloudflare 1.1.1.3/1.0.0.3 by default).
- Zone management — Create primary, secondary, and forward zones with full SOA configuration. Zone serial auto-increments on every change.
- Record types — A, AAAA, CNAME, MX, TXT, NS, SRV, PTR, CAA, SOA. Per-record TTL and enable/disable toggle.
- TSIG keys — Transaction Signature keys for secure zone transfers. Secrets encrypted at rest with AES-256-GCM.
- PostgreSQL-backed — All zone and record data stored in PostgreSQL (source of truth), synced to the in-memory server on every change.
- Live statistics — Real-time query counters (total, success, failed), zones loaded, and server uptime visible from the DNS settings page.
- Audit logging — All zone, record, and TSIG key changes logged with user, action, resource type, and timestamp.
- Service Discovery — Automatic container→DNS registration via Docker event stream. Containers appear as
<container>.containers.localA records with SRV records for exposed ports. Real-time updates on container start/stop.
Crontab Manager
Web-based cron job scheduling and management — create, edit, enable/disable, and execute cron jobs directly from the usulnet UI.
- Three command types — Shell commands (with configurable working directory), Docker exec (target container), and HTTP webhooks (GET/POST/PUT/DELETE).
- Cron scheduling — Standard 5-field cron expressions (
minute hour day-of-month month day-of-week). Jobs fire automatically via an in-process scheduler (robfig/cron). - Execution history — Every run is recorded with status, stdout/stderr output, exit code, duration, and timestamps. Browsable from the job detail page.
- Run Now — Execute any cron job immediately from the UI, independent of its schedule.
- Enable/Disable — Toggle individual jobs on or off without deleting them.
- Auto-cleanup — Execution records older than 30 days are automatically pruned by a daily background worker.
- Stats dashboard — Overview of total, enabled, disabled, and currently running jobs.
Backups
- Targets — Back up individual containers, volumes, or entire stacks
- Scheduling — Cron-based scheduling with configurable retention policies
- Storage backends — Local filesystem, AWS S3, MinIO, Azure Blob, GCS, Backblaze B2, SFTP
- Encryption — AES-256-GCM encryption at rest
- Compression — gzip or zstd with configurable levels
- One-click restore — Restore to original or different target
- Full stack restore — Restores docker-compose.yml, .env files, and all named volumes. Stops the existing stack, restores volume data, and redeploys automatically
Stack Restore Process
When restoring a stack backup, usulnet performs the following steps automatically:
- Extracts the backup archive and reads the stored
docker-compose.ymland.envfiles - Stops the existing stack (if running) to prevent data conflicts
- Restores all named volumes from the backup to their original Docker volume paths
- Redeploys the stack using the restored compose configuration
Web Terminal
- Terminal Hub — Multi-tab xterm.js terminal with container exec and host SSH
- Monaco Editor — VS Code editor in the browser for files inside containers and hosts
- Neovim — Neovim with lazy.nvim running directly in the browser via WebSocket
- SFTP browser — Remote filesystem browsing over SSH/SFTP
Remote Desktop (RDP/VNC)
Access remote desktops directly from the browser via Apache Guacamole (guacd). No client software required — everything runs over HTML5 WebSocket.
- RDP connections — Connect to Windows servers and desktops via Remote Desktop Protocol
- VNC connections — Access VNC-enabled machines (Linux desktops, KVM consoles, etc.)
- SSH connections — Terminal access through Guacamole as an alternative to xterm.js
- Clipboard sync — Copy/paste between local machine and remote desktop
- File transfer — Upload and download files to/from RDP sessions
- Multi-session — Open multiple remote desktop sessions simultaneously in separate tabs
- Credential storage — Connection credentials encrypted with AES-256-GCM and stored in the database
The guacd daemon runs as a sidecar container in Docker Compose deployments. usulnet communicates with guacd over its native protocol and exposes sessions to the browser via WebSocket. No additional ports need to be exposed — all traffic flows through the usulnet web interface.
Authentication
- Local auth — Username/password with bcrypt hashing
- TOTP 2FA — Google Authenticator, Authy, etc. with backup codes
- RBAC — 44+ granular permissions with custom roles (Business edition)
- OAuth / OIDC — GitHub, Google, Microsoft, custom providers (Business edition)
- LDAP / AD — Active Directory and LDAP integration (Business edition)
- API keys — Programmatic access via
X-API-KEYheader - Audit logging — Every user action logged with IP, timestamp, and details
Custom Dashboards
Build personalized monitoring dashboards with drag-and-drop widgets. Available in the Enterprise edition.
Widget Types
| Widget | Description |
|---|---|
cpu_gauge | Real-time CPU usage gauge |
memory_gauge | Memory usage gauge |
disk_gauge | Disk usage gauge |
cpu_chart | CPU usage over time |
memory_chart | Memory usage over time |
network_chart | Network I/O over time |
container_table | Container status table |
container_count | Running/stopped container counters |
alert_feed | Recent alert activity |
log_stream | Live log stream widget |
security_score | Infrastructure security score |
compliance_status | CIS compliance summary |
top_containers | Top resource-consuming containers |
host_info | Host system information |
custom_metric | Custom Prometheus metric display |
Layouts
- Multiple layouts — Create and switch between different dashboard views
- Default layout — Set one layout as your landing page
- Shared layouts — Share layouts with other users in your organization
- Grid positioning — Place widgets at exact grid coordinates with configurable width and height
API Endpoints
http# Layouts
GET /api/v1/dashboards/layouts # List your layouts
POST /api/v1/dashboards/layouts # Create a layout
GET /api/v1/dashboards/layouts/:id # Get layout by ID
PUT /api/v1/dashboards/layouts/:id # Update layout
DELETE /api/v1/dashboards/layouts/:id # Delete layout
# Widgets
GET /api/v1/dashboards/layouts/:id/widgets # List widgets in a layout
POST /api/v1/dashboards/layouts/:id/widgets # Add widget to layout
PUT /api/v1/dashboards/widgets/:id # Update widget
DELETE /api/v1/dashboards/widgets/:id # Remove widget
Registry Browsing
Browse repositories, tags, and manifests from any Docker-compatible v2 registry directly from usulnet. Available in the Business edition.
Supported Registries
| Registry | Features |
|---|---|
| Docker Hub | Namespace browsing (user/org repos), tag listing, manifest details, pull count, star count |
| GHCR (GitHub) | Tag listing, manifest details, token-based auth |
| Harbor | Full v2 catalog, tag listing, manifest details |
| GitLab Registry | Full v2 catalog, tag listing, manifest details |
| Generic OCI v2 | Any registry implementing the OCI Distribution Spec (catalog, tags, manifests) |
Authentication
Registry credentials are stored encrypted (AES-256-GCM) in the database. The browsing service automatically handles token exchange via the Www-Authenticate challenge flow, supporting both Bearer token and Basic auth schemes.
API Endpoints
http# Registry CRUD
GET /api/v1/registries # List registries
POST /api/v1/registries # Add registry
PUT /api/v1/registries/:id # Update registry
DELETE /api/v1/registries/:id # Delete registry
# Browsing
GET /api/v1/registries/:id/repositories # List repos
GET /api/v1/registries/:id/repositories/{repo}/tags # List tags
GET /api/v1/registries/:id/repositories/{repo}/tags/{ref} # Get manifest
Example: Browse Docker Hub Tags
bash# List tags for the official nginx image
curl -s -H "Authorization: Bearer <JWT>" \
"https://your-server:7443/api/v1/registries/<id>/repositories/library/nginx/tags" | jq
Developer Tools Suite
usulnet includes 15 built-in browser-based developer utilities at /tools. All tools run entirely client-side — no data is sent to the server.
| Category | Tools |
|---|---|
| Encoders | Base64, URL encode/decode, HTML entities, hex encode/decode |
| Formatters | JSON pretty-print/minify, YAML ↔ JSON conversion |
| Generators | UUID v4/v7, random strings, secure passwords, Lorem Ipsum |
| Hash | MD5, SHA-1, SHA-256, SHA-512, bcrypt calculator |
| Network | CIDR/subnet calculator, IP geolocation lookup, DNS resolver |
| Regex | Live regex tester with match highlighting and group extraction |
| Text Diff | Side-by-side and unified diff viewer |
| JWT | JWT decoder with header/payload/claims display and expiry validation |
| Crypto | RSA/ECDSA key pair generation, certificate info viewer |
| Token | API key generator, TOTP secret generator |
Operations Calendar
An integrated calendar at /calendar for scheduling maintenance windows, tracking SLA deadlines, and coordinating team tasks.
Features
- Events — Schedule one-time or recurring events with start/end times and descriptions
- Tasks — Create tasks with checklists, due dates, and assignees
- Notes — Attach notes to any date for operational reminders
- Integration — SLA breach events and scheduled backup/scan jobs appear automatically
Drift Detection & Change Feed
Drift Detection automatically compares the expected state of running containers against their actual configuration. It detects mismatches in image tags, environment variables, volume mounts, port bindings, and resource limits.
The Change Events Feed at /changes provides a chronological audit trail of all infrastructure changes — container start/stop/restart, image pulls, stack deploys, configuration edits, and user actions — with filterable timeline.
Firewall Manager
Visual iptables/nftables management directly from the usulnet web UI. Create, edit, and delete firewall rules without touching the command line. Available in the Business edition.
- Rule management — Create, edit, and delete firewall rules with a visual editor. Supports INPUT, OUTPUT, FORWARD, and DOCKER-USER chains.
- Protocol & port configuration — TCP, UDP, ICMP protocol selection with source/destination IP and port range configuration.
- Action types — ACCEPT, DROP, REJECT, and LOG targets with configurable rule ordering and priority.
- Host-level application — Apply firewall rules to individual hosts or across all managed nodes. Push rules from the UI and sync current rules from hosts.
- Rule synchronization — Import existing iptables/nftables rules from hosts into usulnet for centralized management.
- Full audit log — Every rule creation, modification, deletion, and application is logged with user, timestamp, and change details.
- Rule validation — Rules are validated before application to prevent lockouts and misconfigurations.
SSL Observatory
TLS/SSL certificate scanner with comprehensive grading and analysis, similar to SSL Labs. Monitor your infrastructure's TLS posture from a single dashboard. Available in the Business edition.
- SSL Labs-style grading — Automated certificate grading from A+ to F based on protocol support, cipher strength, key exchange, and certificate validity.
- Protocol analysis — Detects supported TLS versions (TLS 1.0 through 1.3) and flags deprecated or insecure protocol versions.
- Cipher suite evaluation — Enumerates and evaluates all supported cipher suites, flagging weak or obsolete algorithms (RC4, 3DES, export ciphers).
- Certificate chain validation — Validates the full certificate chain from leaf to root, detecting missing intermediates, expired certificates, and self-signed chains.
- OCSP stapling detection — Checks whether OCSP stapling is enabled and functioning correctly for improved revocation checking performance.
- Certificate Transparency — Verifies the presence of Signed Certificate Timestamps (SCTs) for Certificate Transparency compliance.
- Expiration alerts — Dashboard with certificate expiration timeline. Alerts for certificates approaching expiry (configurable thresholds: 30, 14, 7 days).
- Scan scheduling — On-demand or scheduled scans with historical grade tracking to monitor TLS posture over time.
Backup Verification
Automated backup integrity verification to ensure your backups are actually restorable. Goes beyond “backup completed” status to validate the contents. Available in the Business edition.
- Extract verification — Automatically extracts backup archives to a temporary location and verifies all files are readable and intact.
- Container verification — Spins up a temporary container from a backup to verify the application starts and responds correctly.
- Database verification — Restores database dumps to a temporary instance and runs integrity checks (e.g.,
pg_restore --list,mysqlcheck). - Checksum validation — Compares SHA-256 checksums of backup contents against the original data to detect corruption or tampering.
- File readability checks — Verifies that compressed and encrypted backup files can be fully decompressed and decrypted without errors.
- Schedulable via cron — Configure verification jobs on a cron schedule to continuously validate backup integrity without manual intervention.
- Verification reports — Detailed pass/fail reports for each verification method, stored in the database and viewable from the backup detail page.
Container Image Builder
Build Docker images from Dockerfiles directly in the usulnet web UI. No CLI required — author, configure, and trigger image builds from the browser. Available in the Business edition.
- Dockerfile editor — Write and edit Dockerfiles in the browser with syntax highlighting. Start from scratch or use built-in Dockerfile templates for common runtimes (Node.js, Python, Go, Java, .NET).
- Multi-stage build support — Full support for multi-stage Dockerfiles. View each stage independently and inspect intermediate layers for debugging.
- Build arguments — Define and pass build-time arguments (
ARG) through the UI. Supports default values, secret arguments, and environment variable interpolation. - Platform targeting — Build images for specific platforms (
linux/amd64,linux/arm64,linux/arm/v7) or create multi-platform manifests in a single build. - Build context management — Upload build contexts from the browser or reference a Git repository as the build source. Supports
.dockerignorerules. - Real-time build logs — Stream build output in real time with per-layer progress indicators. Errors are highlighted inline with Dockerfile line references.
- Image tagging & push — Tag built images and optionally push to configured registries (Docker Hub, GHCR, self-hosted) directly from the build result page.
- Build history — Full audit trail of all builds with duration, status, image size, layer cache hits, and the Dockerfile used for each build.
Automated Rollback
Automatic stack rollback on deploy failure to keep your services running. When a deployment fails, usulnet reverts to the last known-good state without manual intervention. Available in the Business edition.
- Deploy failure rollback — If a
docker compose upfails (non-zero exit code, image pull error, or syntax error), the previous stack definition is automatically redeployed. - Health check rollback — After a successful deploy, usulnet monitors container health checks for a configurable window. If health checks fail, the stack is rolled back automatically.
- Exit code monitoring — Detects containers that start but immediately exit with error codes. Triggers rollback when critical services crash within the stabilization window.
- Configurable rollback policies — Per-stack policies control rollback behavior: enable/disable per trigger type, set health check grace periods, define stabilization windows, and configure maximum rollback attempts.
- Rollback snapshots — Every deploy creates a snapshot of the current stack state (Compose file, environment variables, image digests) so rollbacks restore the exact previous configuration.
- Manual rollback — One-click rollback to any previous deploy snapshot from the stack history page, independent of automatic triggers.
- Rollback notifications — Alerts via configured notification channels (webhook, email, Slack) when an automatic rollback is triggered, including the failure reason and affected services.
- Rollback audit log — Complete history of all rollback events with trigger reason, affected containers, rollback duration, and success/failure status.
WireGuard VPN
Native WireGuard VPN management directly from the usulnet web UI. Create, configure, and monitor WireGuard interfaces and peers without touching the command line. Available in the Business edition.
- Multi-interface management — Create and manage multiple WireGuard interfaces (wg0, wg1, etc.) independently, each with its own configuration, peers, and network settings.
- Auto-generated Curve25519 key pairs — Private and public keys are generated automatically using Curve25519 when creating interfaces or adding peers. No manual key generation required.
- Peer management with QR config generation — Add, edit, and remove peers through the UI. Generate downloadable configuration files and scannable QR codes for easy mobile and remote client setup.
- Allowed IPs and persistent keepalive settings — Configure allowed IP ranges per peer for precise traffic routing. Set persistent keepalive intervals to maintain connections behind NAT or firewalls.
- Transfer statistics (rx/tx) per interface and peer — Real-time and historical transfer statistics showing bytes received and transmitted for each interface and individual peer.
- Post-up/post-down script support for NAT/routing — Define custom post-up and post-down scripts per interface to configure iptables rules, NAT masquerading, routing tables, and other network setup on interface activation and deactivation.
- DNS configuration per interface — Set DNS servers per WireGuard interface. Configured DNS entries are included in generated peer configuration files and QR codes.
- MTU configuration — Configure the Maximum Transmission Unit per interface to optimize performance for your network environment and avoid fragmentation issues.
Container Marketplace
A curated app marketplace for deploying containerized applications with one click. Browse, search, and install pre-configured Docker Compose stacks from a community-driven catalog. Available in the Business edition.
- Searchable app catalog with category filtering — Browse the full app catalog with full-text search and filter by category to quickly find the application you need.
- Featured and verified app badges — Apps can be marked as featured (editor’s pick) or verified (tested and validated) to help users identify high-quality, reliable deployments.
- One-click Docker Compose deployment — Deploy any marketplace app with a single click. Each app includes a pre-configured Docker Compose stack that is deployed directly to your environment.
- Configurable deployment fields per app — Apps define configurable fields (ports, volumes, environment variables, passwords) that users fill in before deployment, ensuring each installation is customized to the environment.
- Installation tracking and status management — Track the installation state of every marketplace app. View which apps are installed, running, stopped, or failed, with quick links to manage deployed stacks.
- User ratings (1–5 stars) and reviews — Rate installed apps on a 1–5 star scale and write reviews. Ratings are aggregated and displayed on the app listing to guide other users.
- Community app submission — Submit your own Docker Compose stacks to the marketplace for community use. Submissions go through a review process before being published.
- App categories — Apps are organized into categories: networking, storage, development, monitoring, security, communication, productivity, and database.
GitOps & Git Sync
Synchronize Docker Compose stacks with Git repositories. Available in the Business edition.
- Repository linking — Connect stacks to Git repositories (GitHub, GitLab, Bitbucket, self-hosted)
- Auto-sync — Automatically deploy changes when the repository is updated (webhook or polling)
- Conflict detection — Detects when the live stack diverges from the Git source and prompts for resolution
- Branch selection — Deploy from any branch with configurable sync intervals
- Credential management — SSH keys and tokens stored encrypted (AES-256-GCM)
- Sync history — Full audit trail of all sync events with commit references
Ephemeral Environments
Spin up short-lived Docker environments for testing, CI/CD previews, or development. Available in the Enterprise edition.
- TTL-based lifecycle — Environments automatically expire after a configurable time-to-live
- Template-based — Create from existing stacks or templates with environment variable overrides
- Branch previews — Deploy preview environments for pull requests (Git integration required)
- Resource limits — Set CPU, memory, and storage constraints per ephemeral environment
- Dashboard — Monitor active, expired, and failed environments with real-time status
- API-driven — Full CRUD API for CI/CD pipeline integration
Manifest Builder
Visual builder for generating Docker Compose and Kubernetes manifests. Available in the Enterprise edition.
- Visual editor — Drag-and-drop service composition with real-time YAML preview
- Service templates — Pre-configured service blocks for databases, caches, web servers, etc.
- Validation — Real-time syntax and configuration validation
- Export — Download generated manifests or deploy directly as a stack
- Version history — Track changes to manifests over time
OPA Policies
Enforce organizational policies on container deployments using Open Policy Agent (OPA). Available in the Enterprise edition.
- Rego policies — Write policies in OPA's Rego language to control what can be deployed
- Pre-deployment checks — Automatically evaluate policies before container creation
- Policy library — Built-in policies for common security requirements (no privileged containers, required labels, image whitelisting)
- Violations dashboard — Track policy violations with severity and remediation guidance
- Dry-run mode — Test policies without blocking deployments
Runtime Security
Real-time container runtime monitoring and threat detection. Available in the Enterprise edition.
- Process monitoring — Track processes running inside containers
- File integrity — Detect unexpected file modifications in running containers
- Network anomalies — Monitor unexpected network connections and port usage
- Security alerts — Real-time alerts for suspicious container behavior
- Baseline profiles — Define expected behavior profiles for containers
Image Signing & Verification
Cryptographic image signing and verification using Cosign / Sigstore. Available in the Enterprise edition.
- Sign images — Sign container images with cryptographic keys
- Verify signatures — Verify image signatures before deployment
- Key management — Manage signing keys with encrypted storage
- Policy enforcement — Block deployment of unsigned or unverified images
- Transparency logs — Integration with Sigstore transparency log (Rekor)
Compliance Frameworks
Map Docker infrastructure security posture to compliance frameworks. Available in the Enterprise edition.
- CIS Docker Benchmark — Automated evaluation against CIS Docker Benchmark standards
- SOC 2 mapping — Map security controls to SOC 2 Trust Services Criteria
- PCI DSS — Container segmentation and access control requirements
- HIPAA — PHI data handling and encryption requirements
- Compliance reports — Generate exportable compliance reports for auditors
Resource Optimization
AI-powered resource analysis and right-sizing recommendations. Available in the Enterprise edition.
- Right-sizing — Recommendations for CPU and memory limits based on actual usage patterns
- Cost analysis — Estimated cost savings from resource optimization
- Over-provisioned detection — Identify containers with significantly more resources than needed
- Under-provisioned alerts — Detect containers at risk of OOM kills or CPU throttling
- Historical trends — Resource usage trends over configurable time windows
Log Aggregation & Search
Centralized log collection, indexing, and full-text search across all containers. Available in the Enterprise edition.
- Centralized collection — Aggregate logs from all containers and hosts in one place
- Full-text search — Search across all logs with regex and structured query support
- Log retention — Configurable retention policies per container or stack
- Filters — Filter by container, stack, severity, time range, and custom labels
- Export — Export log data in JSON or CSV format
Operation Modes
usulnet supports three operation modes configured via mode in config.yaml or USULNET_MODE:
| Mode | Description |
|---|---|
master | Full server deployment (default). Central control plane with all features, agent management, and API routing. |
agent | Worker node. Connects to master via NATS (with optional TLS), executes Docker operations locally, and reports status via heartbeat. |
Agent Deployment
Deploy agents from the web UI or manually.
From the Web UI
Navigate to Nodes → Add Node. Provide SSH credentials for the target host. usulnet will install Docker (if needed), deploy the agent container, and configure mTLS certificates automatically.
Manual Agent Deployment
bashdocker run -d \
--name usulnet-agent \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e USULNET_MODE=agent \
-e USULNET_NATS_URL=nats://master-ip:4222 \
-e USULNET_AGENT_NAME=worker-01 \
ghcr.io/fr4nsys/usulnet:latest
Agent Configuration
yaml# config.agent.yaml
mode: "agent"
agent:
name: "worker-01" # Unique agent name
master_url: "nats://master:4222"
heartbeat_interval: "30s"
reconnect_delay: "5s"
max_reconnect: -1 # Unlimited retries
nats:
url: "nats://master:4222"
tls:
enabled: true
cert_file: "/etc/usulnet/agent.crt"
key_file: "/etc/usulnet/agent.key"
ca_file: "/etc/usulnet/ca.crt"
Agent Events
In multi-node deployments, agent events are persisted to PostgreSQL for audit and troubleshooting. The gateway automatically stores events from remote agents based on severity and type.
Persisted Event Types
Events with operational significance are automatically persisted. These include:
- Agent lifecycle — Connected, disconnected, registered, deregistered
- Container operations — Started, stopped, created, removed, health changes
- System events — Resource threshold alerts, errors, task completions
- Security events — Scan results, policy violations
Event Attributes
| Field | Description |
|---|---|
event_type | Event type identifier (e.g., agent.connected, container.started) |
agent_id | Originating agent identifier |
host_id | Associated host UUID (if applicable) |
severity | info, warning, error, or critical |
message | Human-readable event description |
actor | Who or what triggered the event (user, system, agent) |
attributes | Key-value metadata pairs |
data | Structured event payload (JSON) |
Querying Events
Events can be filtered by host, agent, type, severity, and time range via the API:
bash# List events for a specific agent
curl -s -H "Authorization: Bearer <JWT>" \
"https://your-server:7443/api/v1/events?agent_id=worker-01&severity=error"
Old events are automatically cleaned up based on the configured retention policy.
REST API
usulnet exposes a full CRUD REST API at /api/v1. OpenAPI 3.0 spec is available at /api/v1/openapi.json and Swagger UI at /docs/api.
Base URL
https://your-server:7443/api/v1
Example: List Containers
bashcurl -s -H "Authorization: Bearer <JWT>" \
https://your-server:7443/api/v1/containers | jq
Endpoint Reference
| Resource | Endpoints | Auth Level |
|---|---|---|
| Auth | POST /auth/login, /auth/logout, /auth/refresh, /auth/2fa/* | Public / Bearer |
| Users | GET|POST /users, GET|PUT|DELETE /users/:id | Admin |
| Containers | GET /containers/:hostID, POST /:id/start|stop|restart|kill|remove | Viewer / Operator |
| Images | GET /images/:hostID, POST /pull|push, GET /:id/update-check | Viewer / Operator |
| Volumes | GET|POST /volumes/:hostID, DELETE /:id | Viewer / Operator |
| Networks | GET|POST /networks/:hostID, DELETE /:id | Viewer / Operator |
| Stacks | GET|POST /stacks, GET|PUT|DELETE /stacks/:id, POST /:id/deploy|stop | Viewer / Operator |
| Hosts | GET|POST /hosts, GET|PUT|DELETE /hosts/:id | Viewer / Admin |
| Backups | GET|POST /backups, POST /:id/restore, DELETE /:id | Viewer / Operator |
| Security | POST /security/scan, GET /security/reports, GET /security/sbom/:id | Viewer / Operator |
| Monitoring | GET|POST /notifications/channels, GET|POST /notifications/rules | Viewer / Operator |
| Registries | GET|POST /registries, GET /:id/repositories, GET /.../tags | Viewer / Operator |
| Templates | GET /templates, POST /templates/import, GET /templates/export | Viewer / Operator |
| Dashboards | GET|POST /dashboards/layouts, GET|POST /.../widgets | Enterprise |
| Audit | GET /audit/logs | Admin |
| Proxy | GET|POST /proxy/hosts, GET /proxy/health | Viewer / Operator |
| SSH | GET|POST /ssh/keys, GET|POST /ssh/connections | Operator |
| Calendar | GET|POST /calendar/events, GET|POST /calendar/tasks, GET|POST /calendar/notes | Viewer / Operator |
| Changes | GET /changes, GET /changes/stats | Viewer |
| Drift | GET /drift/check, POST /drift/scan | Enterprise |
| GitOps | GET|POST /gitsync/repos, POST /:id/sync | Business |
| Ephemeral | GET|POST /ephemeral/envs, DELETE /:id | Enterprise |
| Manifests | GET|POST /manifests, POST /:id/build | Enterprise |
| Remote Desktop | GET|POST /guacamole/connections, WS /guacamole/ws | Operator |
| Settings | GET|PUT /settings | Admin |
| License | GET|POST|DELETE /license, GET /license/status | Admin |
All paginated endpoints support ?page= and ?per_page= query parameters. Responses include total, page, per_page, and total_pages metadata. Swagger UI is available at /docs/api.
API Authentication
Two authentication methods are supported:
| Method | Header | Format |
|---|---|---|
| JWT Bearer Token | Authorization | Bearer <token> |
| API Key | X-API-KEY | <api-key> |
Obtain a JWT
bashcurl -s -X POST https://your-server:7443/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"usulnet"}' | jq .token
WebSocket API
Real-time streams are available via WebSocket:
| Endpoint | Description |
|---|---|
/api/v1/ws/containers/:id/logs | Live container log streaming |
/api/v1/ws/containers/:id/exec | Interactive container terminal |
/api/v1/ws/containers/:id/stats | Real-time container stats |
/api/v1/ws/events | Docker event stream |
/api/v1/ws/terminal | Host SSH terminal |
/api/v1/ws/guacamole | Remote desktop session (RDP/VNC) |
/api/v1/ws/nvim | Neovim terminal session |
CLI Commands
The usulnet binary provides several subcommands for server management, database migrations, configuration validation, and admin operations.
serve
Start the usulnet server.
bash# Start in master mode (default)
./bin/usulnet serve
# Start in master mode
./bin/usulnet serve --mode master
# Start in agent mode
./bin/usulnet serve --mode agent
# Use a custom config file
./bin/usulnet serve --config /etc/usulnet/config.yaml
| Flag | Short | Default | Description |
|---|---|---|---|
--mode | -m | master | Operation mode: master or agent |
--config | -c | auto-detect | Path to config file (/etc/usulnet/config.yaml or ./config.yaml) |
--component | Component to run: api, gateway, scheduler (master mode only) |
migrate
Database migration commands. Migrations are embedded in the binary and run automatically on startup, but you can manage them manually.
bash# Apply all pending migrations
./bin/usulnet migrate up
# Roll back the last migration
./bin/usulnet migrate down
# Roll back the last 3 migrations
./bin/usulnet migrate down 3
# Show migration status
./bin/usulnet migrate status
config
Configuration validation and inspection commands.
bash# Validate the configuration file
./bin/usulnet config check
# Show current configuration (sensitive values masked)
./bin/usulnet config show
# Validate a specific config file
./bin/usulnet config check --config /path/to/config.yaml
| Subcommand | Description |
|---|---|
config check | Validates the config file structure and required fields. Prints "Configuration is valid" on success, or a detailed error message. |
config show | Prints the resolved configuration with secrets masked (JWT secret, encryption keys, database passwords). |
admin
Administrative operations that run directly against the database without starting the full server.
bash# Reset admin password (generates a random password)
./bin/usulnet admin reset-password
# Reset admin password with a specific value
./bin/usulnet admin reset-password MyNewSecurePassword123
# From Docker
docker exec usulnet-app /app/usulnet admin reset-password
| Subcommand | Description |
|---|---|
admin reset-password [PASSWORD] | Reset the admin user's password. Creates the admin user if it doesn't exist. Unlocks the account if locked due to failed login attempts. If no password is provided, generates and prints a secure random password. |
version
bash./bin/usulnet version
Prints version, commit hash, build time, and Go version.
RBAC Permissions Reference
usulnet provides 46 granular permissions across 13 categories. In the Business and Enterprise editions, you can create custom roles with any combination of these permissions.
| Category | Permission | Description |
|---|---|---|
| Containers | container:view | View container list and details |
container:create | Create new containers | |
container:start | Start stopped containers | |
container:stop | Stop running containers | |
container:restart | Restart containers | |
container:remove | Delete containers | |
container:exec | Execute commands inside containers | |
container:logs | View container logs | |
| Images | image:view | View image list and details |
image:pull | Pull images from registries | |
image:remove | Delete images | |
image:build | Build images from Dockerfiles | |
| Volumes | volume:view | View volume list and details |
volume:create | Create new volumes | |
volume:remove | Delete volumes | |
| Networks | network:view | View network list and details |
network:create | Create new networks | |
network:remove | Delete networks | |
| Stacks | stack:view | View stack list and details |
stack:deploy | Deploy new stacks | |
stack:update | Update existing stacks | |
stack:remove | Delete stacks | |
| Hosts | host:view | View host list and details |
host:create | Add new hosts | |
host:update | Update host settings | |
host:remove | Remove hosts | |
| Users | user:view | View user list and details |
user:create | Create new users | |
user:update | Update user settings | |
user:remove | Delete users | |
| Roles | role:view | View role list and details |
role:create | Create new roles | |
role:update | Update role permissions | |
role:remove | Delete custom roles | |
| Settings | settings:view | View system settings |
settings:update | Modify system settings | |
| Backups | backup:view | View backup list and details |
backup:create | Create new backups | |
backup:restore | Restore from backups | |
| Security | security:view | View security scan results |
security:scan | Run security scans | |
| Config | config:view | View configuration templates |
config:create | Create configuration templates | |
config:update | Update configuration templates | |
config:remove | Delete configuration templates | |
| Audit | audit:view | View audit logs |
Built-in Roles
| Role | Description | Permissions |
|---|---|---|
admin | Full system access | All 46 permissions |
operator | Operational access (no user/role/settings management) | Container, image, volume, network, stack, backup, security operations |
viewer | Read-only access | All *:view permissions |
Notification Channels
usulnet supports 11 notification channels for monitoring alerts, backup status, and system events.
| Channel | Configuration | Notes |
|---|---|---|
| SMTP host, port, username, password, from address | Supports TLS/STARTTLS. Templates for each alert type. | |
| Slack | Webhook URL | Rich message formatting with severity colors. |
| Discord | Webhook URL | Embed-based messages with metadata fields. |
| Telegram | Bot token, chat ID | Markdown-formatted messages. |
| Gotify | Server URL, application token | Priority mapping from alert severity. |
| ntfy | Server URL, topic | Supports priority, tags, and actions. |
| PagerDuty | Integration key (Events API v2) | Auto-resolves when alert clears. |
| Opsgenie | API key | Priority mapping, auto-close on resolve. |
| Microsoft Teams | Webhook URL | Adaptive Card format. |
| Webhook | URL, optional headers, optional secret | JSON payload with HMAC-SHA256 signature when secret is configured. |
| Custom | URL, method, headers, body template | Fully configurable HTTP request with Go template variables. |
Security Hardening
Recommended security practices for production deployments.
Secrets Management
- Generate unique secrets for every deployment:
openssl rand -hex 32 - Never commit secrets to version control. Use environment variables or Docker secrets.
- Rotate the JWT secret periodically. All active sessions will be invalidated.
- The
config_encryption_keyencrypts stored credentials (registry passwords, SMTP passwords, etc.). Changing it invalidates all stored secrets.
Network Security
- Use HTTPS in production. The auto-generated self-signed cert is suitable for internal use; use Let's Encrypt via the built-in Nginx proxy for public-facing instances.
- Bind to
127.0.0.1and use a reverse proxy if not exposing directly. - The Docker socket (
/var/run/docker.sock) grants root-equivalent access. Mount it read-only (:ro) and restrict container access with network policies. - In multi-node setups, always enable NATS mTLS. The built-in PKI auto-generates certificates.
Authentication
- Change the default admin password immediately after first login.
- Enable TOTP 2FA for all admin accounts.
- Set
password_min_lengthto at least 12 for production. - Configure account lockout:
max_failed_logins: 5andlockout_duration: "15m". - Use API keys instead of JWT tokens for automated/CI integrations.
Docker Socket Security
Access to the Docker socket is equivalent to root access on the host. Only trusted users should have container management permissions. Use RBAC to restrict who can create containers and exec into them.
Production Deployment Guide
Recommendations for deploying usulnet in production.
Infrastructure Requirements
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| Memory | 2 GB | 4+ GB |
| Disk | 20 GB | 50+ GB (depends on backup storage) |
| PostgreSQL | 16+ | 16+ (with TLS) |
| Redis | 8+ | 8+ (with TLS) |
| Docker | 24+ | 29+ |
Recommended Configuration
yaml# Production config.yaml highlights
server:
tls:
enabled: true
auto_tls: true
read_timeout: "30s"
write_timeout: "60s"
database:
max_open_conns: 25
max_idle_conns: 10
conn_max_lifetime: "30m"
security:
jwt_secret: "${USULNET_SECURITY_JWT_SECRET}"
config_encryption_key: "${USULNET_SECURITY_CONFIG_ENCRYPTION_KEY}"
cookie_secure: true
password_min_length: 12
max_failed_logins: 5
lockout_duration: "15m"
logging:
level: "info"
format: "json"
metrics:
enabled: true
Health Checks
usulnet exposes health check endpoints for container orchestrators and load balancers:
| Endpoint | Description | Use Case |
|---|---|---|
/health, /healthz | Full health with component details (DB, Redis, Docker, NATS, disk space) | Monitoring dashboards |
/api/v1/system/health/live | Simple liveness probe (always 200 if process is running) | Kubernetes livenessProbe |
/api/v1/system/health/ready | Readiness probe (checks all components) | Kubernetes readinessProbe, load balancer health |
Backup Strategy
- Configure automated backups with at least daily frequency.
- Use S3-compatible storage (MinIO, AWS S3) for offsite backups.
- Enable AES-256-GCM encryption for all backup archives.
- Set retention to at least 30 days:
storage.backup.default_retention_days: 30. - Test restore procedures periodically to verify backup integrity.
Docker Compose (Production)
yamlservices:
usulnet:
image: ghcr.io/fr4nsys/usulnet:latest
restart: unless-stopped
ports:
- "8080:8080" # HTTP (admin UI)
- "7443:7443" # HTTPS (admin UI, auto-TLS)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- usulnet-data:/var/lib/usulnet
- nginx-conf:/etc/nginx/conf.d/usulnet
- nginx-certs:/etc/usulnet/certs
- acme-webroot:/var/lib/usulnet/acme
environment:
- USULNET_DATABASE_URL=postgres://usulnet:${DB_PASSWORD}@postgres:5432/usulnet?sslmode=require
- USULNET_REDIS_URL=rediss://redis:6379/0
- USULNET_NATS_URL=nats://nats:4222
- USULNET_SECURITY_JWT_SECRET=${JWT_SECRET}
- USULNET_SECURITY_CONFIG_ENCRYPTION_KEY=${ENCRYPTION_KEY}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
nginx:
image: nginx:1.28-alpine
restart: unless-stopped
ports:
- "80:80" # Public HTTP (ACME challenges + redirect)
- "443:443" # Public HTTPS (reverse proxy)
volumes:
- nginx-conf:/etc/nginx/conf.d/usulnet:ro
- nginx-certs:/etc/usulnet/certs:ro
- acme-webroot:/var/lib/usulnet/acme:ro
depends_on:
- usulnet
guacd:
image: guacamole/guacd:1.6.0
restart: unless-stopped # RDP/VNC gateway
postgres:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: usulnet
POSTGRES_USER: usulnet
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U usulnet"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:8-alpine
restart: unless-stopped
volumes:
- redis-data:/data
command: redis-server --appendonly yes
nats:
image: nats:2.12-alpine
restart: unless-stopped
command: ["--jetstream", "--store_dir", "/data"]
volumes:
- nats-data:/data
volumes:
usulnet-data:
postgres-data:
redis-data:
nats-data:
nginx-conf:
nginx-certs:
acme-webroot:
Upgrade Guide
usulnet follows semantic versioning. Database migrations run automatically on startup, so upgrades are typically seamless.
Docker Compose Upgrade
bash# Pull the latest image
docker compose pull usulnet
# Restart with zero downtime (recreates only the usulnet container)
docker compose up -d usulnet
Before Upgrading
- Read the changelog — Check the CHANGELOG.md for breaking changes.
- Back up the database —
pg_dump -U usulnet usulnet > backup.sql - Back up the data volume —
docker run --rm -v usulnet-data:/data -v $(pwd):/backup alpine tar czf /backup/data-backup.tar.gz -C /data .
Rollback
If something goes wrong after upgrading:
bash# Pin to the previous version
docker compose pull usulnet # edit image tag first
docker compose up -d usulnet
# Roll back migrations if needed
docker exec usulnet-app /app/usulnet migrate down
Rolling back migrations may cause data loss for features added in newer versions. Always back up before upgrading.
Troubleshooting
Connection Refused on Port 7443
The HTTPS port requires TLS to be enabled (default). Verify with:
bashcurl -sk https://localhost:7443/health | jq
If you disabled TLS, only port 8080 (HTTP) is active.
Database Connection Failed
- Check that PostgreSQL is running:
docker compose ps postgres - Verify the connection string:
docker exec usulnet-app /app/usulnet config show - Check PostgreSQL logs:
docker compose logs postgres - Ensure the database exists:
docker exec postgres psql -U usulnet -c '\l'
Admin Account Locked Out
After too many failed login attempts, the account is locked. Reset from the command line:
bashdocker exec usulnet-app /app/usulnet admin reset-password NewPassword123
This resets the password and unlocks the account.
Docker Socket Permission Denied
The usulnet container needs access to the Docker socket. Ensure it's mounted correctly:
yamlvolumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
If running rootless Docker, the socket path may differ (e.g., /run/user/1000/docker.sock).
Trivy Scanner Not Available
Trivy is included in the Docker image but not in the standalone binary. If you see "Trivy not available", install it on the host or use the Docker image. Security scanning is a non-blocking feature — usulnet starts normally without Trivy.
Agent Not Connecting to Master
- Verify NATS is reachable from the agent:
nats-cli server ping - Check the agent logs:
docker logs usulnet-agent - Ensure
USULNET_NATS_URLpoints to the master's NATS server - If using mTLS, verify certificates are valid and the CA matches
High Memory Usage
- Check container metrics in the dashboard — usulnet itself typically uses 100-200 MB
- PostgreSQL may need tuning for large deployments: increase
shared_buffersandwork_mem - Reduce the number of open WebSocket connections (container stats, logs)
- Set
logging.level: "info"in production (debug logging is verbose)
Migration Failed
bash# Check current migration status
docker exec usulnet-app /app/usulnet migrate status
# Force re-run after fixing the issue
docker exec usulnet-app /app/usulnet migrate up
If a migration is stuck in a dirty state, you may need to manually fix the schema_migrations table in PostgreSQL.
Migrations
usulnet includes 44 database migrations embedded in the binary. Migrations run automatically on startup and are idempotent (safe to re-run).
bash# Apply all pending migrations
./bin/usulnet migrate up
# or via Make
make migrate
# Roll back last migration
./bin/usulnet migrate down
# or via Make
make migrate-down
# Check migration status
./bin/usulnet migrate status
# or via Make
make migrate-status
Each migration has an up and down pair. Migration files follow the naming convention NNN_description.up.sql / NNN_description.down.sql and are located in internal/repository/postgres/migrations/.
Licensing
usulnet uses a three-tier licensing model:
| Edition | License | Limits | Key Features |
|---|---|---|---|
| Community (CE) | AGPLv3 | 1 node, 3 users, 1 team, 1 role | Full Docker management, security scanning, monitoring, terminal, remote desktop, backups, reverse proxy, DNS server, developer tools, calendar |
| Business | Commercial | Per-node, configurable users | CE + template catalog, registry browsing, OAuth/OIDC, LDAP, RBAC, Git sync, import/export, Swarm management |
| Enterprise | Commercial | Unlimited | Business + custom dashboards, agent events, compliance, OPA policies, runtime security, image signing, ephemeral environments, manifest builder, log aggregation, resource optimization, drift detection |
Instance Binding
Each license key can be active on exactly one instance at a time. Attempting to activate a key already bound to another host returns a 409 Conflict error. You must release the existing instance first — either from the dashboard or remotely from the License Portal.
Activation
- Purchase at usulnet.com/pricing
- Retrieve your JWT license key from the License Portal
- In your usulnet dashboard, go to Settings → License → Activate
- Paste the JWT and click Activate
On activation, the application contacts api.usulnet.com to register the instance and receives a signed Activation Receipt — a short-lived JWT (7-day TTL, RS512) cryptographically bound to the instance fingerprint. The receipt carries the server-signed edition limits, so limits cannot be altered locally without the server private key.
Background Sync
A background process renews the Activation Receipt every 6 hours. If api.usulnet.com cannot be reached:
| Time without sync | Behavior |
|---|---|
| 0 – 7 days | Normal operation using the cached receipt |
| 7 – 14 days | Sync warning banner displayed in the dashboard; functionality unchanged |
| > 14 days | Automatic downgrade to Community Edition until connectivity is restored and the license is re-activated |
Releasing an Instance Remotely
If the host is no longer accessible, you can release the binding from the portal:
- Sign in at id.usulnet.com with your purchase email
- Click Release Instance next to the active license
- The release takes effect on the next check-in cycle (up to 6 hours)
- The portal shows Release pending (< 6 h) until confirmed
- Once released, the key can be activated on a new host
Deactivating from the Dashboard
Go to Settings → License → Deactivate. This immediately clears the binding on the server and reverts the instance to Community Edition.
License API
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/license | Current license info (edition, limits, instance ID, sync status) |
POST | /api/v1/license | Activate a license key |
DELETE | /api/v1/license | Deactivate and revert to CE |
GET | /api/v1/license/status | Detailed status including sync degradation state and active limits |
Only the minimum data required for instance binding is transmitted during activation and check-ins: the license ID and an opaque instance fingerprint (a hash of persistent host identifiers). No usage data, container names, hostnames, or behavioral data are ever sent. Community Edition is fully offline — no network calls are made.