How to Deploy Self-Hosted Baserow on Ubuntu

What You’ll Need
- Hetzner VPS or Contabo VPS running Ubuntu 22.04 or 24.04 LTS (Minimum 2 vCPUs, 4GB RAM recommended)
- DigitalOcean droplet as an alternative VPS host
- Namecheap for managing your custom domain name and DNS records
- n8n Cloud or a self-hosted instance for downstream API automation
- Make.com if comparing SaaS integrations against self-hosted pipelines
Table of Contents
- Server Provisioning and Initial System Setup
- Configuring Docker Compose for Baserow
- Reverse Proxy and Automatic SSL Configuration with Caddy
- Automated Database Backups and Workflow Integrations
- Getting Started
Server Provisioning and Initial System Setup
Deploying your own open-source database platform gives you full sovereignty over your data structure, eliminates per-seat platform fees, and unlocks unlimited API throughput. Baserow is an exceptional open-source, Airtable-compatible relational database builder. To run it reliably in production, you need a stable Linux environment configured with Docker and secure networking.
I recommend starting with a clean Ubuntu 24.04 server on a provider like Hetzner VPS or DigitalOcean . Baserow packages PostgreSQL, Redis, Celery workers, and a web application interface. A machine with 2 vCPUs and 4GB RAM is the baseline for handling concurrent background jobs and complex table relationships without hitting out-of-memory (OOM) kernel kills.
First, access your server via SSH and execute a full package index refresh and system upgrade:
sudo apt-get update && sudo apt-get upgrade -y
Install the essential base utilities required for system administration, container repository management, and SSL certificate verification:
sudo apt-get install -y curl gpg ca-certificates lsb-release ufw fail2ban
Next, add Docker’s official GPG key and APT repository to your system source list to ensure you pull official, updated container engines:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Install the Docker Engine, Docker CLI daemon, containerd runtime, and the Compose plugin:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Enable and start the Docker service so that it automatically launches upon host system reboots:
sudo systemctl enable --now docker
Configure your Uncomplicated Firewall (UFW) to block unneeded inbound traffic, exposing only SSH, HTTP, and HTTPS ports to the public internet:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH Port'
sudo ufw allow 80/tcp comment 'HTTP Port'
sudo ufw allow 443/tcp comment 'HTTPS Port'
sudo ufw --force enable
Create a dedicated system user group and workspace directory for your Baserow stack files. This isolates application data from standard root paths:
sudo mkdir -p /opt/baserow
sudo chown -R $USER:$USER /opt/baserow
cd /opt/baserow
Before proceeding to container declaration, register an A record with your DNS provider—such as Namecheap
—pointing your sub-domain (e.g., db.yourdomain.com) directly to your VPS IPv4 address.
💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.
Configuring Docker Compose for Baserow
Baserow provides a unified multi-service architecture container image containing the web server, application backend, background task processing queues, and media storage modules. While you can deploy external PostgreSQL databases, the consolidated official image simplifies state retention and backup orchestration while maintaining isolated file storage volumes.
Create an environment configuration file named .env inside /opt/baserow to store critical environment settings, database passphrases, and key domain URLs:
cat << 'EOF' > /opt/baserow/.env
SECRET_KEY=c89f1d24a9e5b7c0d1e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5d7e9f1a3b5c7
DATABASE_PASSWORD=SuperSecurePostgresPassword2026!
BASEROW_PUBLIC_URL=https://db.yourdomain.com
EMAIL_SMTP_HOST=smtp.sendgrid.net
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USE_TLS=YES
EMAIL_SMTP_USER=apikey
EMAIL_SMTP_PASSWORD=SG.YourActualSendgridApiKeyStringGoesHere
FROM_EMAIL=noreply@yourdomain.com
BASEROW_AMOUNT_OF_WORKERS=2
BASEROW_CONCURRENCY=4
EOF
Now, construct the core orchestration declaration in /opt/baserow/docker-compose.yml. This file provisions persistent storage volumes, mounts system networking routes, and sets environment dependencies.
version: '3.8'
services:
baserow:
image: baserow/baserow:1.24.2
container_name: baserow_app
restart: unless-stopped
env_file:
- .env
environment:
BASEROW_PUBLIC_URL: '${BASEROW_PUBLIC_URL}'
SECRET_KEY: '${SECRET_KEY}'
DATABASE_PASSWORD: '${DATABASE_PASSWORD}'
EMAIL_SMTP_HOST: '${EMAIL_SMTP_HOST}'
EMAIL_SMTP_PORT: '${EMAIL_SMTP_PORT}'
EMAIL_SMTP_USE_TLS: '${EMAIL_SMTP_USE_TLS}'
EMAIL_SMTP_USER: '${EMAIL_SMTP_USER}'
EMAIL_SMTP_PASSWORD: '${EMAIL_SMTP_PASSWORD}'
FROM_EMAIL: '${FROM_EMAIL}'
BASEROW_AMOUNT_OF_WORKERS: '${BASEROW_AMOUNT_OF_WORKERS}'
BASEROW_CONCURRENCY: '${BASEROW_CONCURRENCY}'
DISABLE_INLINE_DOCUMENTATION: 'false'
BASEROW_ENABLE_GDPR: 'false'
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:8443:443"
volumes:
- baserow_data:/baserow/data
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/api/health/ || exit 1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
volumes:
baserow_data:
driver: local
This configuration routes internal HTTP requests from the container to 127.0.0.1:8080 on your host network. Binding the web service strictly to loopback prevents untracked public traffic from bypassing host SSL proxies or exposing raw internal ports.
Launch the service stack in detached background mode:
docker compose up -d
You can tail the container launch logs to monitor initial database migrations and asset compilations:
docker compose logs -f baserow
Wait until the system initialization logs indicate that the PostgreSQL migration scripts completed and Gunicorn server processes are running before moving to the reverse proxy configuration.
Reverse Proxy and Automatic SSL Configuration with Caddy
While Baserow includes internal Caddy instance features, running a standalone, host-level reverse proxy like Caddy on Ubuntu provides superior flexibility. Host-level Caddy manages automatic TLS issuance through Let’s Encrypt, routes external requests clean into internal loopback ports, enforces strict TLS cipher suites, and manages global reverse proxies if you run multi-service nodes on the same host—such as following my guide on How to Deploy n8n with Docker on Any VPS (2026 Guide) .
Install Caddy onto your Ubuntu host via the official repository package manager:
sudo apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt-get update
sudo apt-get install -y caddy
Backup the default system Caddy configuration file and generate a fresh production server file at /etc/caddy/Caddyfile:
db.yourdomain.com {
encode gzip zstd
request_body {
max_size 100MB
}
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
}
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
log {
output file /var/log/caddy/baserow_access.log {
roll_size 10mb
roll_keep 10
}
}
}
Verify your Caddy file formatting to ensure there are no syntax bugs or missing bracket pairs:
caddy validate --config /etc/caddy/Caddyfile
If the syntax validation succeeds, reload the host Caddy system daemon to obtain valid SSL certificates and start proxying live traffic:
sudo systemctl reload caddy
Open your browser and navigate to https://db.yourdomain.com. You will see the initial Baserow account creation prompt. Register your master administrator credentials immediately.
Automated Database Backups and Workflow Integrations
A self-hosted database service requires automated back-ups. Baserow stores stateful relational schema data, user roles, base metadata inside an internal PostgreSQL database, and uploaded user media (images, files, attachments) within container volumes.
Create an automated backup script that targets both system components directly without requiring service downtime.
Create directory storage for backup artifacts and logs:
sudo mkdir -p /var/backups/baserow
sudo chmod 700 /var/backups/baserow
Write a production-ready bash backup script located at /usr/local/bin/backup-baserow.sh:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/baserow"
DATE_STAMP=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
PG_BACKUP_FILE="${BACKUP_DIR}/baserow_db_${DATE_STAMP}.sql.gz"
MEDIA_BACKUP_FILE="${BACKUP_DIR}/baserow_media_${DATE_STAMP}.tar.gz"
LOG_FILE="${BACKUP_DIR}/backup.log"
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Starting Baserow system backup..." >> "${LOG_FILE}"
# 1. Export PostgreSQL database dump directly out of the application container
docker exec -t baserow_app /bin/bash -c "pg_dump -U baserow baserow" | gzip -9 > "${PG_BACKUP_FILE}"
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] PostgreSQL database dump written to ${PG_BACKUP_FILE}" >> "${LOG_FILE}"
# 2. Compress persistent application state media attachments
tar -czf "${MEDIA_BACKUP_FILE}" -C /var/lib/docker/volumes/baserow_baserow_data/_data .
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Media assets archived to ${MEDIA_BACKUP_FILE}" >> "${LOG_FILE}"
# 3. Enforce backup retention policies (Prune old backups)
find "${BACKUP_DIR}" -type f -name "baserow_db_*.sql.gz" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -type f -name "baserow_media_*.tar.gz" -mtime +${RETENTION_DAYS} -delete
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Backup process completed successfully." >> "${LOG_FILE}"
Make the script executable:
sudo chmod +x /usr/local/bin/backup-baserow.sh
Execute a test run to verify backup file creation:
sudo /usr/local/bin/backup-baserow.sh
Verify the files created in /var/backups/baserow:
ls -lh /var/backups/baserow
Add a recurring Cron rule to trigger this backup daily at 2:30 AM:
(crontab -l 2>/dev/null; echo "30 2 * * * /usr/local/bin/backup-baserow.sh >/dev/null 2>&1") | crontab -
Unlocking Workflow Integrations
Now that your self-hosted Baserow deployment is secure, updated, and backed up, you can connect it directly to your external workflow stack using native REST APIs and webhooks.
Because Baserow exposes an OpenAPI schema, it acts as a structured database backend for automation pipelines. If you evaluate your architectural stack against paid tools, review my analysis on the Best Alternatives to Zapier for API Automation to optimize platform costs.
For real-time operational alerts, project status updates, or customer routing directly out of your Baserow database instances, review my implementation guide on Building Telegram Bots for Workflow Management to wire webhooks directly into interactive chat applications.
To test your API connection, generate a Database Token inside your Baserow user settings interface (Settings -> Database Tokens) and execute a query using standard cURL routines:
curl -X GET "https://db.yourdomain.com/api/database/rows/table/1/?user_field_names=true" \
-H "Authorization: Token YOUR_GENERATED_BASEROW_TOKEN"
This returns structured JSON payloads for seamless ingestion by custom scripts, automated bots, and orchestration engines.
Getting Started
To recap the setup workflow for your open-source data infrastructure:
- Provision a high-performance host instance using Hetzner VPS , Contabo VPS , or DigitalOcean .
- Configure your public domain records via Namecheap .
- Execute the Docker Compose file structure with loopback port mapping and persistent system volumes.
- Protect your platform using a reverse proxy with automated TLS encryption.
- Link your database endpoints to n8n Cloud or self-hosted automation services to power real-time data pipelines.
Outsource Your Automation
Don’t have time? I build production n8n workflows, WhatsApp bots, and fully automated YouTube Shorts pipelines. Hire me on Fiverr — mention SYS3-HUGO for priority. Or DM at chasebot.online .
Want to automate this yourself?
Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.
Want this engine running on your own VPS?
This blog publishes itself — daily, unattended, on free API tiers. The full engine, Hugo theme, and setup guide are available as System 3.
Get System 3