Localify can automatically discover Docker Compose services and
register them as .localify domains. When enabled, starting a
compose stack instantly makes services available at
https://<service>.<project>.localify.
Add the [docker] section to config.toml
(~/Library/Application Support/Localify Desktop/ on macOS, ~/.config/localify/ on Linux):
[docker]
enabled = trueThen restart the daemon:
localify restartLocalify connects to the Docker socket and watches for container lifecycle events. When a container starts or stops, Localify automatically updates its routing table.
When a container starts, Localify evaluates it using these rules (in order):
localify.enable=falselabel -- skip (explicit opt-out)localify.enable=truelabel -- register (explicit opt-in)- Compose labels + exposed port -- register automatically
- Otherwise -- skip
For compose services, the domain is derived from the project
and service names: <service>.<project>.localify. For example,
a service named web in project myapp becomes
web.myapp.localify.
- The container must have at least one published port
(
ports:mapping indocker-compose.yml) - Localify proxies to the host port, not the container port
- If a container exposes multiple ports, set
localify.portto pick one (see Labels Reference)
Given this docker-compose.yml:
services:
web:
build: .
ports:
- "3000:3000"# Enable Docker integration in Localify config
# (add [docker] enabled = true, then restart)
# Start your compose stack
docker compose up -d
# Localify auto-discovers and registers web.myproject.localify
# (project name comes from directory name by default)
open https://web.myproject.localifyNo localify register needed -- it happens automatically.
Control Localify behavior with container labels, either in
docker-compose.yml or via docker run --label.
| Label | Values | Description |
|---|---|---|
localify.enable |
true / false |
Force opt-in or opt-out |
localify.domain |
e.g. app.localify |
Override the auto-generated domain |
localify.port |
e.g. 8080 |
Pick which container port to proxy |
localify.wildcard |
true |
Register as wildcard (*.domain) |
Custom domain:
services:
web:
build: .
ports:
- "3000:3000"
labels:
localify.domain: "myapp.localify"Explicit opt-in (non-compose container):
services:
standalone:
image: nginx
ports:
- "8080:80"
labels:
localify.enable: "true"
localify.domain: "nginx.localify"Multiple ports -- pick one:
services:
api:
build: .
ports:
- "3000:3000"
- "9090:9090"
labels:
localify.port: "3000"Wildcard subdomains:
services:
web:
build: .
ports:
- "3000:3000"
labels:
localify.wildcard: "true"This registers *.web.myproject.localify, so
anything.web.myproject.localify routes to the container.
Opt out a service:
services:
db:
image: postgres
ports:
- "5432:5432"
labels:
localify.enable: "false"Localify determines the domain in this order:
localify.domainlabel -- used as-is (must end with.localify)- Compose labels --
<service>.<project>.localify
The compose project name defaults to the directory name. You
can set it explicitly with COMPOSE_PROJECT_NAME or the
name: key in docker-compose.yml:
name: myapp
services:
web:
build: .
ports:
- "3000:3000"
# Domain: web.myapp.localifyWhen one container needs to reach another container's
.localify domain (or any .localify domain served by the host),
Docker's default DNS won't resolve .localify names. Use
extra_hosts to point the domain at the host:
services:
web:
build: .
ports:
- "3000:3000"
worker:
build: .
extra_hosts:
- "web.myproject.localify:host-gateway"host-gateway resolves to the host machine's IP (typically
host.docker.internal on Docker Desktop). The worker
container can now reach http://web.myproject.localify through
Localify on the host.
Add one entry per .localify domain the container needs to
access.
Note: Wildcard
extra_hosts(e.g.,*.localify) are not supported --/etc/hostsdoes not allow wildcards. You must list each domain explicitly.
On Linux, containers on a bridge network reach the host through its bridge address,
which a daemon on loopback does not answer. Localify listens on loopback by default, so
if a container cannot reach it, run localify lan enable, which lets Localify listen on
every interface. Containers using the host network reach it directly.
On macOS, Docker Desktop runs containers inside a Linux
VM. Containers cannot reach the host via its LAN IP, but can
reach it via host-gateway / host.docker.internal. The
extra_hosts approach above is required for container-to-Localify
communication. Localify listens on loopback by default there. If a
container cannot reach it, run localify lan enable.
Check which Docker containers Localify has discovered:
localify listDocker-discovered domains show their source as "external" in
the output. They appear alongside manually registered domains
but cannot be edited with localify register or localify route --
they are managed entirely by the Docker watcher.
View discovery logs:
# See container add/remove events
LOCALIFY_LOG=debug localify start --foreground
# Or check the log file
localify logs -fExample log output:
INFO Docker integration enabled
INFO Docker domain added domain=web.myapp.localify target=127.0.0.1:3000
INFO Docker reconciliation complete added=1 removed=0 total=1
Check that:
- Docker integration is enabled (
[docker] enabled = true) - The container has published ports (
ports:in compose) - The container is not opted out (
localify.enable=false) - The daemon is running (
localify status)
Run with debug logging to see why a container was skipped:
LOCALIFY_LOG=debug localify start --foregroundLook for Docker container skipped messages with a reason.
Localify needs a host port mapping to proxy traffic. Make sure
your service has a ports: entry:
services:
web:
build: .
# This is required:
ports:
- "3000:3000"
# EXPOSE alone is not enoughIf a container exposes more than one port and no localify.port
label is set, Localify skips it (ambiguous). Add the label:
labels:
localify.port: "3000"Localify connects to the Docker socket
(/var/run/docker.sock by default). The daemon runs as you, so you need access to that socket.
Docker Desktop gives it to you. On Linux that means being in the docker group, which is
equivalent to root on that machine, so it is your call. If you see connection errors, verify the socket exists and is accessible.