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
sudoprivileges. - 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.colorThemeacceptsauto,lightordark;defaults.layoutacceptscolumnsorlist. Visitors can still switch both from the page header.- Each group has a
name, an optional Font Awesomeiconand a list ofitems. - Each item needs a
nameand aurl. Use eitherlogo(an image path) oricon(a Font Awesome class such asfas fa-cloud). tagshows a small label on the card andkeywordsadds 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.
ImportantStatus checks run in the visitor's browser, not in the container. The browser must be able to reach the URL, and the target service must allow the request (CORS). Internal Docker hostnames such as
http://grafana:3000will not work.
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.
