I went with a more immutable approach.
At the core, I have a Dockerfile, composer.json and composer.lock in a git repo.
Whenever I commit changes it automatically builds a new image and deploys it.
It looks a little bit like this
RUN composer create-project flarum/flarum . --stability=beta
COPY composer.json composer.lock ./
RUN composer install
This also has the advantage of securely using extiverse plugins with multi-stage builds.
RUN if [ -n "$EXTIVERSE_TOKEN" ]; then composer config --global --auth bearer.extiverse.com "$EXTIVERSE_TOKEN"; fi
This approach has been very helpful to me for preventing issues showing up in production as I get to test reproducible images both locally and in a staging instance before pushing to production.
Definitely cool technology!