How we run Homebox Demos

How we operate Homebox demo and Homebox nightly over Docker Rootless with no exposed ports, leveraging Cloudflare Tunnels.

· 4 min read
How we run Homebox Demos
Homebox - The simple home inventory solution

As you may be aware, we (fairly) recently, took over the development and operation of Homebox, the home inventory tracking software (https://homebox.software) - As part of this, it was clear that we required a demo instance to enable us to showcase the solution to our community.

With this, https://demo.homebox.software and https://nightly.homebox.software were created. In this blog, I will detail the technical details of how these two demo instances run, and why you may also like to follow a similar configuration.

The configuration

These two instances both operate using Docker compose, and are ran from my lab environment host (this is quite a powerful server, and so the resource was spare to put to use.)

On the server, I created a new folder for the demos at ~/docker/homebox-demos. Under this folder, I then created three new subfolders:

  • logs
  • Demo
  • Scripts

These will become clear in a moment.

Next, it was time to create a bespoke Docker-compose.yml file for these. I changed directory to Demo and ran nano docker-compose.yml - In here, the contents were:

services:
  homebox-demo:
#    image: ghcr.io/sysadminsmedia/homebox:latest
    image: ghcr.io/sysadminsmedia/homebox:latest-rootless
    container_name: homebox-demo
    restart: always
    environment:
    - HBOX_LOG_LEVEL=info
    - HBOX_LOG_FORMAT=text
    - HBOX_WEB_MAX_UPLOAD_SIZE=10
    - HBOX_DEMO=true
    volumes:
      - homebox-data:/data/
    networks:
      - Homebox-Demos

  homebox-nightly:
#    image: ghcr.io/sysadminsmedia/homebox:nightly
    image: ghcr.io/sysadminsmedia/homebox:latest-rootless
    container_name: homebox-nightly
    restart: always
    environment:
    - HBOX_LOG_LEVEL=info
    - HBOX_LOG_FORMAT=text
    - HBOX_WEB_MAX_UPLOAD_SIZE=10
    - HBOX_DEMO=true
    volumes:
      - homebox-data:/data/
    networks:
      - Homebox-Demos

  tunnel:
    container_name: cloudflared-tunnel
    image: cloudflare/cloudflared
    restart: unless-stopped
    command: tunnel --pq run
    environment:
      - TUNNEL_TOKEN={Token}
    networks:
          - Homebox-Demos

networks:
  Homebox-Demos: {}

volumes:
   homebox-data:
     driver: local

Homebox demos docker compose file

This is where it gets interesting - Lets break this YAML file down.

  1. You will note that the Nightly and Demo instances both operate on the same docker-compose. This is to allow easy management of a single Docker network for these two instances (and shared resources to make our demo instance easier for the community).
  2. You will note that there are no exposed ports - The Cloudflare Tunnel handles this for us.
  3. You will note that the demo instances both operate on the Homebox-Demos network. This is a custom Docker network, which allows us to segregate the Docker network traffic from other instances on the host.

The Cloudflare configuration

On Cloudflare, as we have pointed the TUNNEL_TOKEN environment variable to our tunnel, we should now see that this is available and healthy.

The configuration for our Homebox Cloudflare points to the docker containers (and ports) - Remember we didn’t expose the ports? Cloudflare handles this for us.

Homebox Demo/Nightly Cloudflare Tunnel configuration

Automating the rebuilds

To ensure that our demo instances are constantly up-to-date and that they pull down the relevant updates as required, I crafted a shell script. Given that these instances are only for demo data and we do not care about the contents of the instances, we discard the volumes on every rebuild (this also ensures that there is no ballooning of orphaned volumes!)

In docker/homebox-demos/scripts we created a new file called deployments.sh:

#!/bin/bash

# Function to post failure message to Discord webhook
post_failure() {
    local title=$1
    local description=$2
    local date=$(date +"%Y-%m-%d %H:%M:%S")
    local webhook_url="{Discord_webhook}"

    curl -H "Content-Type: application/json" -X POST -d "{
        \"embeds\": [{
            \"title\": \"$title\",
            \"description\": \"$description on $date. Please review and remediate.\"
        }]
    }" $webhook_url
}

# Function to check if the service is available
check_service() {
    local url=$1
    local failure_title=$2
    local failure_description=$3

    if ! curl -s --head --request GET $url | grep "200" > /dev/null; then
        post_failure "$failure_title" "$failure_description"
    else
        echo "Service at $url is up and running."
    fi
}

# Step 1: Change directory to ~/docker/homebox-demos/demo
cd ~/docker/homebox-demos/demo || { echo "Failed to navigate to ~/docker/homebox-demos/demo"; exit 1; }

# Step 2: Remove old Docker volumes
docker compose down -v

# Step 3:  Pull the latest versions of the images using docker compose
docker compose pull
 
# Step 4: Start the updated containers
docker compose up -d

# Step 5: Check if nightly demo is available
check_service "https://nightly.homebox.software" "Nightly deployment FAILED" "The latest deployment of the nightly demos has failed to deploy to https://nightly.homebox.software"

# Step 6: Check if demo is available
check_service "https://demo.homebox.software" "Demo deployment FAILED" "The latest deployment of the demo has failed to deploy to https://demo.homebox.software"

Let’s break this script down.

  1. We created a new function for posting about failed deployments. This sends a message to the Homebox Discord server ( https://discord.homebox.software ) if the deployment fails for whatever reason.
  2. We also created a function to handle the checks to ensure that our instances are online - These both run a grep on the URL to check for a status code of 200. If a status of 200 is not returned, the service is deemed to be down.
  3. Then, we run the usual commands:
    1. Change directory to where the demos are stored
    2. Remove old Docker volumes
    3. Pull the latest versions of the images
    4. Start the updated containers
    5. Check if the services are up

Crontask

To tie this all in, we then run a crontask which runs every hour. The reason for running this every hour is to ensure that the services are always operating at their optimum, and that any changes are pushed through. This also ensures that the demos are reverted back to a clean slate if anyone decides that they want to spend their time to deface it (or create obscene items, which we’ve had)

The crontask runs as follows:

0 * * * * > ~/docker/homebox-demos/logs/deployment.log && /bin/bash ~/docker/homebox-demos/scripts/deployment.sh >> ~/docker/homebox-demos/logs/deployment.log 2>&1 

Breaking this down, this means that every hour, the deployment log gets cleared, and the deployment shell script is ran. The output of this is then saved to the deployment logs for if this goes wrong.