...
šŸš€ deploy kubeara paas on ubuntu vps
Learn how to deploy kubeara paas on ubuntu vps!

This article provides a guide demonstrating how to deploy Kubeara PaaS on Ubuntu VPS.

Table of Contents

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:

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.

Launch 100% ssd ubuntu vps from $3. 19/mo!


Compare Ubuntu VPS Plans

KVM-SSD-1
KVM-SSD-8
KVM-SSD-16
KVM-SSD-32
CPU
1 Core
2 Cores
4 Cores
8 Cores
Memory
1 GB
8 GB
16 GB
32 GB
Storage
16 GB NVMe
128 GB NVMe
256 GB NVMe
512 GB NVMe
Bandwidth
1 TB
4 TB
8 TB
16 TB
Network
1 Gbps
1 Gbps
1 Gbps
1 Gbps
Delivery Time
ā±ļø Instant
ā±ļø Instant
ā±ļø Instant
ā±ļø Instant
Location
US/EU/APAC
US/EU/APAC
US/EU/APAC
US/EU/APAC
Price
$7.58*
$39.50*
$79.40*
$151.22*
KVM-SSD-1
$7.58*
CPU 1 Core
Memory 1 GB
Storage 16 GB NVMe
Bandwidth 1 TB
Network 1 Gbps
Delivery Time ā±ļø Instant
Location US/EU/APAC
KVM-SSD-8
$39.50*
CPU 2 Cores
Memory 8 GB
Storage 128 GB NVMe
Bandwidth 4 TB
Network 1 Gbps
Delivery Time ā±ļø Instant
Location US/EU/APAC
KVM-SSD-16
$79.40*
CPU 4 Cores
Memory 16 GB
Storage 256 GB NVMe
Bandwidth 8 TB
Network 1 Gbps
Delivery Time ā±ļø Instant
Location US/EU/APAC
KVM-SSD-32
$151.22*
CPU 8 Cores
Memory 32 GB
Storage 512 GB NVMe
Bandwidth 16 TB
Network 1 Gbps
Delivery Time ā±ļø Instant
Location US/EU/APAC

How to Deploy Kubeara PaaS on an Ubuntu VPS

To deploy Kubeara PaaS on Ubuntu VPS, follow the steps outlined below:

  1. 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
    
  2. 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 \
        ufw
    

    Reboot if the update installed a new kernel:

    reboot
    

    Reconnect after the server restarts.

  3. 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.

  4. 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.

  5. 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 || true
    

    Create 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.asc
    

    Make 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-plugin
    

    These 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
    
  6. 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
    
  7. 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.com with your actual hostname.

    The installer should:

    1. Verify Docker is installed and running.
    2. Verify Docker Compose v2 is available.
    3. Create /opt/kubeara/control-panel.
    4. Write the Docker Compose configuration.
    5. Generate the environment file.
    6. Generate an encryption secret.
    7. Generate JWT access and refresh secrets.
    8. Pull the Kubeara console, API, agent, and PostgreSQL images.
    9. Start the containers.
    10. Run database migrations.
    11. Seed Kubeara’s templates.
    12. 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
    
  8. 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.

  9. 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 5432 unless 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
    
  10. 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-recreate
    

    Verify 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
    
  11. 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-recreate
    

    Check the container state:

    docker compose \
        -f docker-compose.control-panel.yml \
        --env-file .env.control-panel \
        ps
    
  12. 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=100
    

    Follow logs continuously:

    docker compose \
        -f docker-compose.control-panel.yml \
        --env-file .env.control-panel \
        logs -f
    

    Press Ctrl+C to stop following logs.

  13. 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
    
  14. 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.conf
    

    Test 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
    
  15. 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.com
    

    Replace:

    • kubeara.example.com with your hostname
    • admin@example.com with your administrative email address

    Certbot should:

    1. Validate the domain.
    2. Obtain the certificate.
    3. Add the certificate paths to Nginx.
    4. 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
    
  16. 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.

  17. 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 workloads
    

    To add a server:

    1. Sign in to the Kubeara dashboard.
    2. Open the server management section.
    3. Select the option to add or connect a server.
    4. Enter the server’s public or private IP address.
    5. Supply the requested authentication information.
    6. Allow Kubeara to validate the server.
    7. Complete the agent installation or connection procedure shown in the dashboard.
    8. 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
    
  18. Deploy a test service

    Use a lightweight service for the first deployment rather than a production database.

    From the Kubeara dashboard:

    1. Select the connected server.
    2. Open the service catalog.
    3. Choose a small test application.
    4. Review the required environment variables.
    5. Configure persistent storage if required.
    6. Assign a domain or temporary access method.
    7. Start the deployment.
    8. Watch the live deployment log.
    9. Wait for the health status to become healthy.
    10. Open the deployed service.

    Afterward, confirm from the node:

    docker ps
    

    Review resource use:

    docker stats
    

    Press Ctrl+C to exit.

  19. 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
    
  20. Back up Kubeara

    A useful Kubeara backup should include:

    1. The PostgreSQL database
    2. The environment file
    3. The Compose configuration
    4. Any customized Nginx configuration
    5. 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.conf
    

    Restrict 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
    
  21. 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 \
        -delete
    

    Make 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
    
  22. 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.14 on 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-panel unless 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.

  23. 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-postgres
    

    Restore 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 kubeara
    

    Start all services:

    kubeara-compose up -d
    

    Test:

    curl -fsS https://kubeara.example.com/api/health
    
  24. 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
      
  25. 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 | jq
      

      Check that the database credentials in .env.control-panel match 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_PASSWORD in .env.control-panel does not automatically modify an already initialized PostgreSQL role.

      Reset it from within the container:

      docker exec -it kubeara-postgres \
          psql -U postgres -d kubeara
      

      At 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 migrate
      

      Review 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
  26. 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-panel is 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.

Launch 100% ssd ubuntu vps from $3. 19/mo!

See Also: āœ… Seamlessly Connect Your Moodle Site to the Mobile App: A Practical 9-Step Guide for Admins Who Keep It All Running

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.

Avatar of editorial staff

Editorial Staff

Rad Web Hosting is a leading provider of web hosting, Cloud VPS, and Dedicated Servers in Dallas, TX.
lg