
This article provides a guide demonstrating how to deploy Kubeara PaaS on Ubuntu VPS.
Introduction
Kubeara is an open-source, self-hosted Platform-as-a-Service designed to deploy and manage applications, databases, infrastructure services, and AI workloads on privately controlled servers.
Unlike platforms focused primarily on conventional web applications, Kubeara emphasizes private infrastructure use cases such as:
- PostgreSQL, Redis, Kafka, and other data services
- Next.js, React, and NestJS applications
- Workflow and automation platforms
- Self-hosted AI models
- GPU monitoring and VRAM validation
- Multi-server infrastructure management
- MCP-based infrastructure administration
- Centralized logs, metrics, restarts, and updates
Kubeara currently advertises more than 200 preconfigured service templates. Its self-hosted edition is MIT licensed and can be operated on infrastructure you control.
This guide deploys the Kubeara control plane on an Ubuntu 24.04 VPS using:
- Docker Engine
- Docker Compose
- Kubearaās official installer
- Nginx as a reverse proxy
- Letās Encrypt SSL
- A dedicated hostname such as
kubeara.example.com
Prerequisites ā Deployment architecture
The official Kubeara installer creates a Docker Compose deployment containing three principal services:
| Service | Default port | Purpose |
|---|---|---|
| Kubeara console | 8080 | Web-based administration interface |
| Kubeara control-panel API | 3000 | Backend API and health endpoint |
| PostgreSQL | 5432 | Kubeara configuration database |
The installer places the deployment files under:
/opt/kubeara/control-panel
when run as root. It generates encryption and JWT secrets, pulls the required Docker images, starts the containers, runs database migrations, and seeds the service templates.
For a production deployment, Nginx will provide a single public endpoint:
https://kubeara.example.com
Traffic will be routed as follows:
https://kubeara.example.com/ -> Kubeara console on 127.0.0.1:8080 https://kubeara.example.com/api/ -> Kubeara API on 127.0.0.1:3000
PostgreSQL should not be reachable from the public Internet.
Prerequisites ā VPS requirements
Recommended minimum
For a small evaluation or control-plane-only deployment:
- 2 virtual CPU cores
- 4 GB RAM
- 40 GB SSD storage
- 64-bit x86_64 or ARM64 processor
- Ubuntu 24.04 LTS
- Public IPv4 address
- Root or sudo access
For production use or running workloads on the same VPS:
- 4 or more CPU cores
- 8 GB or more RAM
- 80 GB or more SSD storage
- Separate storage or backup destination
- Additional RAM and disk according to deployed services
A database, AI model, or analytics platform may require substantially more resources than the Kubeara control plane itself.
Kubearaās installer detects both AMD64 and ARM64 systems and selects the appropriate Docker platform automatically.
See Also: Easily Deploy NodeBB Community Forum on Ubuntu VPS
Required ports
Allow these public inbound ports:
| Port | Protocol | Purpose |
|---|---|---|
| 22 | TCP | SSH administration |
| 80 | TCP | HTTP and Letās Encrypt validation |
| 443 | TCP | Kubeara HTTPS interface |
Ports 3000, 8080, and 5432 should not remain publicly accessible after the reverse proxy is configured.
Prerequisites ā Prepare the DNS record
Create an A record for the hostname that will host Kubeara.
Example:
Type: A Name: kubeara Value: 203.0.113.10 TTL: 300
Replace 203.0.113.10 with the VPS public IPv4 address.
The result should be:
kubeara.example.com -> 203.0.113.10
Verify the record:
dig +short kubeara.example.com
Or:
getent hosts kubeara.example.com
Do not request the SSL certificate until the hostname resolves to the VPS.
Compare Ubuntu VPS Plans
How to Deploy Kubeara PaaS on an Ubuntu VPS
To deploy Kubeara PaaS on Ubuntu VPS, follow the steps outlined below:
-
Connect to the VPS
Connect as root:
ssh root@203.0.113.10
Alternatively, connect as a sudo-capable user:
ssh administrator@203.0.113.10
Then obtain a root shell:
sudo -i
-
Update Ubuntu
Update the package metadata and installed packages:
apt update apt upgrade -y
Install commonly required utilities:
apt install -y \ ca-certificates \ curl \ gnupg \ openssl \ unzip \ nano \ jq \ ufwReboot if the update installed a new kernel:
reboot
Reconnect after the server restarts.
-
Configure the hostname and time zone
Set a descriptive hostname:
hostnamectl set-hostname kubeara01.example.com
Set the server time zone:
timedatectl set-timezone America/Chicago
Verify:
hostnamectl timedatectl
The serverās internal hostname does not have to match the public Kubeara URL, but using a valid fully qualified hostname simplifies administration.
-
Configure the Ubuntu firewall
Before enabling UFW, explicitly permit SSH:
ufw allow OpenSSH
Permit HTTP and HTTPS:
ufw allow 80/tcp ufw allow 443/tcp
Enable the firewall:
ufw enable
Verify the rules:
ufw status verbose
Expected public services:
22/tcp ALLOW 80/tcp ALLOW 443/tcp ALLOW
Important Docker firewall consideration
Docker-published ports can bypass ordinary UFW filtering because Docker inserts its own packet-filtering rules. Dockerās documentation specifically warns that exposed container ports may not behave as expected with UFW or firewalld.
For that reason, this guide later changes the Kubeara Compose file so its internal services bind only to
127.0.0.1. -
Install Docker Engine
Remove potentially conflicting packages:
apt remove -y \ docker.io \ docker-compose \ docker-compose-v2 \ docker-doc \ podman-docker \ containerd \ runc 2>/dev/null || trueCreate the Docker keyring directory:
install -m 0755 -d /etc/apt/keyrings
Download Dockerās signing key:
See Also: Install and Run Your Own Image and Video Sharing Platform on Ubuntu VPS
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.ascMake the key readable:
chmod a+r /etc/apt/keyrings/docker.asc
Add Dockerās official Ubuntu repository:
cat > /etc/apt/sources.list.d/docker.sources <
Update package metadata:
apt update
Install Docker Engine and the Compose plugin:
apt install -y \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-pluginThese package names and repository steps follow Dockerās current official Ubuntu installation procedure.
Enable Docker at startup:
systemctl enable --now docker
Verify Docker:
docker version docker compose version systemctl status docker --no-pager
Run a test container:
docker run --rm hello-world
-
Inspect the Kubeara installer before running it
The official quick-start command is:
curl -fsSL https://get.kubeara.dev | sh
The project recommends reviewing the installer before executing it.
Download it locally first:
curl -fsSL https://get.kubeara.dev -o /root/kubeara-install.sh
Inspect the beginning of the script:
less /root/kubeara-install.sh
Optionally calculate its checksum for your records:
sha256sum /root/kubeara-install.sh
Make it executable:
chmod 700 /root/kubeara-install.sh
-
Run the Kubeara installer
Set the public control-panel URL while running the installer:
KUBEARA_PUBLIC_URL="https://kubeara.example.com" \ KUBEARA_INSTALL_DIR="/opt/kubeara/control-panel" \ bash /root/kubeara-install.sh
Replace
kubeara.example.comwith your actual hostname.The installer should:
- Verify Docker is installed and running.
- Verify Docker Compose v2 is available.
- Create
/opt/kubeara/control-panel. - Write the Docker Compose configuration.
- Generate the environment file.
- Generate an encryption secret.
- Generate JWT access and refresh secrets.
- Pull the Kubeara console, API, agent, and PostgreSQL images.
- Start the containers.
- Run database migrations.
- Seed Kubearaās templates.
- Test the API health endpoint.
The installer checks:
http://127.0.0.1:3000/api/health
and waits up to approximately two minutes for the API to respond.
At completion, it should report locations similar to:
Install directory: /opt/kubeara/control-panel Control panel API: http://127.0.0.1:3000 Console (SPA): http://127.0.0.1:8080
-
Review the generated files
Enter the deployment directory:
cd /opt/kubeara/control-panel
List the files:
ls -la
You should see files such as:
.env.control-panel docker-compose.control-panel.yml
Protect the environment file:
chown root:root .env.control-panel chmod 600 .env.control-panel
Review its variable names without printing secret values:
grep -E '^[A-Z0-9_]+=' .env.control-panel | cut -d= -f1
The generated file normally includes:
KUBEARA_CONTROL_PANEL_IMAGE KUBEARA_CONSOLE_IMAGE KUBEARA_AGENT_IMAGE DOCKER_PLATFORM PORT CONSOLE_PORT VITE_API_URL CONTROL_PANEL_URL ENCRYPTION_SECRET JWT_SECRET JWT_REFRESH_SECRET DB_HOST DB_PORT DB_USERNAME DB_PASSWORD DB_DATABASE
The installer warns that the encryption secret must be preserved because the same value may be required when agents are installed later.
See Also: š How to Deploy KumoMTA on Rocky Linux VPS (Easy Step-by-Step Guide)
Back up the environment file securely:
install -m 700 -d /root/kubeara-secrets cp -a .env.control-panel /root/kubeara-secrets/ chmod 600 /root/kubeara-secrets/.env.control-panel
Do not commit this file to Git or store it in a publicly accessible location.
-
Replace the default PostgreSQL password
At the time of writing, the embedded installer configuration can create PostgreSQL with the default value:
DB_PASSWORD=postgres
The generated Compose configuration also publishes PostgreSQL port
5432unless it is modified.Change the password before exposing the platform.
Generate a strong password:
NEW_DB_PASSWORD="$(openssl rand -base64 48 | tr -d '\n')" printf '%s\n' "$NEW_DB_PASSWORD"
Edit the environment file:
nano /opt/kubeara/control-panel/.env.control-panel
Replace:
DB_PASSWORD=postgres
with:
DB_PASSWORD=YOUR_GENERATED_PASSWORD
Existing PostgreSQL volume warning
Because the installer already initialized PostgreSQL, changing only the environment file does not necessarily change the password stored inside PostgreSQL.
Update the database role password directly:
cd /opt/kubeara/control-panel
Load the new password without placing it directly into shell history:
read -rsp "Enter the new PostgreSQL password: " NEW_DB_PASSWORD echo
Update PostgreSQL:
docker exec -i kubeara-postgres \ psql -U postgres -d kubeara \ -v new_password="$NEW_DB_PASSWORD" \ -c "ALTER USER postgres WITH PASSWORD :'new_password';"Then unset the variable:
unset NEW_DB_PASSWORD
Restart the API after the environment file has been updated:
docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ up -d --force-recreate -
Bind Kubearaās internal ports to localhost
Open the Compose file:
nano /opt/kubeara/control-panel/docker-compose.control-panel.yml
Locate the PostgreSQL port mapping:
ports: - "${DB_PORT:-5432}:5432"Change it to:
ports: - "127.0.0.1:${DB_PORT:-5432}:5432"Locate the API mapping:
ports: - "${PORT:-3000}:3000"Change it to:
ports: - "127.0.0.1:${PORT:-3000}:3000"Locate the console mapping:
ports: - "${CONSOLE_PORT:-8080}:80"Change it to:
ports: - "127.0.0.1:${CONSOLE_PORT:-8080}:80"Save the file and recreate the stack:
cd /opt/kubeara/control-panel docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ up -d --force-recreateVerify the listening sockets:
ss -lntp | grep -E ':(3000|8080|5432)\b'
Expected bindings:
See Also: Free Website Migration ā Hassle-Free & Zero Downtime!
127.0.0.1:3000 127.0.0.1:8080 127.0.0.1:5432
You should not see:
0.0.0.0:3000 0.0.0.0:8080 0.0.0.0:5432
-
Configure the public API URL
Open the Kubeara environment file:
nano /opt/kubeara/control-panel/.env.control-panel
Set:
CONTROL_PANEL_URL=https://kubeara.example.com VITE_API_URL=https://kubeara.example.com/api
The official installer otherwise defaults the browser-facing API URL to:
http://localhost:3000/api
That value works only when the browser itself is running on the Kubeara server. Remote users need a publicly reachable API URL.
Recreate the console and control panel:
cd /opt/kubeara/control-panel docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ up -d --force-recreateCheck the container state:
docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ ps -
Test the local Kubeara services
Test the API health endpoint:
curl -i http://127.0.0.1:3000/api/health
Test the console:
curl -I http://127.0.0.1:8080
Inspect all Kubeara containers:
docker ps --filter "name=kubeara"
Expected containers include:
kubeara-postgres kubeara-control-panel kubeara-console
View recent logs:
cd /opt/kubeara/control-panel docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ logs --tail=100Follow logs continuously:
docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ logs -fPress
Ctrl+Cto stop following logs. -
Install Nginx
Install Nginx:
apt install -y nginx
Enable and start it:
systemctl enable --now nginx
Verify:
nginx -v systemctl status nginx --no-pager
Remove the default site:
rm -f /etc/nginx/sites-enabled/default
-
Configure the Kubeara reverse proxy
Create an Nginx virtual host:
nano /etc/nginx/sites-available/kubeara.conf
Add:
server { listen 80; listen [::]:80; server_name kubeara.example.com; client_max_body_size 1g; location /api/ { proxy_pass http://127.0.0.1:3000/api/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600; proxy_send_timeout 3600; proxy_buffering off; } location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600; proxy_send_timeout 3600; proxy_buffering off; } }Replace every instance of:
See Also: What to Consider When Renting a VPS
kubeara.example.com
with your hostname.
Enable the site:
ln -s /etc/nginx/sites-available/kubeara.conf \ /etc/nginx/sites-enabled/kubeara.confTest the configuration:
nginx -t
Reload Nginx:
systemctl reload nginx
Test the HTTP endpoint:
curl -I http://kubeara.example.com
Test the proxied API:
curl -i http://kubeara.example.com/api/health
-
Install Certbot and enable HTTPS
Install Certbot and its Nginx plugin:
apt install -y certbot python3-certbot-nginx
Request a certificate:
certbot --nginx \ -d kubeara.example.com \ --redirect \ --agree-tos \ --no-eff-email \ -m admin@example.comReplace:
kubeara.example.comwith your hostnameadmin@example.comwith your administrative email address
Certbot should:
- Validate the domain.
- Obtain the certificate.
- Add the certificate paths to Nginx.
- Redirect HTTP traffic to HTTPS.
Test the certificate:
curl -I https://kubeara.example.com
Test the API through HTTPS:
curl -i https://kubeara.example.com/api/health
Test automatic renewal:
certbot renew --dry-run
Check the renewal timer:
systemctl status certbot.timer --no-pager
-
Open the Kubeara dashboard
Open:
https://kubeara.example.com
Complete the initial account registration or setup flow presented by the console.
After signing in, verify that you can reach:
- The main dashboard
- Server management
- Service templates
- Deployment history
- Logs
- User or team settings
Kubearaās public documentation describes a workflow in which an administrator connects a server, selects a service, and deploys it from the dashboard. The platform then manages items such as domains, SSL, health checks, logs, restarts, and updates.
-
Add a deployment server
The control-plane VPS may also be used as a workload server, but separating the control plane from workload nodes is preferable for larger or production environments.
A typical architecture is:
kubeara-control01 Kubeara console Kubeara API PostgreSQL kubeara-node01 Application workloads Databases Containers kubeara-node02 Additional services AI or GPU workloadsTo add a server:
- Sign in to the Kubeara dashboard.
- Open the server management section.
- Select the option to add or connect a server.
- Enter the serverās public or private IP address.
- Supply the requested authentication information.
- Allow Kubeara to validate the server.
- Complete the agent installation or connection procedure shown in the dashboard.
- Confirm that the node reports as online.
Kubeara states that its agent architecture initiates outbound connections and is intended to avoid storing plaintext SSH keys in the platform database.
Recommended node preparation
On each deployment node:
See Also: How to Install and Deploy FusionPBX on Debian VPS
apt update apt upgrade -y
Ensure:
- The node has a valid hostname.
- Time synchronization is active.
- DNS resolution works.
- Required outbound HTTPS access is permitted.
- Ports 80 and 443 are available if the node will directly publish services.
- No existing application is unexpectedly occupying those ports.
Check occupied ports:
ss -lntp
-
Deploy a test service
Use a lightweight service for the first deployment rather than a production database.
From the Kubeara dashboard:
- Select the connected server.
- Open the service catalog.
- Choose a small test application.
- Review the required environment variables.
- Configure persistent storage if required.
- Assign a domain or temporary access method.
- Start the deployment.
- Watch the live deployment log.
- Wait for the health status to become healthy.
- Open the deployed service.
Afterward, confirm from the node:
docker ps
Review resource use:
docker stats
Press
Ctrl+Cto exit. -
Create convenient management commands
Create a wrapper script:
nano /usr/local/sbin/kubeara-compose
Add:
#!/usr/bin/env bash set -euo pipefail INSTALL_DIR="/opt/kubeara/control-panel" COMPOSE_FILE="${INSTALL_DIR}/docker-compose.control-panel.yml" ENV_FILE="${INSTALL_DIR}/.env.control-panel" cd "${INSTALL_DIR}" exec docker compose \ -f "${COMPOSE_FILE}" \ --env-file "${ENV_FILE}" \ "$@"Make it executable:
chmod 750 /usr/local/sbin/kubeara-compose
Examples:
kubeara-compose ps kubeara-compose logs -f kubeara-compose restart kubeara-compose pull kubeara-compose up -d kubeara-compose stop kubeara-compose start
-
Back up Kubeara
A useful Kubeara backup should include:
- The PostgreSQL database
- The environment file
- The Compose configuration
- Any customized Nginx configuration
- The encryption and JWT secrets
Create a backup directory
install -m 700 -d /var/backups/kubeara
Back up PostgreSQL
docker exec kubeara-postgres \ pg_dump -U postgres -d kubeara \ | gzip > "/var/backups/kubeara/kubeara-db-$(date +%F-%H%M%S).sql.gz"Back up the configuration
tar -czf "/var/backups/kubeara/kubeara-config-$(date +%F-%H%M%S).tar.gz" \ /opt/kubeara/control-panel/.env.control-panel \ /opt/kubeara/control-panel/docker-compose.control-panel.yml \ /etc/nginx/sites-available/kubeara.confRestrict access:
chmod 600 /var/backups/kubeara/*
Copy the backups to an off-server destination. A backup stored only on the same VPS will be lost if the VPS or its storage becomes unavailable.
Example retention cleanup
Delete local Kubeara backups older than 14 days:
find /var/backups/kubeara \ -type f \ -mtime +14 \ -delete -
Automate daily database backups
Create a backup script:
nano /usr/local/sbin/backup-kubeara
Add:
#!/usr/bin/env bash set -euo pipefail BACKUP_DIR="/var/backups/kubeara" TIMESTAMP="$(date +%F-%H%M%S)" DATABASE_BACKUP="${BACKUP_DIR}/kubeara-db-${TIMESTAMP}.sql.gz" CONFIG_BACKUP="${BACKUP_DIR}/kubeara-config-${TIMESTAMP}.tar.gz" install -m 700 -d "${BACKUP_DIR}" docker exec kubeara-postgres \ pg_dump -U postgres -d kubeara \ | gzip > "${DATABASE_BACKUP}" tar -czf "${CONFIG_BACKUP}" \ /opt/kubeara/control-panel/.env.control-panel \ /opt/kubeara/control-panel/docker-compose.control-panel.yml \ /etc/nginx/sites-available/kubeara.conf chmod 600 "${DATABASE_BACKUP}" "${CONFIG_BACKUP}" find "${BACKUP_DIR}" \ -type f \ -mtime +14 \ -deleteMake it executable:
See Also: Connect BigBlueButton Server to Moodle LMS for Integrated eLearning
chmod 700 /usr/local/sbin/backup-kubeara
Test it:
/usr/local/sbin/backup-kubeara
Create a systemd service:
nano /etc/systemd/system/kubeara-backup.service
Add:
[Unit] Description=Back up Kubeara database and configuration Requires=docker.service After=docker.service [Service] Type=oneshot ExecStart=/usr/local/sbin/backup-kubeara
Create a timer:
nano /etc/systemd/system/kubeara-backup.timer
Add:
[Unit] Description=Run Kubeara backup daily [Timer] OnCalendar=*-*-* 03:30:00 Persistent=true RandomizedDelaySec=15m [Install] WantedBy=timers.target
Enable the timer:
systemctl daemon-reload systemctl enable --now kubeara-backup.timer
Verify:
systemctl list-timers kubeara-backup.timer
-
Update Kubeara
Because Kubeara is under active development, review release notes and create a backup before every update. The project was publishing frequent releases during July 2026, including version
0.0.14on July 29, 2026.Create a backup:
/usr/local/sbin/backup-kubeara
Pull new images:
kubeara-compose pull
Recreate the services:
kubeara-compose up -d
Review status:
kubeara-compose ps
Review logs:
kubeara-compose logs --tail=200
Test the health endpoint:
curl -fsS https://kubeara.example.com/api/health
Rerun the installer
The installer preserves an existing
.env.control-panelunless forced to regenerate it. This allows the installer to reuse existing secrets and database settings during subsequent runs.A rerun can be performed with:
KUBEARA_PUBLIC_URL="https://kubeara.example.com" \ KUBEARA_INSTALL_DIR="/opt/kubeara/control-panel" \ bash /root/kubeara-install.sh
However, inspect whether the installer rewrites the Compose file. If it does, reapply the localhost-only port bindings before restarting the stack.
Do not use:
KUBEARA_FORCE_ENV=1
on an existing installation unless you intentionally want to regenerate the environment file. Regenerating encryption or JWT secrets could invalidate stored credentials or sessions.
-
Restore Kubeara
Restore the configuration
Extract the configuration backup:
tar -xzf /path/to/kubeara-config-backup.tar.gz -C /
Verify permissions:
chown root:root /opt/kubeara/control-panel/.env.control-panel chmod 600 /opt/kubeara/control-panel/.env.control-panel
Start PostgreSQL:
kubeara-compose up -d postgres
Wait until it is healthy:
docker inspect \ --format '{{.State.Health.Status}}' \ kubeara-postgresRestore the database
Stop the API temporarily:
kubeara-compose stop control-panel-app console
Drop and recreate the database:
See Also: How to Install Pleroma on Ubuntu VPS (5 Minute Quick-Start Guide)
docker exec -i kubeara-postgres \ psql -U postgres \ -c "DROP DATABASE IF EXISTS kubeara;"docker exec -i kubeara-postgres \ psql -U postgres \ -c "CREATE DATABASE kubeara;"Restore the dump:
gunzip -c /path/to/kubeara-db-backup.sql.gz \ | docker exec -i kubeara-postgres \ psql -U postgres -d kubearaStart all services:
kubeara-compose up -d
Test:
curl -fsS https://kubeara.example.com/api/health
-
Monitoring and maintenance
-
Check container health
kubeara-compose ps
-
Check resource consumption
docker stats
-
Check disk use
df -h docker system df
-
Check Docker logs
journalctl -u docker --since "1 hour ago"
-
Check Nginx logs
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
-
Check Kubeara logs
kubeara-compose logs -f control-panel-app
kubeara-compose logs -f console
kubeara-compose logs -f postgres
-
Check the public health endpoint
curl -fsS https://kubeara.example.com/api/health
-
-
Troubleshooting
-
Docker is not installed
Error:
Docker is not installed. Install Docker Engine, then re-run this script.
Verify:
command -v docker docker version
Install Docker using the procedure in this guide.
-
Docker daemon is not running
Error:
Docker daemon is not running or you lack permission
Start it:
systemctl enable --now docker
Review errors:
journalctl -u docker -n 200 --no-pager
-
Docker Compose plugin is missing
Error:
Docker Compose v2 plugin is required
Install it:
apt update apt install -y docker-compose-plugin
Verify:
docker compose version
The installer requires the modern command:
docker compose
rather than the legacy standalone command:
docker-compose
-
Kubeara API does not become healthy
Test locally:
curl -v http://127.0.0.1:3000/api/health
Inspect the API logs:
kubeara-compose logs --tail=200 control-panel-app
Inspect PostgreSQL:
kubeara-compose logs --tail=200 postgres
Verify the database container is healthy:
docker inspect \ --format '{{json .State.Health}}' \ kubeara-postgres | jqCheck that the database credentials in
.env.control-panelmatch the PostgreSQL role password. -
The dashboard loads but API requests fail
Open the environment file:
nano /opt/kubeara/control-panel/.env.control-panel
Confirm:
VITE_API_URL=https://kubeara.example.com/api CONTROL_PANEL_URL=https://kubeara.example.com
Recreate the containers:
kubeara-compose up -d --force-recreate
Test the API through Nginx:
curl -i https://kubeara.example.com/api/health
Use the browserās developer tools to determine whether the console is attempting to contact:
http://localhost:3000
If it is, the public API variable was not applied to the console container.
-
Nginx returns 502 Bad Gateway
Check whether the services are listening:
ss -lntp | grep -E ':(3000|8080)\b'
Test each backend directly:
See Also: Email Sending Best Practices
curl -i http://127.0.0.1:3000/api/health curl -I http://127.0.0.1:8080
Check Nginx errors:
tail -n 100 /var/log/nginx/error.log
Check the containers:
kubeara-compose ps kubeara-compose logs --tail=200
-
Port 3000 or 8080 is already in use
Find the process:
ss -lntp | grep -E ':(3000|8080)\b'
Change the Kubeara ports:
nano /opt/kubeara/control-panel/.env.control-panel
For example:
PORT=3100 CONSOLE_PORT=8180
Update Nginx:
proxy_pass http://127.0.0.1:3100/api/;
and:
proxy_pass http://127.0.0.1:8180;
Recreate the stack:
kubeara-compose up -d --force-recreate
Reload Nginx:
nginx -t && systemctl reload nginx
-
PostgreSQL is publicly reachable
Check:
ss -lntp | grep ':5432'
An unsafe result resembles:
0.0.0.0:5432
The preferred result is:
127.0.0.1:5432
Correct the Compose port mapping:
ports: - "127.0.0.1:${DB_PORT:-5432}:5432"Then recreate the database container:
kubeara-compose up -d --force-recreate postgres
-
Database authentication fails after changing the password
Changing
DB_PASSWORDin.env.control-paneldoes not automatically modify an already initialized PostgreSQL role.Reset it from within the container:
docker exec -it kubeara-postgres \ psql -U postgres -d kubearaAt the PostgreSQL prompt:
ALTER USER postgres WITH PASSWORD 'REPLACE_WITH_STRONG_PASSWORD';
Exit:
\q
Then ensure the same password appears in:
/opt/kubeara/control-panel/.env.control-panel
Restart the API:
kubeara-compose restart control-panel-app
-
Database migration fails
Run migrations manually:
cd /opt/kubeara/control-panel docker compose \ -f docker-compose.control-panel.yml \ --env-file .env.control-panel \ --profile migrate \ run --rm migrateReview the output carefully.
Verify PostgreSQL is healthy first:
docker inspect \ --format '{{.State.Health.Status}}' \ kubeara-postgres -
Certificate issuance fails
Verify DNS:
dig +short kubeara.example.com
Verify port 80:
ufw status ss -lntp | grep ':80'
Test HTTP externally:
curl -I http://kubeara.example.com
Review Certbot:
journalctl -u certbot --since today
Retry:
certbot --nginx -d kubeara.example.com
-
Containers repeatedly restart
Check status:
docker ps -a --filter "name=kubeara"
Inspect the restarting container:
docker inspect kubeara-control-panel | jq '.[0].State'
Review logs:
docker logs --tail=200 kubeara-control-panel
Common causes include:
- Incorrect database password
- Missing encryption secret
- Invalid JWT secret
- PostgreSQL not healthy
- Port conflicts
- Unsupported image architecture
- Incomplete image download
- Failed database migration
-
-
Production security checklist
Before placing Kubeara into production, confirm:
- The dashboard is accessible only through HTTPS.
- Ports 3000, 8080, and 5432 bind only to localhost.
- PostgreSQL does not use the default password.
.env.control-panelis readable only by root.- The encryption secret is backed up securely.
- JWT secrets are not stored in source control.
- SSH password authentication is disabled where practical.
- Root SSH login is restricted.
- Automatic security updates are configured.
- Off-server backups are tested.
- Docker and Kubeara images are updated regularly.
- The API health endpoint is monitored.
- Nginx and Docker logs are reviewed.
- Separate workload nodes are used for sensitive or resource-intensive services.
- Only trusted administrators can add servers or deploy templates.
- Recovery procedures have been tested before they are needed.
Conclusion
You now know how to deploy Kubeara PaaS on Ubuntu VPS. By following this guide, youāll have a self-hosted Kubeara PaaS deployment consisting of:
- A Docker-based Kubeara control plane
- A persistent PostgreSQL database
- A web console
- A backend API
- Nginx reverse proxying
- Letās Encrypt HTTPS
- Localhost-only internal ports
- Database and configuration backups
- A foundation for adding application or infrastructure nodes
The most important production adjustments are to replace the default database password, preserve Kubearaās generated secrets, avoid publicly exposing its internal Docker ports, and maintain tested off-server backups.









