Deploying Metabase on Amazon Lightsail

Metabase is an easy, open-source tool for querying and visualizing data. In this article, we will walk through deploying Metabase on an Amazon Lightsail instance with docker and securing our server with an SSL Certificate.

Setting up Amazon Lightsail

  1. Access the Lightsail service on your AWS Console and create an OS Only instance running Ubuntu 20.
Choose availability region
Choose instance OS and image
Choose instance plan
Choose a name for your instance and click `Create instance`

You will be redirected to the Lightsail dashboard where you will find your new instance being provisioned. After a few seconds, the provisioning should be complete and the status should change from ‘pending’ to ‘running.

Our instance is now up and running.

2. The next thing we want to do is to connect to our instance via SSH and start installing the tools we need to get Metabase running but first, we will need to create a static IP address and attach it to our instance. Go to the networking tab on your Lightsail dashboard and click ‘create static IP’.

You will be redirected to this page where you will choose the instance to which to attach the static IP address (‘metabase-demo’ in our case) and also a name for the static IP address (‘metabase-demo-ip’)
Static IP address is now created and attached to our metabase-demo instance.

3. Now that we have a static IP attached to our instance we will proceed to connect using a terminal via SSH protocol. Go to the accounts page via the Account menu on the navbar and click the SSH keys tab to download your SSH key. You must download the key associated with the availability zone of your instance which in our case is Frankfurt (eu-central-1). ( You can verify this on your Lightsail dashboard at the bottom right corner of your instance’s display card).

4. Time to connect to our Lightsail instance. Open a terminal on your machine and run the following command.

$ sudo chmod 600 /path/to/ssh-key
$ ssh -i /path/to/ssh-key ubuntu@<static-IP>

Answer ‘yes’ to the prompt and you should now be logged in to your Lightsail instance.

5. We will be running Metabase and Postgres in docker containers so we would need to install docker and docker-compose. Run the following commands to install docker and docker-compose

Docker

$ sudo apt update && sudo apt install apt-transport-https ca-certificates curl software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable" && sudo apt update && apt-cache policy docker-ce && sudo apt install docker-ce && sudo systemctl status docker

Once you get the printout above, the installation is successful. Hit ‘q’ on your keyboard and proceed to install docker-compose.

Docker-Compose

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose && docker-compose --version

6. We are almost done with the configuration. The last configuration we will be doing is as a result of our RAM size. Our instance is running on 512MB RAM and Metabase needs a little more room to run efficiently. If you had created your instance with 1GB ram and above then you can skip this step. But for mere mortals like us on a budget, we will need to create a ‘swap space’. This is just a region on the SSD allocated to be used as extra RAM once the RAM is full. This is a pretty straightforward process. We will use the following command to create 2GB of swap space from our storage.

$ sudo fallocate -l 2G /swapfile && sudo dd if=/dev/zero of=/swapfile bs=1024 count=2097152 && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile && sudo nano /etc/fstab

Once nano pops up, move the cursor to the next line and paste in the following.

/swapfile swap swap defaults 0 0

Then Ctrl X, Y, Enter to save and you’re out of nano and good to go.

Running our Metabase and Postgres Containers

1. So far, we haven’t done anything related to Metabase. But fortunately, we are out of the primary configuration phase and can now proceed to build and run a Metabase container. Create a folder called Metabase, cd into this folder, and create a docker-compose.yml file.

$ mkdir Metabase && cd Metabase/ && nano docker-compose.yml

When the nano interface pops up, paste in the following.

version: "3"
services:
postgres-db:
image: postgres
restart: always
ports:
- 5432:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: metabase
PGDATA: /var/lib/postgresql/data
volumes:
- /home/ubuntu/pgdata:/var/lib/postgresql/data
metabase-app:
image: metabase/metabase
restart: always
ports:
- 3000:3000
volumes:
- /home/ubuntu/metabase-data:/metabase-data
environment:
MB_DB_TYPE: postgres
MB_DB_DBNAME: metabase
MB_DB_PORT: 5432
MB_DB_USER: postgres
MB_DB_PASS: postgres
MB_DB_HOST: postgres-db
depends_on:
- postgres-db
links:
- postgres-db

Save and close the file, then spin up the containers with the following command.

$ sudo docker-compose up

You should run it without the ‘detached’ flag so you can see the logs of both containers, especially if you’re deploying Metabase for the first time. You should also wait till the last log from the ‘metabase-app’ container is Metabase initialization COMPLETE . To test that everything is working fine, go to the ‘Networking’ tab of your Metabase instance on your Lightsail dashboard and add a ‘Custom’ Ipv4 Firewall Rule with TCP protocol on port 3000. Then paste the following in a fresh browser tab.

<static-IP>:3000

… where <static-IP> is the static IP address of your instance. It will load for a while and then the following should show up.

2. We have come a great way. You can click the `Let’s get started` button and go through Metabase’s straightforward setup process. At this stage, you probably want to kill the containers and restart them in detached mode.

$ sudo docker-compose up -d

Configuring a reverse-proxy server and setting up a Subdomain

For performance, security and reliability, we want to use a much more robust web server than our Metabase container’s web server. More specifically, we want to put a much more reliable server between the internet and our Metabase container. We will use nginx.

  1. Run the following command to install and enable nginx.
$ sudo apt-get update && sudo apt-get install nginx && sudo systemctl start nginx && sudo systemctl enable nginx && sudo systemctl status nginx

Respond in the affirmative to any prompts. The installation should end with.

If you paste your instance’s static IP address in the browser, you should get:

2. Remove this default landing page by removing the symbolic link to the default configuration file.

$ sudo unlink /etc/nginx/sites-enabled/default

3. Now we will create a new configuration file for our Metabase server.

$ sudo nano /etc/nginx/sites-available/metabase.conf

This brings up a nano interface into which you should paste the following.

server {listen 80;
location / {
proxy_pass http://localhost:3000/; }}

Then save and close the file.

4. Create a symbolic link for this new configuration file.

$ sudo ln -s /etc/nginx/sites-available/metabase.conf /etc/nginx/sites-enabled/metabase.conf

Then test the new configuration with the following commands.

$ sudo service nginx configtest && sudo service nginx restart

If you reload the browser tab into which you pasted your static IP, the Nginx landing page should now be replaced with the Metabase landing page.

If you mess anything up, for example, a typo in your `metabase.conf` file (which happened to me a lot), you should:

Check the Nginx logs for the exact error with

$ cat /var/log/nginx/error.log

For example, if I had initially missed the ‘/’ on line 3 in my metabase.conf file like so:

server {
listen 80;
location {
proxy_pass http://localhost:3000/;
}
}

… and gone ahead to enable the config and restart Nginx, I would get an error page when I load the IP in the browser.

Checking the Nginx error log would reveal the following message.

$ cat /var/log/nginx/error.log 
10 2021/05/18 14:42:46 [emerg] 64343#64343: invalid number of arguments in "location" directive in /etc/nginx/sites-enabled/metabase.conf:3

Just correct the `metabase.conf` file as necessary and run the following commands.

$ sudo rm /etc/nginx/sites-enabled/metabase.conf
$ sudo ln -s /etc/nginx/sites-available/metabase.conf /etc/nginx/sites-enabled/metabase.conf
$ sudo service nginx configtest && sudo service nginx restart

Given that there are no more errors in the conf file, the site should be back up and running.

5. If you have a domain/hosted zone, you can simply create an A record to point to the IP of your Metabase instance on whatever DNS Registrar you are using.

Once the subdomain is set up, you can now access Metabase via URL

Securing Metabase with an SSL Certificate

  1. Run the following command to install Cerbot.
$ sudo apt update && sudo apt install certbot python3-certbot-nginx

2. Open the `metabase.conf` file and add the following just before the location directive

server_name <metabase-domain>;

where <metabase-domain> is the name of the record you created with your hosting provider. (`metabase.aminuolawale.com` in my case).

3. Update the enabled sites like so

$ sudo rm /etc/nginx/sites-enabled/metabase.conf
$ sudo ln -s /etc/nginx/sites-available/metabase.conf /etc/nginx/sites-enabled/metabase.conf

4. Install the certificate with the following command.

$ sudo certbot --nginx -d <metabase-domain>

Fill in the info requested correctly and answer in the affirmative to the prompts. Alas, you should get:

5. Configure your firewall to allow only HTTPS:

$ sudo ufw allow 'Nginx HTTPS' && sudo ufw deny 'Nginx HTTP' && sudo ufw allow 'Nginx Full' && sudo ufw enable && sudo ufw status

You should get:

6. Now on your Lightsail dashboard, visit your instance’s Networking tab and add an HTTPS Rule. You should also delete the custom rule we had created on port 3000. Your networking tab should look like this at the end:

Now type your Metabase URL in the browser and it should load with HTTPS!

7. Now that we have concluded the deployment and configuration phase, we can now connect Metabase to our data warehouse and start viewing tables and creating charts!

Thanks for reading!

Software Engineer. 3D Artist.