Homepage with Docker: One Dashboard for All Your Services (Linux, Windows, Mac)
Before you start
- 19 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
Homepage is a free, self-hosted start page: one fast dashboard with links, live status and widgets for all the services you run, configured with a few YAML files and shown in any browser.

Logo: the official Homepage project (github.com/gethomepage/homepage)
Instead of remembering ten ports, you open one page and see which services are up, what they are doing and where to click. Homepage has over 100 service integrations (our guides on Uptime Kuma and Beszel are two of them), proxies every API call on the server so your keys never reach the browser, and can find your Docker containers by labels. The two things that trip people up are the HOMEPAGE_ALLOWED_HOSTS variable, which is required, and the Docker socket, which is powerful. This guide handles both.
| Current version | v2.7.0 (released October 2026), GitHub release page |
| Time needed | About 15 minutes (our estimate: two small files and one docker compose up) |
| RAM | No official minimum. One user saw about 125 MB in use after a 128 MB limit made the container exit |
| Ports | 3000 (web interface) |
| Licence | GPL-3.0 (open source) |
| Platforms | Docker images for linux/amd64 and linux/arm64 |
| Official docs | gethomepage.dev and github.com/gethomepage/homepage |
At a glance:
- What it is: a Next.js application dashboard; its config is YAML files in one folder you mount into the container.
- What it shows: your services as tiles, with optional widgets (counts, uptime, queue sizes), container status, weather, search and bookmarks.
- Keys stay on the server: "All API requests to backend services are proxied, keeping your API keys hidden" (README). You still keep them out of your config files, see Step 3.
- Required setting:
HOMEPAGE_ALLOWED_HOSTS, since v1.0, for any address other thanlocalhost. - Optional login: since v2.0 a built-in password or OIDC gate, off by default.
- Our setup: a pinned image, a
.envsecrets file, and a read-only Docker socket proxy instead of the raw socket.
How it fits together#
Your browser only ever talks to Homepage; Homepage reads your config and talks to your services.
Dashed boxes are optional. The host check comes first: a request with a Host that is not on the list never reaches your services. Drawn from the official docs, October 2026.
Before you start#
You need Docker with Compose. Any small machine works; Homepage is a light Node.js app.
| System | What to have |
|---|---|
| Linux | Docker Engine with the Compose plugin; the images exist for amd64 and arm64 |
| Windows | Docker Desktop (WSL 2 backend), PowerShell |
| Mac | Docker Desktop, Terminal |
Check Docker on each system (same commands):
docker --version docker compose version
Checklist before you install:
- [ ] Port 3000 is free (
docker psshows nothing on it) - [ ] You know the address you will type in the browser, for example
<server-ip>:3000orlocalhost:3000 - [ ] For widgets: the web address and, where needed, the login or API key of each service
- [ ] Only for the HTTPS section: a domain, DNS pointing at the server, and ports 80/443 open
Tested on: not run by DIY Lab Hub for this guide. Every command comes from the official docs (v2.7.0) and the Docker image registry, read in October 2026. The Windows and Mac steps use the same Compose file as Linux; the Homepage docs only describe Linux paths.
Step 1: Create the folders and the secrets file#
Everything lives in one folder, ~/docker_volumes/homepage: config (your YAML files and logs), backups, and a .env file for settings and secrets.
Linux#
mkdir -p ~/docker_volumes/homepage/{config,backups}
cd ~/docker_volumes/homepage
printf 'HOMEPAGE_ALLOWED_HOSTS=<server-ip>:3000\nPUID=%s\nPGID=%s\n' "$(id -u)" "$(id -g)" > .env
chmod 600 .env
PUID and PGID make the container run as you, so the files in config are yours, not root's. Replace <server-ip> with the address you type in the browser. On the same machine you can use localhost:3000.
Windows (PowerShell)#
New-Item -ItemType Directory -Force "$HOME\docker_volumes\homepage\config","$HOME\docker_volumes\homepage\backups" | Out-Null
Set-Location "$HOME\docker_volumes\homepage"
Set-Content -Path .env -Value "HOMEPAGE_ALLOWED_HOSTS=localhost:3000"
icacls .env /inheritance:r /grant:r "${env:USERNAME}:(R,W)"
We leave PUID and PGID out on Windows; the image then runs as root, which is its documented default.
Mac (Terminal)#
Same commands as Linux, but leave PUID/PGID out like on Windows:
mkdir -p ~/docker_volumes/homepage/{config,backups}
cd ~/docker_volumes/homepage
printf 'HOMEPAGE_ALLOWED_HOSTS=localhost:3000\n' > .env
chmod 600 .env
Check it worked. The folder has a config and a backups directory and a .env file only you can read (ls -la on Linux and Mac, Get-ChildItem -Force on Windows).
Tip:
HOMEPAGE_ALLOWED_HOSTSis a comma-separated list with no spaces, and each entry is the host exactly as you type it in the browser, with the port when it is not 80 or 443:<server-ip>:3000,home.example.com. You do not need to addlocalhost:3000or127.0.0.1:3000, they are always included.
Step 2: Write the Compose file and start Homepage#
Save this as compose.yaml in ~/docker_volumes/homepage (any editor). It has no version: line, and the image is pinned to v2.7.0 instead of the latest tag the docs show.
services:
homepage:
image: ghcr.io/gethomepage/homepage:v2.7.0
container_name: homepage
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env
volumes:
- ./config:/app/config
Linux#
cd ~/docker_volumes/homepage nano compose.yaml docker compose up -d docker compose ps
Windows (PowerShell)#
Set-Location "$HOME\docker_volumes\homepage" notepad compose.yaml docker compose up -d docker compose ps
Mac (Terminal)#
Same commands as Linux:
cd ~/docker_volumes/homepage nano compose.yaml docker compose up -d docker compose ps
Check it worked. The image has its own health check (every 10 seconds against /api/healthcheck), so after about half a minute docker compose ps should show homepage as Up ... (healthy) (expected from the Dockerfile; we did not run it). Open http://localhost:3000 or http://<server-ip>:3000: you get the default dashboard with a resources widget and a search box.
On the first start Homepage copies its skeleton files into config. A user's v2.7.0 log shows lines like this:
info: kubernetes.yaml was copied to the config folder
Look in config and you find bookmarks.yaml, custom.css, custom.js, docker.yaml, kubernetes.yaml, proxmox.yaml, services.yaml, settings.yaml and widgets.yaml. These are the files you edit next.
Tip: Seeing
Host validation failed. See logs for more details.in the browser? Rundocker logs homepage --tail 20. The log names the exact host it refused. Copy that host intoHOMEPAGE_ALLOWED_HOSTSin.env, then recreate the container withdocker compose up -d --force-recreate. A plain restart does not re-read environment variables; the maintainer says so in discussions 5290 and 6094.
Step 3: Add your first services, with keys kept out of the YAML#
Open config/services.yaml (replace its content). This example adds a link plus live widget for Uptime Kuma and Beszel. If you have not installed them yet, see our Uptime Kuma guide and our Beszel guide.
- Monitoring:
- Uptime Kuma:
icon: uptime-kuma.png
href: http://<kuma-address>:3001
description: Are my sites up?
widget:
type: uptimekuma
url: http://<kuma-address>:3001
slug: <status-page-slug>
- Beszel:
icon: beszel.png
href: http://<beszel-address>:8090
description: Server stats
widget:
type: beszel
url: http://<beszel-address>:8090
username: "{{HOMEPAGE_VAR_BESZEL_USER}}"
password: "{{HOMEPAGE_VAR_BESZEL_PASSWORD}}"
version: 2
What the widgets need, from the official widget pages:
| Widget | Needs | Notes |
|---|---|---|
| Uptime Kuma | A status page and its slug (the part after /status/) | No API key. url is the base address only |
| Beszel | A Beszel superuser login | version: 2 for Beszel 0.9.0 and newer |
The secrets go in .env, not in the YAML. Any variable that starts with HOMEPAGE_VAR_ replaces {{HOMEPAGE_VAR_...}} in your config files. Add these lines to .env (edit it with nano .env on Linux and Mac, notepad .env on Windows):
HOMEPAGE_VAR_BESZEL_USER=<your-beszel-email> HOMEPAGE_VAR_BESZEL_PASSWORD=<your-beszel-password>
Prefer files? HOMEPAGE_FILE_BESZEL_PASSWORD=/run/secrets/beszel makes {{HOMEPAGE_FILE_BESZEL_PASSWORD}} read the file's contents (the value must be a file path).
Linux#
cd ~/docker_volumes/homepage nano config/services.yaml nano .env docker compose up -d --force-recreate
Windows (PowerShell)#
Set-Location "$HOME\docker_volumes\homepage" notepad config\services.yaml notepad .env docker compose up -d --force-recreate
Mac (Terminal)#
Same commands as Linux:
cd ~/docker_volumes/homepage nano config/services.yaml nano .env docker compose up -d --force-recreate
Check it worked. Reload the dashboard. You see a Monitoring group with two tiles, each with its numbers (up/down for Uptime Kuma, systems for Beszel). After later changes to settings.yaml or services.yaml, click the refresh icon at the bottom right of the page to clear the cache. A red "API Error" button on a widget opens the error details; the cause is almost always the url.
Tip: Never type a real key into a screenshot, a forum post or a shared config. Keep keys in
.envand share the YAML with the{{HOMEPAGE_VAR_...}}placeholders in it. If a key did leak, create a new one in that service.
Tip:
localhostinside the Homepage container means the Homepage container itself. Use the other service's real address, or put both containers on one Docker network and use its container name. The troubleshooting page of the docs tests this withdocker exec homepage ping <address>.
Step 4: Show container status (optional, with a socket proxy)#
Homepage can show a green or red dot for each container, and stats when you click it. This needs the Docker API, and that is the risky part.
The risk, in plain words. The Docker socket is the control panel of your machine. The documented easy way is to mount it into Homepage (/var/run/docker.sock:/var/run/docker.sock:ro). The authors of the Docker Socket Proxy put it bluntly: "Giving access to your Docker socket could mean giving root access to your host." The Homepage docs call mounting the socket "not the recommended method", and for the direct socket Homepage must run as root (or your user must be in the docker group). If anything in the dashboard were ever abused, the socket is what the attacker would reach for.
The documented safer option. Homepage's own Docker page recommends a docker-socket-proxy container. Only the proxy touches the socket. It answers Homepage over plain HTTP with an API that is cut down by switches; POST=0 means only GET and HEAD requests pass, so the API is read-only. Everything else gets 403 Forbidden.
| Direct socket | Socket proxy (our choice) | |
|---|---|---|
| What Homepage can do | Everything the socket allows | Only what you switch on: list containers |
| Homepage must run as | root, or a member of the docker group | any user (PUID/PGID work) |
| Extra container | none | one small proxy |
| Documented by Homepage | yes, "not recommended" | yes, "more restricted and secure" |
Add the proxy to compose.yaml next to Homepage (pinned tag v0.5.0; the docs example uses latest). It publishes no port: only containers on the same Compose network can reach it, which is what the proxy's authors ask for.
services:
homepage:
image: ghcr.io/gethomepage/homepage:v2.7.0
container_name: homepage
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env
volumes:
- ./config:/app/config
dockerproxy:
image: ghcr.io/tecnativa/docker-socket-proxy:v0.5.0
container_name: dockerproxy
restart: unless-stopped
environment:
- CONTAINERS=1 # allow viewing containers
- SERVICES=1 # needed for Docker Swarm only
- TASKS=1 # needed for Docker Swarm only
- POST=0 # no POST requests: effectively read-only
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
Then tell Homepage where the proxy is, in config/docker.yaml:
my-docker: host: dockerproxy port: 2375
And attach a container to a service tile in services.yaml with two lines (container is the container's name):
- Beszel:
server: my-docker
container: beszel
Linux#
cd ~/docker_volumes/homepage nano compose.yaml nano config/docker.yaml nano config/services.yaml docker compose up -d
Windows (PowerShell)#
Set-Location "$HOME\docker_volumes\homepage" notepad compose.yaml notepad config\docker.yaml notepad config\services.yaml docker compose up -d
The Homepage docs only show Linux socket paths. With Docker Desktop on Windows, the Linux containers run in WSL 2 and the same Compose lines are the normal way, but we did not test it.
Mac (Terminal)#
Same commands as Linux. If the socket mount fails, Docker's docs say the /var/run/docker.sock symlink is an optional setting in Docker Desktop (Settings, Advanced); enable it and recreate the containers.
cd ~/docker_volumes/homepage nano compose.yaml nano config/docker.yaml nano config/services.yaml docker compose up -d
Check it worked. The Beszel tile shows a status dot; click it for CPU and memory stats of that container. docker compose ps lists homepage and dockerproxy. Homepage only reads container status; it cannot start or stop anything, which is the point of POST=0.
Tip: The
:roflag marks the mount; what limits the Docker API is the proxy's switches (POST=0allows only GET and HEAD, per its README). Never publish the proxy's port 2375 to a network you do not control.
Put it behind HTTPS (with or without Traefik)#
This is for a server you reach by a domain name. Using Homepage only at home on localhost? You can skip this section. The docs say a public Homepage "must rely on a reverse proxy (and/or VPN) that enforces authentication, TLS, and unexpected Host headers".
Two things change when a proxy is in front: add the new host name to HOMEPAGE_ALLOWED_HOSTS in .env (for example home.example.com, without a port, because the browser uses 443), and bind Homepage's own port to the machine only ("127.0.0.1:3000:3000"). Both Traefik and Caddy pass the browser's Host header on by default, so the host Homepage sees is the one in the address bar. Check the log line if unsure.
With Traefik#
Prerequisites: a domain, DNS pointing to the server, ports 80 and 443 open, and Traefik running on the external proxy network. Create the network once if it is missing:
docker network create proxy
Change the Homepage service like this. The labels are our example (the same pattern as in our Uptime Kuma and Beszel guides), not from the Homepage docs: check them against your Traefik setup.
homepage:
image: ghcr.io/gethomepage/homepage:v2.7.0
container_name: homepage
restart: unless-stopped
env_file:
- .env
volumes:
- ./config:/app/config
networks:
- proxy
- default
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.homepage.rule=Host(`home.example.com`)
- traefik.http.routers.homepage.entrypoints=https
- traefik.http.routers.homepage.tls=true
- traefik.http.services.homepage.loadbalancer.server.port=3000
networks:
proxy:
external: true
Keep the dockerproxy service from Step 4 as it is, on the default network only: it must not join proxy.
Without Traefik: Caddy#
Choose Caddy if you have no Traefik yet and run one small server.
| Case | Result | You do |
|---|---|---|
| Public domain | Automatic Let's Encrypt certificate | DNS A record to the server, ports 80 and 443 open |
| Home only | tls internal (Caddy's local certificate) | Trust Caddy's root certificate on each device |
Caddyfile for a public domain:
home.example.com {
reverse_proxy localhost:3000
}
Caddyfile for home only (point the name at the Caddy machine):
dashboard.home.arpa {
tls internal
reverse_proxy localhost:3000
}
Trust the root certificate (pki/authorities/local/root.crt in Caddy's data directory):
# Linux: on the Caddy machine sudo caddy trust # other Linux devices, with root.crt copied over sudo cp root.crt /usr/local/share/ca-certificates/caddy-root.crt && sudo update-ca-certificates # Mac sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root.crt
# Windows (PowerShell as administrator) certutil -addstore -f ROOT root.crt
Run Caddy. Linux: install it from the official apt repository on caddyserver.com/docs/install, then sudo systemctl reload caddy. Windows: winget install CaddyServer.Caddy, then caddy run. Mac: brew install caddy, then caddy run. Or use the official image caddy:2.11.7 (current in October 2026) on the same Docker network: drop Homepage's ports: line, use reverse_proxy homepage:3000, and keep ./caddy_data:/data under ~/docker_volumes/caddy.
Set HOMEPAGE_ALLOWED_HOSTS=home.example.com in .env, then docker compose up -d --force-recreate.
Check it worked. curl -I https://home.example.com answers HTTP/2 200.
Security and testing#
Homepage can show private data, so the dashboard needs a guard. The official warning: if it is reachable from an untrusted network, put it behind a reverse proxy or VPN that enforces authentication and TLS.
- Do not forward port 3000 to the internet. Reach it from home, over a VPN such as WireGuard or Tailscale, or through the HTTPS proxy above.
- Do not set
HOMEPAGE_ALLOWED_HOSTSto*. It switches the host check off. The docs call that "not recommended"; and the check is only "a best-effort guard for local setups". - Turn on the built-in login if other people can reach the dashboard. Since v2.0, add to
.env:HOMEPAGE_AUTH_ENABLED=true,HOMEPAGE_AUTH_SECRET(at least 32 characters; make one withopenssl rand -base64 32),HOMEPAGE_EXTERNAL_URL(the full address, withhttps://when you use TLS) andHOMEPAGE_AUTH_PASSWORD. Homepage has no rate limiting for password attempts, so the docs ask you to rate limitPOST /api/auth/callback/credentialsat your proxy. OIDC is supported too, viaHOMEPAGE_OIDC_*variables. - Secrets:
.envischmod 600(Linux/Mac) or locked withicacls(Windows); API keys only asHOMEPAGE_VAR_*orHOMEPAGE_FILE_*. - What leaves your machine: icons from
mdi-,si-andsh-sets are loaded by your browser from CDN servers, and Homepage checks GitHub for new versions unless you setdisableUpdateCheck: trueinsettings.yaml. - Status test:
docker compose psshowshealthy;curl -I http://localhost:3000returns an HTTP answer;docker logs homepage --tail 50shows noerror:lines.
Common mistakes#
| Mistake | Why it happens | Do this instead |
|---|---|---|
Spaces after the commas in HOMEPAGE_ALLOWED_HOSTS | The value looks like a normal list. A user wrote astra.infv:4100, start.astra.home, start.astra.home:443 and still got the error (discussion 5290) | Comma-separated, no spaces, each entry exactly as in the log line |
Restarting the container after changing .env | Docker only reads environment variables when it creates the container; the maintainer answered this twice (5290, 6094) | docker compose up -d --force-recreate |
Adding localhost, a scheme (https://) or a different port than the browser uses | People copy what they think should be allowed; a TrueNAS user tried many variants (5412) | Use the host as the browser shows it, with the port only when it is not 80/443 |
Running as a normal user (PUID/PGID) with the raw Docker socket | The docs say direct socket access needs root or the docker group; a Synology user got connect EACCES /var/run/docker.sock (7140) | Use the socket proxy from Step 4, which works for any user |
Putting the whole status-page URL in the Uptime Kuma widget url | The browser address looks like the thing to paste; the widget got HTML and showed API Error: Invalid data (7279) | url = base address only; the part after /status/ goes in slug |
Using a public reverse-proxy domain or localhost as a widget url | The container could not resolve the domain (ENOTFOUND, 6255) | Use an address the container can reach; test with docker exec homepage ping <address> |
| Squeezing the container to 128 MB | It looked small enough; one Swarm user saw the container exit and blamed the Docker host, then found the memory limit (7282) | Give it 512 MB while you measure with docker stats; that user then saw about 125 MB used |
| Trusting an AI assistant's Homepage setup | Assistants copy older tutorials: the retired ghcr.io/benphelps/homepage image, no HOMEPAGE_ALLOWED_HOSTS at all (needed since v1.0), a value with http://, or ":ro makes the socket read-only" | Take the image from the current docs (ghcr.io/gethomepage/homepage), the host list from the log, and limit the API with the proxy's POST=0 |
Keys typed straight into services.yaml | The examples in the docs show plain keys | Use {{HOMEPAGE_VAR_NAME}} with the value in .env, and quote the placeholder |
Tip: When a widget fails, click its "API Error Information" button first. It tells you whether the problem is reaching the host, a wrong key or a wrong path, before you change anything.
Troubleshooting#
| Problem | Solution |
|---|---|
Host validation failed. See logs for more details. in the browser | Run docker logs homepage --tail 20, put the refused host in HOMEPAGE_ALLOWED_HOSTS, recreate the container |
connect EACCES /var/run/docker.sock | The container user cannot read the socket. Use the socket proxy (Step 4) or run as root |
Widget shows API Error: Invalid data | The url returns a web page, not the API. Use the base address; for Uptime Kuma add slug |
Widget shows ENOTFOUND or ECONNREFUSED | The container cannot reach that address. Test docker exec homepage ping <address>; put both containers on one network |
| Service name missing or tiles overlap | Every service and every group needs a unique name |
| Icon missing | Check the icon name in the Dashboard Icons list, or use si-<name>. A local icon needs a mount at /app/public/icons and a restart |
Change in services.yaml not visible | Click the refresh icon at the bottom right of the page |
| Container keeps exiting | docker logs homepage, check the memory limit, and remove a docker.yaml host that is switched off |
Host validation failed#
error: Host validation failed for: <host>. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port.
This is the log line from several user reports. It means the Host header of the request is not on the list. Add exactly that host.
Known bugs#
Homepage keeps bug reports and questions in GitHub Discussions; the issues list showed one open item (a translations update) when we read it in October 2026. For a stuck widget, start from the troubleshooting page and attach its output when you ask. Diagnostic commands:
docker logs homepage --tail 100 docker compose ps docker exec homepage ping <address>
To add curl inside the container for a test, the docs suggest apk add curl. Set the environment variable LOG_LEVEL=debug for more detail.
Updates and backups#
Update. Homepage releases often (six releases between early September and late October 2026). Change the tag in compose.yaml, read the release notes, then:
cd ~/docker_volumes/homepage docker compose pull && docker compose up -d
On Windows use Set-Location "$HOME\docker_volumes\homepage" first; the Compose commands are the same.
Back up the folder that matters: config (your YAML) and .env (your secrets, so protect the archive).
cd ~/docker_volumes/homepage mkdir -p backups tar -czf "backups/homepage-$(date +%F).tar.gz" config .env compose.yaml chmod 600 backups/*.tar.gz
Set-Location "$HOME\docker_volumes\homepage" New-Item -ItemType Directory -Force backups | Out-Null Compress-Archive -Path config,.env,compose.yaml -DestinationPath "backups\homepage-$(Get-Date -Format yyyy-MM-dd).zip" -Force
Schedule: on Linux and Mac add this cron line (crontab -e) for 03:00 every day: 0 3 * * * cd ~/docker_volumes/homepage && tar -czf "backups/homepage-$(date +\%F).tar.gz" config .env compose.yaml. On Windows, create a Task Scheduler task that runs the two PowerShell lines at 03:00.
Restore test. Unpack the archive into a new empty folder, check that config/services.yaml is there, copy it over a fresh install and start with docker compose up -d. Your dashboard should come back as it was.
Performance and resources#
- Memory: no official minimum. One user's v2.7.0 container exited with a 128 MB limit and then sat at about 125 MB with a 512 MB limit; give yourself room and watch
docker stats homepage. - Speed: the README promises "cached dashboard data and optimized assets"; a refresh clears the cache when you change config.
- Many widgets: each widget makes a server-side API call; remove ones you do not read.
- Logs: they go to
config/logs, rotate at 10 MiB and keep five files; setLOG_TARGETS=stdoutto log only to Docker.
docker stats homepage --no-stream
FAQ#
Do I need Docker? No. Homepage can also be installed from source or on Kubernetes, but Docker is the simplest and best documented way.
Why does it say "Host validation failed"? Since v1.0 Homepage only answers for localhost and the hosts you list in HOMEPAGE_ALLOWED_HOSTS. Read the log, add the host, recreate the container.
Is it safe to mount the Docker socket? It gives whatever can use it broad control of your machine. Use the socket proxy with POST=0 as in Step 4, and keep the proxy off every public network.
Can I show services without widgets? Yes. A tile only needs a name and an href. Widgets, container status and ping checks are all optional.
Does it find my containers automatically? Yes, with labels such as homepage.group, homepage.name and homepage.href on the other containers. That needs the Docker integration from Step 4.
What does it cost? Nothing. It is GPL-3.0 open source.
Sources#
- Homepage on GitHub: README, releases, licence (v2.7.0, read October 2026)
- Homepage docs: installation and HOMEPAGE_ALLOWED_HOSTS, authentication (read October 2026)
- Homepage docs: Docker installation and secrets (read October 2026)
- Homepage docs: Docker integration and socket proxy (read October 2026)
- Homepage docs: services, icons, widgets (read October 2026)
- Homepage docs: Uptime Kuma widget and Beszel widget (read October 2026)
- Homepage docs: troubleshooting (read October 2026)
- Tecnativa docker-socket-proxy (v0.5.0, read October 2026)
- Caddy docs: reverse_proxy, automatic HTTPS, tls internal (Caddy 2.11.7, read October 2026)
- Traefik docs: load balancer service, passHostHeader (read October 2026)
- Docker Desktop docs: Mac permission requirements (read October 2026)
- GitHub discussions 5290, 5412, 6094, 6255, 7140, 7279, 7282 (read October 2026)
Checked against the official docs on 2026-10-30.