Homer is a static homepage for your self-hosted services. It has no database and no backend: a single config.yml file describes groups of links, and the page is rendered entirely in the browser. In this tutorial you will run Homer with Docker on Ubuntu 24.04, build a dashboard with grouped services and icons, add status checks, and publish it over HTTPS behind Nginx with password protection.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS. Homer uses only a few megabytes of RAM.
  • A non-root user with sudo privileges.
  • Docker Engine and the Docker Compose plugin installed from Docker's official repository.
  • A domain name with an A record pointing to your server. This guide uses home.your_domain.
  • Ports 80 and 443 reachable from the internet.

Step 1 - Running Homer with Docker Compose

Create a directory for Homer. The assets subdirectory holds config.yml, icons and any custom CSS, and is mounted into the container:

sudo mkdir -p /opt/homer/assets
sudo chown 1000:1000 /opt/homer/assets
cd /opt/homer

The container runs as UID 1000, so it needs to own the assets directory. Create the Compose file:

sudo nano /opt/homer/docker-compose.yml
services:
  homer:
    image: b4bz/homer:latest
    restart: unless-stopped
    user: "1000:1000"
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      INIT_ASSETS: "1"
    volumes:
      - ./assets:/www/assets

With INIT_ASSETS=1, Homer copies a sample config.yml, a logo and icons into the empty assets directory on first start. The port is bound to 127.0.0.1 so the dashboard is only reachable through Nginx; ports published by Docker bypass UFW.

Start the container:

sudo docker compose up -d

Check that the sample files were created and that the page is served:

ls /opt/homer/assets
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/
config.yml  icons  logo.png  ...
200

Step 2 - Writing the dashboard configuration

Everything Homer shows comes from /opt/homer/assets/config.yml. Replace the sample with your own configuration:

sudo nano /opt/homer/assets/config.yml

The following example defines the page header, a dark theme, and two groups of services. Replace the URLs with your own services:

title: "Dashboard"
subtitle: "your_domain services"
logo: "assets/logo.png"

header: true
footer: false
columns: "3"

defaults:
  layout: columns
  colorTheme: dark

services:
  - name: "Monitoring"
    icon: "fas fa-heartbeat"
    items:
      - name: "Grafana"
        logo: "assets/icons/grafana.png"
        subtitle: "Metrics and dashboards"
        tag: "monitoring"
        url: "https://grafana.your_domain"
        target: "_blank"
      - name: "Uptime Kuma"
        logo: "assets/icons/uptime-kuma.png"
        subtitle: "Status checks"
        url: "https://status.your_domain"
        target: "_blank"

  - name: "Tools"
    icon: "fas fa-toolbox"
    items:
      - name: "Gitea"
        logo: "assets/icons/gitea.png"
        subtitle: "Git hosting"
        tag: "dev"
        keywords: "git code repositories"
        url: "https://git.your_domain"
        target: "_blank"
      - name: "Nextcloud"
        icon: "fas fa-cloud"
        subtitle: "Files and calendars"
        url: "https://cloud.your_domain"
        target: "_blank"

Key fields:

  • defaults.colorTheme accepts auto, light or dark; defaults.layout accepts columns or list. Visitors can still switch both from the page header.
  • Each group has a name, an optional Font Awesome icon and a list of items.
  • Each item needs a name and a url. Use either logo (an image path) or icon (a Font Awesome class such as fas fa-cloud).
  • tag shows a small label on the card and keywords adds extra terms for the search box.

YAML is sensitive to indentation, so validate the file before reloading the page:

python3 -c "import yaml, sys; yaml.safe_load(open('/opt/homer/assets/config.yml')); print('config.yml OK')"
config.yml OK

Homer reads the file in the browser, so there is nothing to restart: reload the page to see the changes.

Step 3 - Adding service icons

Homer ships with the free Font Awesome icon set, which covers generic services. For application logos, the community Dashboard Icons collection provides PNG and SVG files named after each application. Download the logos referenced in the configuration into the icons directory:

cd /opt/homer/assets/icons
for app in grafana uptime-kuma gitea; do
  sudo curl -fsSLO "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/${app}.png"
done
ls -l grafana.png uptime-kuma.png gitea.png

curl -f stops with an error instead of saving an HTML error page if a name does not exist. Browse the collection on its GitHub repository (homarr-labs/dashboard-icons) to find the exact file name of other applications.

To use your own image, copy it into /opt/homer/assets/icons/ and reference it with a relative path such as assets/icons/myapp.png. Absolute server paths do not work because the browser loads the file over HTTP.

Step 4 - Adding status checks

Homer can show whether a service is up by using a smart card type. The simplest one is Ping, which requests the URL and shows a green or red indicator:

      - name: "Grafana"
        logo: "assets/icons/grafana.png"
        subtitle: "Metrics and dashboards"
        url: "https://grafana.your_domain"
        type: "Ping"

Other types, such as Prometheus, Portainer or Gitea, read extra information from the service's API. Check the smart cards page in the Homer repository for the exact options each type needs.

Step 5 - Publishing Homer with Nginx, HTTPS and a password

Homer has no login of its own, and a list of your internal services should not be public. Nginx will add HTTPS and HTTP basic authentication.

Install Nginx, Certbot and the htpasswd tool:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx apache2-utils
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'

Create a password file with a user for yourself. The command prompts for the password:

sudo htpasswd -c /etc/nginx/.htpasswd-homer your_user

Create the server block:

sudo nano /etc/nginx/sites-available/homer
server {
    listen 80;
    listen [::]:80;
    server_name home.your_domain;

    auth_basic "Dashboard";
    auth_basic_user_file /etc/nginx/.htpasswd-homer;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

Enable it, test and reload:

sudo ln -s /etc/nginx/sites-available/homer /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Request the certificate. Certbot adds the TLS configuration and the redirect from HTTP to HTTPS:

sudo certbot --nginx -d home.your_domain

Verify that the page now requires credentials:

curl -s -o /dev/null -w "%{http_code}\n" https://home.your_domain/
curl -s -o /dev/null -w "%{http_code}\n" -u your_user:your_password https://home.your_domain/
401
200

Open https://home.your_domain in your browser, log in, and your dashboard appears.

Step 6 - Customizing the look

Beyond colorTheme, you can override individual colors in config.yml with the colors key, which has a light and a dark block:

colors:
  dark:
    highlight-primary: "#1f6feb"
    highlight-secondary: "#388bfd"
    background: "#0d1117"
    card-background: "#161b22"
    text: "#e6edf3"

For changes that the color keys do not cover, add a stylesheet. Create /opt/homer/assets/custom.css:

sudo nano /opt/homer/assets/custom.css
.card {
  border-radius: 10px;
}

Then reference it from config.yml:

stylesheet:
  - "assets/custom.css"

Reload the page (use a hard refresh if your browser cached the old files).

Troubleshooting

The page is blank after editing config.yml. Almost always a YAML error. Run the validation command from Step 2, which prints the line and column of the problem.

Changes to config.yml do not appear. The browser may be serving a cached copy. Do a hard refresh, and confirm that you edited /opt/homer/assets/config.yml on the host, which is the file mounted into the container.

The sample files are not created on first start. The container runs as UID 1000 and cannot write to assets if it belongs to root. Fix it with sudo chown -R 1000:1000 /opt/homer/assets and run sudo docker compose restart.

An icon shows as broken. Open https://home.your_domain/assets/icons/name.png directly. A 404 means the path in config.yml or the file name is wrong.

Conclusion

You now have a Homer dashboard running in Docker, configured from a single YAML file, with application icons, status indicators and password-protected HTTPS access. Because the whole configuration is one file, consider keeping /opt/homer/assets in a Git repository; you can also add more smart cards for services that expose an API, or place Homer behind a single sign-on proxy instead of basic authentication.