mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-10 09:08:09 -04:00
* chore(server): bake collectstatic into image, drop runtime scratch mount
Static files (admin assets + the bun-built dist/) are immutable from
image build time onward — `bin/start_server.sh` was running
`collectstatic --clear --noinput` on every container start into a host
bind-mount on /home/${USER}/anthias/staticfiles, which existed only as
a writable scratch path for collectstatic to write to. Same data, every
restart, into a directory the container itself populated.
Move the work to where it belongs:
- docker/Dockerfile.server.j2: run `collectstatic --noinput --clear`
in the production stage, after the bun-built dist/ is COPYed in.
Wrapped in `HOME=/tmp/anthias-build` because the Django settings
module instantiates AnthiasSettings() at import time, which writes a
default anthias.conf into $HOME/.anthias if one isn't there yet
(start_server.sh seeds /data/.anthias before this same import at
runtime; at build time the throwaway HOME is removed after the
RUN finishes).
- src/anthias_server/django_project/settings.py: STATIC_ROOT moves
from /data/anthias/staticfiles to /usr/src/app/staticfiles. Inside
the container this path is now read-only — admin + collected app
static is immutable per-image. Dev (DEBUG=True) bypasses STATIC_ROOT
entirely via WHITENOISE_USE_FINDERS so the path doesn't have to
exist in the dev image.
- bin/start_server.sh: drop the runtime collectstatic invocation and
the "Generating Django static files..." progress line.
- docker-compose.yml.tmpl: drop the
/home/${USER}/anthias/staticfiles -> /data/anthias/staticfiles
bind-mount. The host-side directory becomes orphan state after
upgrade — operators can `rm -rf ~/anthias/staticfiles` once the
new image is pulled. (One of the two reasons ~/anthias has to
persist after install. The other — runtime shell scripts in
~/anthias/bin/ — is tracked separately in #2845.)
Verified by building the production server image locally
(`docker buildx build --file docker/Dockerfile.server`):
- 210 static files copied to /usr/src/app/staticfiles at image build.
- Container starts, uvicorn comes up, no "Generating Django static
files..." line.
- `curl http://localhost:8080/static/admin/css/base.css` -> HTTP 200,
22120 bytes (matches the baked file).
- /data/anthias/ does not exist in the running container -- no
runtime scratch dir is needed.
Refs #2845.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: address Copilot review nits
Two pure-comment fixes flagged by Copilot review on #2846:
- src/anthias_server/django_project/settings.py: "admin assets +
collected app static is immutable" -> "admin assets and collected
app static are immutable" (compound subject takes plural verb).
- docker/Dockerfile.server.j2: "COPYed" -> "copied" in the
collectstatic comment block.
No behavior change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
2.9 KiB
Bash
Executable File
77 lines
2.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
ENVIRONMENT=${ENVIRONMENT:-production}
|
|
|
|
# Defensively expose legacy /data/.screenly and /data/screenly_assets
|
|
# paths as symlinks if a running setup still has them in DB rows or in
|
|
# an older docker-compose file. No-op on clean installs.
|
|
/usr/src/app/bin/migrate_in_container_paths.sh
|
|
|
|
mkdir -p \
|
|
/data/.config \
|
|
/data/.anthias \
|
|
/data/.anthias/backups \
|
|
/data/anthias_assets
|
|
|
|
cp -n /usr/src/app/ansible/roles/anthias/files/anthias.conf /data/.anthias/anthias.conf
|
|
cp -n /usr/src/app/ansible/roles/anthias/files/default_assets.yml /data/.anthias/default_assets.yml
|
|
|
|
echo "Running migration..."
|
|
|
|
# The following block ensures that the migration is transactional and that the
|
|
# database is not left in an inconsistent state if the migration fails.
|
|
|
|
if [ -f /data/.anthias/anthias.db ]; then
|
|
python -m anthias_server.manage dbbackup --noinput --clean && \
|
|
python -m anthias_server.manage migrate --fake-initial --noinput || \
|
|
python -m anthias_server.manage dbrestore --noinput
|
|
else
|
|
python -m anthias_server.manage migrate && \
|
|
python -m anthias_server.manage dbbackup --noinput --clean
|
|
fi
|
|
|
|
UVICORN_BIND_HOST="${LISTEN:-0.0.0.0}"
|
|
UVICORN_BIND_PORT="${PORT:-8080}"
|
|
|
|
# Trust X-Forwarded-* only from explicitly listed proxies. We deliberately
|
|
# do NOT default this to '*' — the IP allowlists in views_files.py rely on
|
|
# the TCP peer address, and a wildcard would let any client spoof
|
|
# REMOTE_ADDR via X-Forwarded-For. Operators who terminate TLS at a
|
|
# reverse proxy (e.g. the Caddy sidecar bin/enable_ssl.sh installs) get
|
|
# this set automatically via the compose override.
|
|
UVICORN_PROXY_ARGS=()
|
|
if [[ -n "${FORWARDED_ALLOW_IPS:-}" ]]; then
|
|
UVICORN_PROXY_ARGS=(
|
|
--proxy-headers
|
|
--forwarded-allow-ips "$FORWARDED_ALLOW_IPS"
|
|
)
|
|
fi
|
|
|
|
if [[ "$ENVIRONMENT" == "development" ]]; then
|
|
echo "Building frontend assets..."
|
|
bun install && bun run build
|
|
echo "Starting uvicorn (development, --reload)..."
|
|
# uvicorn's --reload watches *.py only by default. Add Django
|
|
# templates and built CSS so a template / SCSS edit on the host
|
|
# propagates to the running worker without a manual restart.
|
|
exec uvicorn anthias_server.django_project.asgi:application \
|
|
--host "$UVICORN_BIND_HOST" \
|
|
--port "$UVICORN_BIND_PORT" \
|
|
--timeout-keep-alive 30 \
|
|
--reload \
|
|
--reload-dir /usr/src/app \
|
|
--reload-include "*.html" \
|
|
--reload-include "*.css" \
|
|
"${UVICORN_PROXY_ARGS[@]}"
|
|
else
|
|
# collectstatic ran at image build time (docker/Dockerfile.server.j2)
|
|
# — STATIC_ROOT is baked into the read-only image layer. No runtime
|
|
# invocation needed.
|
|
echo "Starting uvicorn..."
|
|
exec uvicorn anthias_server.django_project.asgi:application \
|
|
--host "$UVICORN_BIND_HOST" \
|
|
--port "$UVICORN_BIND_PORT" \
|
|
--timeout-keep-alive 30 \
|
|
"${UVICORN_PROXY_ARGS[@]}"
|
|
fi
|