From 2661edeb8c441cc4de6b07d49ff87c8ee475b260 Mon Sep 17 00:00:00 2001 From: renaud gaudin Date: Fri, 8 Dec 2023 07:52:22 +0000 Subject: [PATCH] Fixed #24: chown data folders to www-data - on start, unless `NO_CHOWN_DATA` is set, must-be-writable folders are chown'd to www-data/www-data - Base python image updated to bookworm --- edupi/Dockerfile | 3 ++- edupi/README.md | 9 ++++++++- edupi/entrypoint.py | 34 ++++++++++++++++++++++++++++++++-- edupi/nginx.conf | 2 +- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/edupi/Dockerfile b/edupi/Dockerfile index 4f5f520..fdc709d 100644 --- a/edupi/Dockerfile +++ b/edupi/Dockerfile @@ -24,7 +24,7 @@ RUN npm -g install bower && \ python3 ./manage.py bower install && \ python3 ./manage.py collectstatic --noinput -FROM python:3.8.14-slim-bullseye +FROM python:3.8-slim-bookworm LABEL org.opencontainers.image.source https://github.com/offspot/container-images EXPOSE 80 @@ -33,6 +33,7 @@ VOLUME /data ENV ADMIN_USERNAME "" ENV ADMIN_PASSWORD "" ENV SRC_DIR "#" +ENV NO_CHOWN_DATA "" RUN apt-get update -y && \ apt-get install -y --no-install-recommends libmagic1 ghostscript libmagickwand-dev nginx curl && \ diff --git a/edupi/README.md b/edupi/README.md index 7fb9f02..f0d5f10 100644 --- a/edupi/README.md +++ b/edupi/README.md @@ -26,6 +26,7 @@ No configuration is required but you'll likely want to set some of the following | `ADMIN_USERNAME` | Username of the *admin* user. Requires setting the password. | | `ADMIN_PASSWORD` | Password of the *admin* user. | | `SRC_DIR` | In-container path of the folder to import files from. | +| `NO_CHOWN_DATA` | Don't chown www-data:www-data folders in `/data` on start | Note that registered users access the special UI at [`/custom`](http://localhost/custom). A link is only present on homepage is there is no imported data. @@ -38,10 +39,16 @@ If you want to persist EduPi's data, you'll need to bind some paths to a persist | Path | Usage | | --- | --- | | `/data` | All user-modifiable data | -| `/data/database` | Only EduPi's database (SQLite) | +| `/data/database` | Only EduPi's database (SQLite) | | `/data/media` | EduPi's files are stored here. Their thumbnails inside a `thumbnails` sub-folder | | `/data/log` | nginx's access logs | | `/data/stats` | EduPi's statistics based off (on-demand) reading of nginx log | | `/var/lib/edupi/favicon.ico` | Default EduPi favicon | **Important**: when importing existing content (via `SRC_DIR` environ), make sure to mount that source directory in the same bound volume as `/data/media` so that files are moved effisciently. + +### Permissions + +Web-servers (uwsgi and nginx) runs as user `www-data`/`www-data`. `/data/*` thus needs to be writable by these processes. +To ensure this, the container will chown those folders on start. +If you don't want this chown to happen (and ensure perms are correct yourself), set the `NO_CHOWN_DATA` environment variable. diff --git a/edupi/entrypoint.py b/edupi/entrypoint.py index 951d176..7eb3001 100755 --- a/edupi/entrypoint.py +++ b/edupi/entrypoint.py @@ -1,28 +1,58 @@ #!/usr/local/bin/python3 +import grp import os import pathlib +import pwd import shutil import subprocess import sys +SKIP_CHOWN = bool(os.getenv("NO_CHOWN_DATA")) def ensure_folders(): root = pathlib.Path("/data") stat = root.stat() - for folder in ("database", "media", "stats", "log"): + folders = ("database", "media", "stats", "log") + + for folder in folders: path = root.joinpath(folder) try: path.mkdir(parents=True) except FileExistsError: - continue + pass else: try: os.chown(path, stat.st_uid, stat.st_gid) except Exception as exc: print(f"Unable to change owner of created {path}: {exc}") + if not SKIP_CHOWN: + username = "www-data" + groupname = "www-data" + try: + user = pwd.getpwnam(username)[2] + except KeyError: + print(f"Unable to get uid of user {username}") + return + + try: + group = grp.getgrnam(groupname)[2] + except KeyError: + print(f"Unable to get gid of group {groupname}") + return + + for folder in folders: + path = root.joinpath(folder) + try: + os.chown(path, user, group) + except Exception as exc: + print(f"Unable to change ownership of {path}: {exc}") + continue + + + def start_nginx(): if os.getenv("NO_NGINX"): diff --git a/edupi/nginx.conf b/edupi/nginx.conf index 14db82a..4847813 100644 --- a/edupi/nginx.conf +++ b/edupi/nginx.conf @@ -1,4 +1,4 @@ -user www-data; +user www-data www-data; worker_processes auto; pid /run/nginx.pid;