CaddyLander — JSON-backed wildcard landing page and Caddyfile editor.
2.5K
. . . .
,-. ,-. ,-| ,-| . . | ,-. ,-. ,-| ,-. ,-.
| ,-| | | | | | | | ,-| | | | | |-' |
`-' `-^ `-' `-' `-| `--' `-^ ' ' `-' `-' '
/|
`-'
caddyLander is a web-based Caddyfile editor and landing page generator that shares volumes with your Caddy container. You edit your Caddyfile in a browser, it validates before saving, and you get a simple service dashboard as a bonus.
caddyLander needs access to two directories that Caddy already uses:
| Volume Mount | What Lives There | Who Uses It |
|---|---|---|
/config | Your live Caddyfile | Caddy reads it; caddyLander edits it |
/var/caddy | content.json (landing page data) | caddyLander reads/writes it |
That's it. caddyLander is a sidecar that edits Caddy's config files through a shared volume.
1. A Caddyfile Editor (/admin)
2. A Landing Page (/)
content.json3. Password Protection
ADMIN_PASSWORD environment variable (default: caddyLander)You likely already have caddy_config and caddy_data from your Caddy install. You'll need to add one volume for landing page state:
docker volume create caddy_var
Then mount the shared volumes in both containers:
# Your existing Caddy container — add caddy_var
volumes:
- caddy_config:/config
- caddy_data:/data
- caddy_var:/var/caddy # ← add this
# caddyLander container — shares config and var
volumes:
- caddy_config:/config # caddyLander edits your Caddyfile here
- caddy_var:/var/caddy # landing page content.json lives here
caddyLander writes to /config/Caddyfile. Caddy reads from /config/Caddyfile. Same file.
Point your wildcard catch-all at caddyLander:
*.example.com {
reverse_proxy caddylander:8080
}
Load order matters—put specific routes first, wildcard last. Everything unmatched lands on your dashboard.
Optional: Direct admin access without the landing page:
caddylander.example.com {
reverse_proxy caddylander:8080
handle_path / {
redir /admin.html
}
}
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- caddy_config:/config
- caddy_data:/data
- caddy_var:/var/caddy # shared with caddyLander
networks:
- caddy_net
caddylander:
image: mythosaz/caddylander:main
restart: unless-stopped
environment:
- ADMIN_PASSWORD=YourSecurePassword
volumes:
- caddy_config:/config # edits your Caddyfile
- caddy_var:/var/caddy # landing page state
networks:
- caddy_net
# Optional debug port:
# ports:
# - "8386:8080"
volumes:
caddy_config:
external: true # assuming these already exist
caddy_data:
external: true
caddy_var: # create this one: docker volume create caddy_var
networks:
caddy_net:
When you save a Caddyfile edit:
/tmp/caddyfile.uploadcaddy fmt --overwritecaddy adapt/config/Caddyfile, backup createdBackups go to /config/backup/Caddyfile.old.YYYYMMDD-HHMMSS. Last 10 kept.
You still need to reload Caddy after saving. caddyLander edits the file; Caddy reads it on reload.
All fields optional except name and url on items:
{
"siteTitle": "My Services",
"siteSubtitle": "Homelab Dashboard",
"theme": "dark",
"favicon": "/static/favicon.ico",
"items": [
{
"name": "Service Name",
"url": "https://service.example.com",
"desc": "Optional description",
"icon": "🚀",
"group": "Infrastructure"
}
]
}
On first run, if /var/caddy/content.json doesn't exist, a template is copied from the container.
docker build -t caddylander .
docker run -p 8386:8080 -v caddylander_data:/var/caddy caddylander
Visit http://localhost:8386 for the landing page, http://localhost:8386/admin for the editor.
Admin Portal:
Landing Page:
MIT — see LICENSE.
Content type
Image
Digest
sha256:df81e873c…
Size
70.8 MB
Last updated
6 months ago
docker pull mythosaz/caddylander:next