docs/docs/en/get-started/installation/docker-caddy.mdx
In this setup, the NocoBase app container and the Caddy container run separately. You can start with Docker Installation (Built-in Nginx) and then switch the entry service to an external Caddy container.
If you need the full image, replace latest-no-nginx with latest-full-no-nginx.
The 13000:80 mapping is only for convenient local testing, so it does not occupy the standard host ports directly. In production, you usually do not keep using 13000:80; instead, let the external Caddy container map directly to the host 80 and 443 ports.
networks:
nocobase:
driver: bridge
services:
app:
image: nocobase/nocobase:latest-no-nginx
restart: always
depends_on:
- postgres
networks:
- nocobase
environment:
- APP_KEY=your-secret-key
- DB_DIALECT=postgres
- DB_HOST=postgres
- DB_PORT=5432
- DB_DATABASE=nocobase
- DB_USER=nocobase
- DB_PASSWORD=nocobase
- TZ=Etc/UTC
- NOCOBASE_EXTRACT_CLIENT_ASSETS=true
- NOCOBASE_PROXY_PROVIDER=caddy
- NOCOBASE_PROXY_STORAGE_PATH=/app/nocobase/storage
- NOCOBASE_PROXY_UPSTREAM_HOST=app
volumes:
- ./storage:/app/nocobase/storage
caddy:
image: caddy:2
restart: always
depends_on:
- app
networks:
- nocobase
volumes:
- ./storage:/app/nocobase/storage
command: >
/bin/sh -c '
while [ ! -f /app/nocobase/storage/.nocobase/proxy/caddy/nocobase.caddy ]; do
echo "waiting for nocobase.caddy..."
sleep 1
done
ln -sf /app/nocobase/storage/.nocobase/proxy/caddy/nocobase.caddy /etc/caddy/Caddyfile
caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
'
ports:
# This is only a local testing example.
- "13000:80"
# In production, usually change it to:
# - "80:80"
# - "443:443"
postgres:
image: postgres:16
restart: always
command: postgres -c wal_level=logical
environment:
POSTGRES_USER: nocobase
POSTGRES_DB: nocobase
POSTGRES_PASSWORD: nocobase
volumes:
- ./storage/db/postgres:/var/lib/postgresql/data
networks:
- nocobase
NOCOBASE_EXTRACT_CLIENT_ASSETS=true extracts client assets and generates proxy configNOCOBASE_PROXY_PROVIDER=caddy tells the app to generate Caddy configNOCOBASE_PROXY_UPSTREAM_HOST=app lets the Caddy container reach the app service through the Compose network./storage must be mounted into both the app and caddy containers so they can share proxy config, static assets, and uploaded filescaddy container should wait until nocobase.caddy is generated, then link it to /etc/caddy/Caddyfile with ln -sf13000:80; in production, you usually expose the host 80 and 443 ports directly, while the app service does not need to expose its port to the hostIf your Caddy is installed directly on the host instead of running in a Docker container, it is better to use a separate docker-compose.yml. In this setup, the app service must expose a host port directly, and the proxy-related environment variables should use host-side values.
You can use a docker-compose.yml like this:
networks:
nocobase:
driver: bridge
services:
app:
image: nocobase/nocobase:latest-no-nginx
restart: always
depends_on:
- postgres
networks:
- nocobase
environment:
- APP_KEY=your-secret-key
- DB_DIALECT=postgres
- DB_HOST=postgres
- DB_PORT=5432
- DB_DATABASE=nocobase
- DB_USER=nocobase
- DB_PASSWORD=nocobase
- TZ=Etc/UTC
- NOCOBASE_EXTRACT_CLIENT_ASSETS=true
- NOCOBASE_PROXY_PROVIDER=caddy
- NOCOBASE_PROXY_STORAGE_PATH=/path/to/your-project/storage
- NOCOBASE_PROXY_UPSTREAM_HOST=127.0.0.1
- NOCOBASE_PROXY_UPSTREAM_PORT=13000
volumes:
- ./storage:/app/nocobase/storage
ports:
- "13000:13000"
postgres:
image: postgres:16
restart: always
command: postgres -c wal_level=logical
environment:
POSTGRES_USER: nocobase
POSTGRES_DB: nocobase
POSTGRES_PASSWORD: nocobase
volumes:
- ./storage/db/postgres:/var/lib/postgresql/data
networks:
- nocobase
In this variant:
NOCOBASE_PROXY_STORAGE_PATH should be the absolute host path of your storage directoryNOCOBASE_PROXY_UPSTREAM_HOST should be 127.0.0.1app service must keep ports, so the local Caddy can reach the app through 127.0.0.1:13000After the app container starts, wait for the config file to be generated, then link it into the local Caddy config path:
while [ ! -f ./storage/.nocobase/proxy/caddy/nocobase.caddy ]; do
echo "waiting for nocobase.caddy..."
sleep 1
done
sudo ln -sf "$(pwd)/storage/.nocobase/proxy/caddy/nocobase.caddy" /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy
If your host Caddy does not use /etc/caddy/Caddyfile, replace the link target with your own config path. Usually it is safer to keep nocobase.caddy as the main entry file instead of copying its content manually.