Umami is an open-source, privacy-focused web analytics tool that serves as an alternative to Google Analytics. Its free plan comes with certain limits — including 6 months of data retention, support for up to 3 websites, and a cap of 100,000 events per month. However, you can self-host Umami on your own server to access all its features without paying a dime.
In this tutorial, I’ll walk you through how to self-host Umami on Oracle Cloud (OCI), using their Free Tier resources. For the tech stack, we’ll use Nginx as web server, Cloudflare SSL, and Docker Compose for deployment. Now let’s begin.
Launch a new Instance on OCI
Refer to this article for instructions on how to launch a new Instance on OCI. When configuring the instance, allocate at least 1 OCPU and 2GB of RAM to ensure Umami runs smoothly.
Prepare a domain or sub-domain
You must have a domain or sub-domain to access Umami, for example, yourdomain.com or data.yourdomain.com. And point its DNS record to the instance’s public IP address.
In the Instances dashboard of Oracle, you can see the Public IP of each Instance. Use your DNS manager (in this case is Cloudflare) to point to this IP.
Install Docker and Docker Compose
We’ll use Docker Compose to deploy the whole Umami package — including Umami itself and PostgreSQL.
Connect to your server via SSH.
Update and upgrade your server:
sudo apt update && sudo apt upgrade -y
Code language: Bash (bash)
Install necessary packages for Docker:
sudo apt install -y curl ca-certificates apt-transport-https software-properties-common
Code language: Bash (bash)
Add new official GPG Key to verify the authenticity of Docker’s repository to ensure you’re downloading trusted software:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo install -m 0755 -d /usr/share/keyrings/
Code language: Bash (bash)
Verify the repo:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Code language: Bash (bash)
Update the packages list:
sudo apt update
Code language: Bash (bash)
Install Docker & Docker Compose:
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Code language: Bash (bash)
Start Docker:
sudo systemctl start docker
Code language: Bash (bash)
Verify the status of Docker & Docker Compose:
sudo systemctl status docker
sudo docker --version
sudo docker compose version
Code language: Bash (bash)
Enable Docker to start on server boot:
sudo systemctl enable docker
sudo systemctl enable containerd
Code language: Shell Session (shell)
Set up Docker Compose
In this step, we’ll set up the .env and Docker Compose YAML configuration files. The structure of your Umami project directory should look like this:
/umami/
|-- .env
|-- docker-compose.ymlCode language: Bash (bash)
Create a new directory for Umami project and switch to it:
mkdir umami && cd umami
Code language: Shell Session (shell)
.env file
Create new .env file:
sudo touch .env
Code language: Bash (bash)
Set owner and permission for .env file:
sudo chown ubuntu:ubuntu .env
sudo chmod 600 .env
Code language: Bash (bash)
Open .env file:
sudo nano .env
Code language: Bash (bash)
And paste this content to the file:
# Umami environment variables
DATABASE_URL=postgresql://umami_user:umami_pass@db:5432/umami_db
DATABASE_TYPE=postgresql
APP_SECRET=your_random_secret_key
# PostgreSQL environment variables
POSTGRES_DB=umami_db
POSTGRES_USER=umami_user
POSTGRES_PASSWORD=umami_passCode language: YAML (yaml)
And update these parameters:
POSTGRES_PASSWORD: change fromumami_passto a strong password.DATABASE_URL: Update your new password to theumami_passpart of the string.
For the APP_SECRET parameter, you need to enter this command:
openssl rand -hex 32
Code language: Bash (bash)
The terminal will output a string like this (DO NOT COPY this string):
cedc41a9c7a8c019866d4c38905165f516e089190651ff08f1a01c3b0612fa04Code language: plaintext (plaintext)
Replace your_random_secret_key with the string generated by the openssl command.
Press Ctrl + X, then Y to close and save the .env file.
docker-compose.yml file
Create and open docker-compose.yml file:
sudo nano docker-compose.yml
Code language: Bash (bash)
Paste this content to that file:
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
- "3000:3000"
env_file: .env
environment:
- DATABASE_URL=${DATABASE_URL}
- DATABASE_TYPE=${DATABASE_TYPE}
- APP_SECRET=${APP_SECRET}
depends_on:
- db
restart: always
networks:
- umami-net
db:
image: postgres:latest
env_file: .env
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- umami-db-data:/var/lib/postgresql/data
restart: always
networks:
- umami-net
networks:
umami-net:
driver: bridge
volumes:
umami-db-data:
Code language: YAML (yaml)
Change its permission:
sudo chmod 600 docker-compose.yml
Code language: Bash (bash)
Start Umami:
sudo docker compose up -d
Code language: Bash (bash)
Install Nginx
Enter these commands to install Nginx and enable it to start on server boot:
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Code language: Shell Session (shell)
Create and open the Nginx configuration file for Umami:
sudo nano /etc/nginx/sites-available/umami
Code language: Bash (bash)
Paste this content to that file:
server {
listen 80;
server_name yourdomain.com;
# Deny access to .env files
location ~* \.env$ {
deny all;
return 403;
}
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
# Deny access to .env files
location ~* \.env$ {
deny all;
return 403;
}
# Reverse proxy to Umami (Docker container)
location / {
proxy_pass http://localhost:3000;
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;
}
# Logs
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# SSL certificate
ssl_certificate /etc/ssl/certs/cloudflare.pem;
ssl_certificate_key /etc/ssl/private/cloudflare.key;
# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://icons.duckduckgo.com; connect-src 'self';";
}
Code language: Nginx (nginx)
Update your server_name (line 3, 16).
For the SSL certificate files (line 38, 39), refer to this article for instructions on how to obtain them.
Press Ctrl + X, then Y to close and save the file.
Activate the above configuration by linking that config file to the sites-enableddirectory:
sudo ln -s /etc/nginx/sites-available/umami /etc/nginx/sites-enabled/
Code language: Bash (bash)
Remove the default config file:
sudo rm /etc/nginx/sites-enabled/default
Code language: Bash (bash)
Check the Nginx syntax and reload it:
sudo nginx -t
sudo systemctl reload nginx
Code language: Bash (bash)
Now you can visit yourdomain.com to use Umami. The default login credentials are:
username: admin
password: umamiCode language: plaintext (plaintext)
After logging in, change your password in the Umami’s Settings.
Done.