====== Caddy Caddyfile Reload: Docker Bind Mount Inode Bug ====== When deploying Caddyfile changes to a running Caddy container, the standard rsync command will silently fail to update the container's view of the file. Caddy reload will report "config is unchanged" even though the file on disk is different. ===== Root Cause ===== rsync replaces files atomically by writing to a temp file and renaming it over the destination. The rename operation creates a new inode. Docker's single-file bind mount holds a reference to the original inode at mount time. After rsync replaces the file, the container's /etc/caddy/Caddyfile still points to the old inode, so Caddy never sees the new content. This only affects single-file bind mounts (e.g. a specific file like Caddyfile). Directory bind mounts follow the path and do not have this problem. ===== Symptom ===== After running rsync to update the Caddyfile on the host and then running: docker exec folkzone-caddy caddy reload --config /etc/caddy/Caddyfile Caddy logs show: "msg":"config is unchanged" even though the host file has new content. Verifying with: docker exec folkzone-caddy grep 'new-domain.folk.zone' /etc/caddy/Caddyfile returns nothing, confirming the container sees the stale inode. ===== Fix ===== Use docker compose restart instead of caddy reload when deploying Caddyfile changes. Restarting the container remounts the bind mount from the current file path, picking up whichever inode is now at that path: docker compose restart caddy Do not use --force-recreate unless necessary, as that is slower and causes a longer downtime window. A plain restart is sufficient to refresh the bind mount. ===== Workaround (avoids restart) ===== Write to the file in-place on the host using shell redirection rather than rsync. This preserves the inode while updating the content: cat /path/to/new/Caddyfile > /home/brennan/homelab/caddy/Caddyfile Or use rsync with the --inplace flag, which writes directly to the existing file without creating a temp file: rsync --inplace -avz -e "ssh -i ~/.omg-lol-keys/id_ed25519" \ server/caddy/Caddyfile \ brennan@192.168.1.65:/home/brennan/homelab/caddy/Caddyfile After either of these, caddy reload will work correctly without a restart. ===== Correct Deployment Procedure ===== rsync --inplace -avz -e "ssh -i ~/.omg-lol-keys/id_ed25519" \ server/caddy/Caddyfile \ brennan@192.168.1.65:/home/brennan/homelab/caddy/Caddyfile docker exec folkzone-caddy caddy reload --config /etc/caddy/Caddyfile Or if you forget --inplace and already ran a plain rsync: docker compose -f /home/brennan/homelab/docker-compose.yml restart caddy