TL;DR
You can run a production-ready Apache Superset instance on a $6-per-month VPS in under two hours. the setup uses Docker Compose, Nginx as a reverse proxy, and Let’s Encrypt for SSL. you need basic Linux command-line skills and a domain name you control.
What You Need Before You Start
- a VPS with at least 2 vCPUs and 4 GB RAM (8 GB recommended for heavier query loads). Hetzner CPX21, DigitalOcean Droplet 4 GB, or Vultr Cloud Compute 4 GB all work.
- Ubuntu 22.04 LTS or 24.04 LTS on the VPS.
- Docker 24+ and Docker Compose v2.20+ (not the old standalone
docker-composebinary — that is v1 and unmaintained). - a domain name with an A record pointed at your VPS IP. a subdomain on a domain you already own is fine.
- SSH access as a non-root user with sudo privileges.
- a working email address for the Let’s Encrypt certificate issuance.
- (optional) a managed PostgreSQL database on Supabase, Neon, or RDS if you want to keep Superset’s metadata database off the VPS disk. the default Docker Compose setup bundles a local Postgres container, which works for small teams.
- Apache Superset 4.x is the current stable release as of mid-2026.
Step 1: Provision and Harden Your VPS
Spin up a fresh Ubuntu 24.04 VPS. log in as root, create a sudo user, and disable root SSH login before you do anything else.
adduser superset_admin
usermod -aG sudo superset_admin
Edit /etc/ssh/sshd_config and set both of these:
PermitRootLogin no
PasswordAuthentication no
Copy your SSH public key to the new user with ssh-copy-id, restart sshd, and reconnect as superset_admin. then run a full system update:
sudo apt update && sudo apt upgrade -y
Open ports 80 and 443 in UFW:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
you should now see Status: active from sudo ufw status with both HTTP ports listed as allowed and root SSH locked out.
Step 2: Install Docker and Docker Compose
Docker ships its own apt repository, which gives you a much newer version than the Ubuntu default package. follow the official path:
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
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 update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Add your user to the docker group so you skip sudo on every command:
sudo usermod -aG docker $USER
newgrp docker
Confirm versions:
docker --version # expect 26.x or higher
docker compose version # expect v2.27 or higher
you should now see both version strings with no permission errors. if you see permission denied, log out and back in to refresh group membership.
Step 3: Clone the Superset Repository
Superset keeps a production-ready Docker Compose configuration in its official GitHub repo. clone the version tag you want to pin to:
git clone --depth 1 --branch 4.1.0 \
https://github.com/apache/superset.git /opt/superset
cd /opt/superset
The --depth 1 flag keeps the download small. /opt/superset keeps it outside any home directory, which avoids permission headaches later when services run as different users.
you should now see the repo contents including docker/ and docker-compose.yml when you run ls /opt/superset.
Step 4: Configure Your Environment Variables
Copy the example env file and edit it:
cp docker/.env-non-dev docker/.env
nano docker/.env
Two values are critical. first, generate a proper secret key:
openssl rand -base64 48
Paste the output as SECRET_KEY. never use the placeholder that ships in the example file. if you skip this, anyone who reads a forum post about Superset defaults can forge admin session cookies on your instance.
also set SUPERSET_ENV=production. if you are using an external Postgres instance for metadata, add:
DATABASE_URL=postgresql+psycopg2://user:password@your-db-host:5432/superset
Leave that line out if you are happy with the bundled Postgres container.
you should now have a populated docker/.env file with no placeholder values remaining in it.
Step 5: Build and Start the Stack
With the environment configured, start the full stack:
cd /opt/superset
docker compose -f docker-compose-image-tag.yml up -d
The first run pulls several images (Superset, Celery worker, Redis, Postgres) and can take 5-10 minutes depending on your VPS bandwidth. watch the logs to confirm a clean startup:
docker compose -f docker-compose-image-tag.yml logs -f superset
you should see Starting server on 0.0.0.0:8088 and no Python tracebacks. press Ctrl+C to detach. if you see an Address already in use error, another process is sitting on port 8088 — run sudo ss -tulnp | grep 8088 to find it.
Step 6: Initialize the Database and Create Your Admin User
Superset stores all its metadata (dashboards, chart configs, user accounts) in Postgres. you need to run three commands in order before you can log in:
docker compose -f docker-compose-image-tag.yml exec superset \
superset db upgrade
docker compose -f docker-compose-image-tag.yml exec superset \
superset fab create-admin \
--username admin \
--firstname Admin \
--lastname User \
--email your@email.com \
--password yourStrongPassword
docker compose -f docker-compose-image-tag.yml exec superset \
superset init
The db upgrade command runs schema migrations. create-admin creates your first login. superset init loads roles and permissions into the database. skipping superset init is one of the most common causes of mysterious permission errors on fresh installs.
you should now be able to reach Superset at http://YOUR_VPS_IP:8088 and log in. do not leave 8088 public-facing any longer than needed — you close it in step 8.
Step 7: Install Nginx as a Reverse Proxy
Nginx sits in front of Superset, handles SSL termination, and lets you serve traffic on port 443 without exposing the raw 8088 port.
sudo apt install -y nginx
sudo systemctl enable nginx
Create a server block for your domain:
sudo nano /etc/nginx/sites-available/superset
Paste this, replacing bi.yourdomain.com with your actual subdomain:
server {
listen 80;
server_name bi.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8088;
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_read_timeout 120s;
}
}
Enable the site and reload Nginx:
sudo ln -s /etc/nginx/sites-available/superset /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
you should now reach Superset at http://bi.yourdomain.com over plain HTTP. block the raw port: sudo ufw deny 8088/tcp.
Step 8: Add SSL with Certbot
Certbot automates Let’s Encrypt certificate issuance and renewal. install from snap for the most reliable version on Ubuntu:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx -d bi.yourdomain.com
Certbot prompts for your email, asks you to agree to the TOS, and automatically edits your Nginx config to redirect HTTP to HTTPS and inject the SSL certificate block.
Verify auto-renewal works:
sudo certbot renew --dry-run
you should see Congratulations, all simulated renewals succeeded. your Superset instance should now load on https://bi.yourdomain.com with a valid padlock and no browser warnings.
Step 9: Connect Your First Database
Log into Superset as admin. go to Settings > Database Connections > + Database. Superset supports PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, ClickHouse, DuckDB, and dozens more via SQLAlchemy connection strings.
For a PostgreSQL database:
postgresql+psycopg2://your_user:your_password@your_db_host:5432/your_db_name
Click Test Connection before saving. a green checkmark confirms the connection is live. if it fails, check that your VPS IP is in the database’s allowed hosts list and that port 5432 is reachable between the two servers.
Once saved, Superset scans for tables automatically. go to Data > Datasets to create your first dataset, then Charts to build a visualization, and drag it onto a new dashboard.
you should now see your database tables available in SQL Lab under SQL > SQL Lab, queryable with full autocomplete.
Common Mistakes To Avoid
- Using the default SECRET_KEY from the example file. the placeholder is publicly documented. regenerate it with
openssl rand -base64 48every time, on every new install. - Skipping
superset initafter version upgrades. when you pull a new image and restart, rundb upgradeandsuperset initagain immediately or you will see role permission errors that look like bugs but are just missing initialization. - Leaving port 8088 open to the internet. the container’s Gunicorn server has no rate limiting or brute-force protection. always put Nginx in front and deny 8088 at the firewall.
- No memory limits on containers. on a 4 GB VPS, an unconstrained Superset container can OOM-kill the Postgres container mid-query. add
mem_limit: 1500mto the superset service in your compose file. - Not backing up the metadata database. every dashboard, chart, and user account lives in that Postgres instance. a weekly
pg_dumppiped to S3 or Backblaze B2 takes five minutes to set up and saves you from a full rebuild. - Forgetting
proxy_set_header X-Forwarded-Proto $schemein Nginx. without it, Superset generates HTTP links in email reports and embedded iframes even when the site is on HTTPS, which breaks mixed-content rules in every modern browser.
When To Level Up
The single-VPS Docker Compose setup handles teams of 1-15 people querying databases that respond in under 30 seconds. you will start hitting walls when:
dashboards time out because queries regularly exceed 60-90 seconds and tuning the proxy_read_timeout in Nginx does not fix the underlying slow queries. multiple analysts running concurrent heavy queries spike CPU past 90% and results start failing silently. you need row-level security tied to an SSO provider like Okta or Azure AD and the built-in LDAP config is not flexible enough. you want scheduled email reports delivered reliably at scale, which needs a dedicated Celery Beat setup and a persistent task queue.
at that point, look at managed Superset offerings like Preset.io, or evaluate whether a lighter BI tool fits your use case better. the full breakdown of self-hosted options is at /category/bi-tools/. for a direct feature comparison of Superset against its main alternatives, see Apache Superset vs Metabase and self-hosted BI tools compared.
Frequently Asked Questions
Can I run this on a 2 GB VPS?
Technically yes, but Superset’s Python workers plus the bundled Redis and Postgres containers together use around 2.5 GB at idle. a 2 GB VPS will swap continuously and queries will be painfully slow. start with 4 GB minimum and watch free -m after a few days of real usage.
How do I upgrade Superset to a newer version?
Pull the new image tag, run docker compose pull, bring the stack back up with docker compose up -d, then immediately run superset db upgrade and superset init inside the container. always pg_dump your metadata database before upgrading between minor versions because schema migrations are not always reversible.
Does this setup support multiple users with different permissions?
Yes. Superset has role-based access control built in with Viewer, Editor, and Admin roles out of the box. for SSO via Google, GitHub, or Okta, you configure Flask-AppBuilder’s OAuth settings in a superset_config.py file mounted into the container.
What databases can I connect to?
Any database with a SQLAlchemy driver. that covers PostgreSQL, MySQL, MariaDB, SQLite, BigQuery, Redshift, Snowflake, ClickHouse, DuckDB, Trino, Presto, and more. you install the Python driver inside the Superset container by adding it to a requirements-local.txt file and rebuilding the image.
How do I enable query result caching?
The Docker Compose setup includes Redis by default. add CACHE_CONFIG and DATA_CACHE_CONFIG blocks to your superset_config.py pointing at the Redis container hostname. Superset will then cache query results and dashboard thumbnails, which cuts load time dramatically for shared read-heavy dashboards.
Bottom Line
Self-hosting Superset on a VPS gives you a full-featured BI platform with no per-seat licensing fee and complete control over where your data goes. the Docker Compose path handles the multi-service complexity, and Nginx plus Certbot deliver a production-grade HTTPS frontend in under an hour of setup time. the ongoing operational cost is small: keep the metadata database backed up, run db upgrade and superset init after version bumps, and watch memory usage on smaller VPS instances. for a data team that wants SQL Lab, a rich chart library, and shareable dashboards without paying a managed cloud BI bill, this setup is solid and maintainable. when your query volumes or team size outgrow a single VPS, the /category/bi-tools/ section has comparisons of tools that scale with less operational overhead.