Multi-App On One Host
Two configs side by side, showing which keys must differ when two services share a host. Both apps are static Caddy sites, so nothing distracts from the naming.
For one static site on its own, use the static site recipe. For the full workflow — DNS, secrets, setup order, collision checks — see the Multi-App Hosting guide.
my-app/.meridian/deploy.yml
yaml
service: my-app
image: ghcr.io/example/my-app:latest
servers:
web:
hosts:
- prod-01.example.com
proxy:
host: app.example.com
ssl: true
app_port: 8000
healthcheck:
path: /health
ssh:
user: deploy
keys:
- ~/.ssh/id_ed25519
transfer:
mode: streammy-blog/.meridian/deploy.yml
yaml
service: my-blog
image: ghcr.io/example/my-blog:latest
servers:
web:
hosts:
- prod-01.example.com
proxy:
host: blog.example.com
ssl: true
app_port: 3000
healthcheck:
path: /up
ssh:
user: deploy
keys:
- ~/.ssh/id_ed25519
transfer:
mode: streamSee service, servers.<role>.proxy, and the multi-app guide.
Containerfile
Both projects use the same image, differing only in the exposed port — 8000 for my-app, 3000 for my-blog. Those must match app_port above.
dockerfile
FROM caddy:2.8-alpine
COPY public /srv
COPY Caddyfile /etc/caddy/Caddyfile
EXPOSE 8000Caddyfile
Same story: port and health route follow the service's deploy.yml. my-blog listens on :3000 and responds to /up.
text
:8000 {
root * /srv
respond /health 200
file_server
}Commands
Run these from each project directory in turn. The second meridian setup does not create a second proxy — it registers my-blog's network against the shared one.
bash
podman build -t ghcr.io/example/my-app:latest .
meridian setup
meridian plan
meridian check
meridian deploy