A fresh panel no longer lets whoever reaches it first become admin: registering the first account needs a one-time code the installer prints (`serverkit setup-code` repeats it). SERVERKIT_ADMIN_EMAIL and SERVERKIT_ADMIN_PASSWORD create the admin unattended instead. Git apps now deploy what users expect: a repository with a compose file deploys every service it declares, "Deploy latest" builds the branch's newest commit, and push webhooks rebuild the containers. Also fixes branch switching on single-branch clones, uploads of a lone file, compose v1 port preflight, and CLI commands that ignored their flags.
10 KiB
ServerKit Deployment Guide
Complete guide for deploying ServerKit on Ubuntu servers.
Deployment model (important)
ServerKit's backend manages the host it runs on — it creates app
directories under /var/serverkit/apps, drives the host Docker daemon (one
container per managed app), reloads nginx, and runs systemctl/firewall/PHP-FPM.
A backend running inside a container cannot do any of that. So the canonical
deployment installed by ./serverkit install (install.sh) runs fully off
Docker for the panel itself:
- the backend on the host via systemd (
serverkit.service), and - the frontend as static files served directly by host nginx from
frontend/dist(built byinstall.sh) — no container. Host nginx serves the SPA atlocation /and proxies/api+/socket.ioto the host backend on:5000.
Docker is therefore used only for the workloads you host (one container per managed app). This is deliberate: a ServerKit update never touches those containers, and host nginx — which reverse-proxies them — is only ever reloaded, never stopped, so updating the panel causes zero downtime for hosted apps.
Do not add the backend into Docker — a containerized backend fails
app/WordPress creation with Permission denied: /var/serverkit/apps/... and has
no access to the host Docker daemon. A containerized frontend is still
available as an opt-in escape hatch (docker compose --profile legacy-frontend up -d, plus repointing nginx location / at 127.0.0.1:3847) but is not used
by the default install. The single-container image in ./Dockerfile exists only
for throwaway demos and, as its header states, cannot manage the host.
Quick Install (Ubuntu)
# One-line install
curl -fsSL https://serverkit.ai/install.sh | bash
# Or clone and install manually
git clone https://github.com/jhd3197/serverkit.git
cd serverkit
chmod +x serverkit
./serverkit install
Prerequisites
- Ubuntu 20.04+ (or Debian 11+)
- Docker 20.10+ and Docker Compose 2.0+
- At least 1GB RAM
- Domain name (for SSL/HTTPS)
CLI Commands
ServerKit includes a management CLI for common administrative tasks.
Service Management
# Start/Stop/Restart
serverkit start
serverkit stop
serverkit restart
# View status
serverkit status
# View logs
serverkit logs # All services
serverkit logs backend # Backend only
serverkit logs frontend # Frontend only
# Update to latest version
serverkit update
# Uninstall
serverkit uninstall
User Management
# Show the setup code the first admin registration needs
serverkit setup-code
# Create admin user
serverkit create-admin
# Prompts for: email, username, password
# (or: serverkit create-admin --email a@b.com --username admin --password '...')
# Reset a user's password
serverkit reset-password
# Prompts for: email, new password
# Unlock a locked account (after failed login attempts)
serverkit unlock-user
# Prompts for: email
# List all users
serverkit list-users
# Promote user to admin
serverkit make-admin
# Prompts for: email
# Deactivate/Activate user
serverkit deactivate-user
serverkit activate-user
Database Management
# Initialize database
serverkit init-db
# Apply database migrations (after updates)
serverkit migrate-db
# Backup database
serverkit backup-db
# Creates: backup/serverkit-YYYYMMDD-HHMMSS.db
# Restore from backup
serverkit restore-db backup/serverkit-20240115-120000.db
App & Cleanup Commands
# List all installed applications (from database)
serverkit list-apps
# Also show all Docker containers (including infrastructure)
serverkit list-apps --all
# Delete all apps, containers, folders, and orphaned Docker resources
serverkit cleanup-apps
# Also delete Docker volumes
serverkit cleanup-apps --delete-volumes
# Keep database records (only delete containers/folders)
serverkit cleanup-apps --keep-db
# Complete factory reset (delete everything and start fresh)
# Preserves only serverkit-frontend infrastructure
serverkit factory-reset
Note: Cleanup commands will:
- Stop and remove all app containers
- Remove orphaned Docker containers (not tracked in database)
- Prune unused Docker networks
- Delete all folders in
/var/serverkit/apps/ - Never touch ServerKit infrastructure (serverkit-frontend, serverkit-network)
Utility Commands
# Generate secure keys for .env
serverkit generate-keys
# Edit configuration
serverkit config
# Open shell in backend container
serverkit shell
# Show help
serverkit help
Manual Installation
1. Install Docker
# Install Docker
curl -fsSL https://get.docker.com | sh
# Add user to docker group
sudo usermod -aG docker $USER
# Log out and back in, then verify
docker --version
2. Clone Repository
git clone https://github.com/jhd3197/serverkit.git /opt/serverkit
cd /opt/serverkit
3. Configure Environment
# Generate secure keys
serverkit generate-keys
# Create .env file
cat > .env << 'EOF'
SECRET_KEY=<paste-generated-key>
JWT_SECRET_KEY=<paste-generated-key>
DATABASE_URL=sqlite:///serverkit.db
CORS_ORIGINS=https://yourdomain.com
PORT=80
SSL_PORT=443
FLASK_ENV=production
EOF
4. SSL Certificate Setup
Option A: Let's Encrypt (Recommended)
# Install certbot
sudo apt install certbot
# Get certificate (stop any service on port 80 first)
sudo certbot certonly --standalone -d yourdomain.com
# Copy certificates
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem nginx/ssl/
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem nginx/ssl/
sudo chown -R $USER:$USER nginx/ssl/
Option B: Self-Signed (Development Only)
mkdir -p nginx/ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout nginx/ssl/privkey.pem \
-out nginx/ssl/fullchain.pem \
-subj "/CN=localhost"
5. Build and Start
Both panel tiers run on the host: the backend under systemd
(serverkit.service) and the frontend as static files served by host nginx from
frontend/dist. ./serverkit install builds the bundle and wires nginx for
you. See the Deployment model note above.
# Build the SPA bundle host nginx serves (install.sh does this automatically)
cd frontend && npm ci && npm run build && cd ..
# Start the host backend + nginx
sudo systemctl start serverkit
sudo systemctl reload nginx
# Verify
serverkit status
6. Create Admin User
serverkit create-admin
Systemd Service
Run ServerKit as a system service:
# Copy service file
sudo cp deploy/serverkit.service /etc/systemd/system/
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable serverkit
sudo systemctl start serverkit
# Check status
sudo systemctl status serverkit
Configuration Reference
Environment Variables
| Variable | Description | Default |
|---|---|---|
SECRET_KEY |
Flask secret key | Required |
JWT_SECRET_KEY |
JWT signing key | Required |
DATABASE_URL |
Database connection string | sqlite:///serverkit.db |
CORS_ORIGINS |
Allowed CORS origins | http://localhost |
PORT |
HTTP port | 80 |
SSL_PORT |
HTTPS port | 443 |
FLASK_ENV |
Environment mode | production |
Host data locations
The backend runs on the host, so its data lives on the host filesystem (not in Docker volumes):
| Path | Purpose |
|---|---|
/opt/serverkit/backend/instance/serverkit.db |
SQLite database (default) |
/var/serverkit/apps/ |
Managed app directories (one per app) |
/etc/serverkit/ |
Config (templates, ssl-mode, install state) |
/var/backups/serverkit/ |
Backups |
Common Tasks
Auto-renew SSL Certificate
Certbot installs its own renewal timer, and host nginx reads the certificates
straight out of /etc/letsencrypt/live/, so there is nothing to copy and no
container to restart. Verify it is armed:
# The renewal timer certbot installed
systemctl list-timers | grep certbot
# Dry-run a renewal without touching the live certificate
sudo certbot renew --dry-run
Only if the timer is missing, add a cron entry that reloads host nginx:
sudo crontab -e
# Renew at 2:30 AM daily, reload nginx only when something actually renewed
30 2 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
Change Domain
- Update
.envfile:CORS_ORIGINS=https://newdomain.com - Get new SSL certificate
- Restart:
serverkit restart
Scale for Production
For high-traffic deployments, consider:
# Use PostgreSQL instead of SQLite
DATABASE_URL=postgresql://user:pass@localhost:5432/serverkit
# Add Redis for session storage
# Edit docker-compose.yml to add redis service
Troubleshooting
Panel won't start
This guide covers the host install, where the panel is a systemd service and
not a container — do not reach for docker compose here, it would build a second,
separate all-in-one panel beside this one.
# Check logs
serverkit logs backend
# Restart the service
serverkit restart
serverkit status
# Deeper diagnosis
serverkit doctor
Permission denied errors
# Fix Docker socket permissions
sudo chmod 666 /var/run/docker.sock
# Or add user to docker group
sudo usermod -aG docker $USER
# Then log out and back in
Port already in use
# Find what's using port 80 (host nginx) or 5000 (the panel backend)
sudo lsof -i :80
sudo lsof -i :5000
Reset everything
# Delete all managed apps, containers, folders and orphaned Docker resources
serverkit factory-reset
# Bring the panel back up
serverkit start
serverkit init-db
serverkit create-admin
Locked out / Forgot password
# Reset password via CLI
serverkit reset-password
# Enter email and new password
# Or unlock account if locked
serverkit unlock-user
Security Checklist
- Generated unique SECRET_KEY and JWT_SECRET_KEY
- Using HTTPS with valid SSL certificate
- Firewall configured (allow only ports 80, 443, 22)
- Regular backups configured
- Admin password is strong
- Updated to latest version
Support
- GitHub Issues: https://github.com/jhd3197/serverkit/issues
- Documentation: https://github.com/jhd3197/serverkit/wiki