Back to Blog

Self-Hosting Business Intelligence Platforms with Container Orchestration

A step-by-step guide to deploying and managing containerized applications on VPS.

Docker BI Platform

Overview

Self-hosting business intelligence tools gives your organization full control over data, privacy, and costs. In this guide, I walk through deploying a complete BI stack on a VPS using Docker Compose, secured with a reverse proxy and custom subdomains.

What You'll Need

  • A VPS with at least 4GB RAM and 2 vCPUs (Ubuntu 22.04 LTS recommended)
  • A domain name with DNS access
  • Basic Linux command line knowledge
  • Understanding of Docker concepts (images, containers, volumes)

Architecture Overview

Deployment Architecture
Internet
Reverse Proxy + SSL
Docker Network
BI App + DB

Step 1: VPS Initial Setup

Start with a fresh Ubuntu 22.04 LTS server. Secure it first:

# Update system
sudo apt update && sudo apt upgrade -y

# Create non-root user
sudo adduser deploy
sudo usermod -aG sudo deploy

# Configure SSH key authentication
ssh-copy-id deploy@your-server-ip

# Disable password authentication
sudo nano /etc/ssh/sshd_config
# Set: PasswordAuthentication no
sudo systemctl restart sshd

# Enable firewall
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Step 2: Install Docker & Docker Compose

# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker deploy

# Install Docker Compose plugin
sudo apt install docker-compose-plugin -y

# Verify installation
docker --version
docker compose version

Step 3: Docker Compose Configuration

Create a project directory and define your services:

# docker-compose.yml
version: "3.8"
services:
  bi-app:
    image: your-bi-platform:latest
    container_name: bi-app
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=bi_data
      - DB_USER=${DB_USER}
      - DB_PASS=${DB_PASS}
    volumes:
      - bi-data:/app/data
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:15-alpine
    container_name: bi-db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=bi_data
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASS}
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network

volumes:
  bi-data:
  db-data:

networks:
  app-network:
    driver: bridge

Security Note

Never hardcode credentials in docker-compose.yml. Use a .env file and add it to .gitignore. For production, use Docker secrets or a vault solution.

Step 4: Reverse Proxy with SSL

Use a reverse proxy to handle SSL termination and route traffic to containers:

  • Point your subdomain DNS record (e.g., bi.yourdomain.com) to your VPS IP
  • Configure the reverse proxy to forward traffic to the container's internal port
  • Enable automatic SSL certificate provisioning (Let's Encrypt)
  • Set up automatic certificate renewal

Step 5: Backup Strategy

# backup.sh - Run via cron daily
#!/bin/bash
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d)

# Backup database
docker exec bi-db pg_dump -U $DB_USER bi_data | \
  gzip > "$BACKUP_DIR/db-$DATE.sql.gz"

# Backup volumes
docker run --rm \
  -v bi-data:/source \
  -v $BACKUP_DIR:/backup \
  alpine tar czf "/backup/bi-data-$DATE.tar.gz" -C /source .

# Retain last 14 days
find $BACKUP_DIR -mtime +14 -delete

echo "Backup completed: $DATE"

Key Takeaways

Deployment Checklist

  • Secure the VPS before deploying anything (SSH keys, firewall, updates)
  • Use Docker Compose for reproducible deployments
  • Never expose container ports directly — always use a reverse proxy
  • Implement automated backups from day one
  • Monitor container health and resource usage
  • Use environment variables for all credentials
  • Set up log rotation to prevent disk space issues