Files
notes/archive/discopharma/20250320-manual-project.md
Petar Cubela 252a91dbcc ]
2025-07-15 15:36:24 +02:00

11 KiB

title, author, date, geometry, output
title author date geometry output
Metabase - Setup Manual Petar Cubela March 20, 2025 margin=1.5cm pdf_document

Intro

Setting up a Metabase instance via Docker with a PostgreSQL application database and a secure web connection via https mediated by a public facing reverse proxy (nginx) and commercial TLS/SSL certificates.

Goals and Requirements

Software

VM Specs

Metabase Server

  • Name: Metabase Server
  • OS: Debian 12
  • hostname: mb-prod
  • IP Address: 10.156.0.6/24
  • CPU: 2 core
  • RAM: 2 GB (2048 MB)
  • Storage: depends (30 GB)
  • DNS entry: none
  • Note: for every 20 concurrent users: needs 1CPU and 2GB of RAM more

Reverse Proxy

  • Name: Reverse Proxy
  • OS: Debian 12
  • hostname: rproxy
  • IP Address: 10.156.0.7/24 + <PUBLIC IP> address (only activated in the end)
  • CPU: 1 core
  • RAM: 1 GB (1024 MB)
  • Storage: depends (16 GB)
  • DNS entry: metabase.discopharma.de -> <PUBLIC IP>
  • Note: for every concurrent users: needs 1CPU and 2GB of RAM more

Firewall

I list all necessary communications and respective ports needed:

Abbreviations:

  • Metabse: mb-prod = 10.156.0.6
  • Metabse Dev: mb-dev = 10.156.0.8
  • ReverseProxy: rp = 10.156.0.7
Source SourcePort Destination DestPort Description
mb-prod 3306/tcp db 3306/tcp 3306 is the standard mysql port. Communication of mb-prod to db
rp 3000/tcp
3000/udp
mb-prod 3000/tcp
3000/udp
3000 is the metabase web port. Reverse Proxy sends request via this port to mb.
rp 3000/tcp
3000/udp
mb-dev 3000/tcp
3000/udp
3000 is the metabase web port. Reverse Proxy sends request via this port to mb.
OPEN INTERNET any PUBLIC IP of rp 443/tcp 443 is the https port to communicate to rp over internet

Network Diagram

diagram

Metabase Application Server and Database

Administration

Update

In order to update the metabase containers change to the ~/metabase/ folder (where compose.yml file resides) and use the following command:

docker compose pull && docker compose up -d

Monitor the container logs to see if there are any errors by using the command:

docker compose logs -f

The docker compose pull command searches for images which are specified by a tag in the image variable in the compose.yml file: image: metabase/metabase:latest latest is here the tag and can also be changed to a version number which can be extracted from the docker-hub.

To simplify the process I wrote a simple bash script which updates the container images and removes old container images. The script is in the folder /home/lukas_discopharma_de/scripts/metabase-update.sh. The update has to be done manually.

Backup

There is a script /home/lukas_discopharma_de/db-backup.sh which creates a database dump from the postgres instance running in the container and places the dump into the folder at /home/lukas_discopharma_de/backup-db including the current date in the filename. The scripts runs weekly mondays at 2 a.m. via a cronjob. You should secure the backups/dumps to a secure location.

Development Instance

Go step-by-step through the installation and setup of a development metabase instance.

1. Setup VM

Setup the a new VM with specs as described in the VM specs section. The OS we are using is Debian 12. The private ip address can be chosen as 10.156.0.8

2. Update pkgs and install docker and compose

After Installation of the OS perform a pkg update:

sudo apt update && sudo apt upgrade -y

In order to install docker engine we will follow the official documentation.

  1. Set up Docker's apt repository
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
  1. Install the Docker packages (which includes docker compose)
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  1. Verify that the installation is successful by running the hello-world image
sudo docker run hello-world

It is possible to manage Docker as a non-root user. It the next steps we describe how to achieve this. We need to create a docker group and add to user we wish to use:

  1. Create the docker group
sudo groupadd docker
  1. Add your user to the docker group.
sudo usermod -aG docker $USER
  1. Log out and log back in so that your group membership is re-evaluated
  2. Verify that you can run docker commands without sudo
docker run hello-world

3. Create folder and compose file

After getting Docker Engine to work we can setup the necessary files and folders for the metabase container. Create a metabase folder for the docker compose files in your home folder:

mkdir -p ~/metabase/plugins

In addition create two files where the database user name and password will be placed:

touch ~/metabase/{db_user.txt,db_password.txt}

Create a compose.yml file which will be used to spin up the containers:

---
services:
  metabase:
    image: metabase/metabase:latest
    container_name: mb-dev
    hostname: mb-dev
    restart: unless-stopped
    volumes:
      - /dev/urandom:/dev/random:ro
      - ./plugins:/plugins
    ports:
      - 3000:3000
    environment:
      JAVA_TIMEZONE: Europe/Berlin
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: metabase
      MB_DB_PORT: 5432
      MB_DB_USER_FILE: /run/secrets/db_user
      MB_DB_PASS_FILE: /run/secrets/db_password
      MB_DB_HOST: postgres
    networks:
      - metanet1
    secrets:
      - db_password
      - db_user
    healthcheck:
      test: curl --fail -I http://localhost:3000/api/health || exit 1
      interval: 15s
      timeout: 5s
      retries: 5
  postgres:
    image: postgres:latest
    container_name: postgres-dev
    hostname: postgres-dev
    restart: unless-stopped
    environment:
      POSTGRES_USER_FILE: /run/secrets/db_user
      POSTGRES_DB: metabase
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    networks:
      - metanet1
    secrets:
      - db_password
      - db_user
networks:
  metanet1:
    driver: bridge
secrets:
  db_password:
    file: db_password.txt
  db_user:
    file: db_user.txt

Choose a name for the database user and place it in the db_user.txt file, e.g.:

echo "metabase" > db_user.txt

and accordingly for the password:

echo "SecurePass" > db_password.txt

Change the permissions of the files such that they are read-only for your own user:

chmod 400 db_*.txt

4. Pull images and start container

The pull of the container images and the start of the containers can be simply done by one command. Change the working directory to the metabase folder,

cd ~/metabase

and execute the command:

docker compose up -d

During the startup the log files for the containers should be monitored for possible errors by using the command:

docker compose logs -f

If you see now errors and if you have the possibility to reach the server you can visit the metabase instance using the URL http://<private-ip-of-server>:3000. Port 3000 has to be open and you have to be able to reache the server via its private ip address.

Reverse Proxy

The software which is used on the reverse proxy server is called nginx. This is a standard common web server/reverse proxy. Its configuration files reside in the folder /etc/nginx/ and its log files can be found in /var/logs/nginx/. The configuration file which accomplishes the reverse proxying for your metabase instance is /etc/nginx/sites-available/metabase.conf:

server {
        listen 80;
        listen [::]:80;
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name metabase.discopharma.de;

        ssl_certificate     /etc/nginx/ssl/discopharma.de/discopharma_fullchain.cer;
        ssl_certificate_key /etc/nginx/ssl/discopharma.de/discopharma_private.key;



        if ($ssl_protocol = "") {
            return 301 https://$server_name$request_uri;
        }

        location / {
                proxy_pass http://10.156.0.6:3000;
                proxy_set_header HOST $host;
        }
}

In order to reverse proxy traffic to a development instance you can proceed as follows:

  1. Create a nginx configuration file for the dev metabase instance by copying the existing config: cp /etc/nginx/sites-available/metabase.conf /etc/nginx/sites-available/mb-dev.conf
  2. Open the new file using any text editor nano /etc/nginx/sites-available/mb-dev.conf and edit the server_name and proxy_pass variables to reflect your new dev instance, e.g.: server_name mb-dev.discopharma.de; (the corresponding dns entry for mb-dev.discopharma.de has to point to the public ip of the reverse proxy) and proxy_pass http:<private-ip-of-server>:3000;
  3. Create a symbolic link (nignx reads the config files in sites-enabled):
ln -sf /etc/nginx/sites-available/mb-dev.conf /etc/nginx/sites-enabled/
  1. Restart the nignx service: systemctl restart nginx
  2. Setup your google firewall such that the reverse proxy can reach your dev metabase instance via port 3000.
  3. Visit https://mb-dev.discopharma.de. The homepage should working ssl certificates which are configured in the nginx configuration file for mb-dev.