From 7c02774924d87c9a5bafbb1efb87e2cd5ce22774 Mon Sep 17 00:00:00 2001
From: Romain de Laage <romain.delaage@adaures.com>
Date: Fri, 5 May 2023 15:46:40 +0200
Subject: [PATCH] build(docker): add ability to configure timeouts, max body
 size and max memory limit

---
 docker/production/app/Dockerfile              |  4 +-
 docker/production/app/entrypoint.sh           |  1 +
 docker/production/app/uploads.ini             |  6 ---
 docker/production/app/uploads.template.ini    |  6 +++
 .../production/{unit => castopod}/Dockerfile  | 10 ++--
 .../config.template.json}                     | 14 +++---
 .../production/{unit => castopod}/crontab.txt |  0
 .../{unit => castopod}/entrypoint.sh          |  1 +
 .../{unit => castopod}/supervisord.conf       |  0
 .../production/common/prepare_environment.sh  | 25 +++++++++-
 docker/production/web-server/Dockerfile       |  4 +-
 docker/production/web-server/entrypoint.sh    | 15 +++++-
 .../{nginx.conf => nginx.template.conf}       |  6 +--
 docs/src/getting-started/docker.md            | 46 ++++++-------------
 14 files changed, 78 insertions(+), 60 deletions(-)
 delete mode 100644 docker/production/app/uploads.ini
 create mode 100644 docker/production/app/uploads.template.ini
 rename docker/production/{unit => castopod}/Dockerfile (81%)
 rename docker/production/{unit/config.json => castopod/config.template.json} (63%)
 rename docker/production/{unit => castopod}/crontab.txt (100%)
 rename docker/production/{unit => castopod}/entrypoint.sh (67%)
 rename docker/production/{unit => castopod}/supervisord.conf (100%)
 rename docker/production/web-server/{nginx.conf => nginx.template.conf} (94%)

diff --git a/docker/production/app/Dockerfile b/docker/production/app/Dockerfile
index 771a87a8b6..92231fb4d3 100644
--- a/docker/production/app/Dockerfile
+++ b/docker/production/app/Dockerfile
@@ -2,13 +2,13 @@ FROM docker.io/php:8.1-fpm-alpine3.17
 
 COPY docker/production/common/prepare_environment.sh /prepare_environment.sh
 COPY docker/production/app/entrypoint.sh /entrypoint.sh
-COPY docker/production/app/uploads.ini /usr/local/etc/php/conf.d/uploads.ini
+COPY docker/production/app/uploads.template.ini /uploads.template.ini
 
 RUN echo "* * * * * /usr/local/bin/php /opt/castopod/public/index.php scheduled-activities" > /crontab.txt && \
     echo "* * * * * /usr/local/bin/php /opt/castopod/public/index.php scheduled-websub-publish" >> /crontab.txt
 
 # TODO: remove freetype (package and gd support) and ffmpeg
-RUN apk add --no-cache libpng icu-libs freetype libwebp libjpeg-turbo libxpm ffmpeg && \
+RUN apk add --no-cache libpng icu-libs freetype libwebp libjpeg-turbo libxpm ffmpeg coreutils gettext && \
     apk add --no-cache --virtual .php-ext-build-dep freetype-dev libpng-dev libjpeg-turbo-dev libwebp-dev zlib-dev libxpm-dev icu-dev && \
     docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp --with-xpm && \
     docker-php-ext-install gd intl mysqli exif && \
diff --git a/docker/production/app/entrypoint.sh b/docker/production/app/entrypoint.sh
index e92dd10d8a..7e81d438ee 100644
--- a/docker/production/app/entrypoint.sh
+++ b/docker/production/app/entrypoint.sh
@@ -3,6 +3,7 @@
 ENV_FILE_LOCATION=/opt/castopod/.env
 
 . /prepare_environment.sh
+cat /uploads.template.ini | envsubst '$CP_MAX_BODY_SIZE$CP_MAX_BODY_SIZE_BYTES$CP_TIMEOUT$CP_PHP_MEMORY_LIMIT' > /usr/local/etc/php/conf.d/uploads.ini
 
 /usr/sbin/crond -f /crontab.txt -L /dev/stdout &
 /usr/local/sbin/php-fpm
diff --git a/docker/production/app/uploads.ini b/docker/production/app/uploads.ini
deleted file mode 100644
index 0262ec7c05..0000000000
--- a/docker/production/app/uploads.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-file_uploads = On
-memory_limit = 512M
-upload_max_filesize = 500M
-post_max_size = 512M
-max_execution_time = 300
-max_input_time = 300
diff --git a/docker/production/app/uploads.template.ini b/docker/production/app/uploads.template.ini
new file mode 100644
index 0000000000..52ac70fc1b
--- /dev/null
+++ b/docker/production/app/uploads.template.ini
@@ -0,0 +1,6 @@
+file_uploads = On
+memory_limit = $CP_PHP_MEMORY_LIMIT
+upload_max_filesize = $CP_MAX_BODY_SIZE
+post_max_size = $CP_MAX_BODY_SIZE
+max_execution_time = $CP_TIMEOUT
+max_input_time = $CP_TIMEOUT
diff --git a/docker/production/unit/Dockerfile b/docker/production/castopod/Dockerfile
similarity index 81%
rename from docker/production/unit/Dockerfile
rename to docker/production/castopod/Dockerfile
index 268ff2e6c0..fc5db99739 100644
--- a/docker/production/unit/Dockerfile
+++ b/docker/production/castopod/Dockerfile
@@ -34,14 +34,14 @@ COPY --from=UNIT_BUILDER /usr/lib/unit/ /usr/lib/unit/
 COPY --from=CRON_BUILDER /usr/local/bin/supercronic /usr/local/bin/supercronic
 
 COPY docker/production/common/prepare_environment.sh /prepare_environment.sh
-COPY docker/production/unit/entrypoint.sh /entrypoint.sh
+COPY docker/production/castopod/entrypoint.sh /entrypoint.sh
 COPY castopod /var/www/castopod
-COPY docker/production/unit/config.json /config.json
-COPY docker/production/unit/crontab.txt /crontab.txt
-COPY docker/production/unit/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
+COPY docker/production/castopod/config.template.json /config.template.json
+COPY docker/production/castopod/crontab.txt /crontab.txt
+COPY docker/production/castopod/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 RUN apt-get update && \
-    apt-get install -y supervisor ffmpeg curl libfreetype6-dev libjpeg62-turbo-dev libpng-dev libwebp-dev libxpm-dev libpcre2-8-0 libicu-dev && \
+    apt-get install -y supervisor ffmpeg curl gettext-base libfreetype6-dev libjpeg62-turbo-dev libpng-dev libwebp-dev libxpm-dev libpcre2-8-0 libicu-dev && \
     rm -rf /var/lib/apt/lists/* && \
     pecl install -o -f redis && \
     rm -rf /tmp/pear && \
diff --git a/docker/production/unit/config.json b/docker/production/castopod/config.template.json
similarity index 63%
rename from docker/production/unit/config.json
rename to docker/production/castopod/config.template.json
index d8d8d76fcd..1290fbbd76 100644
--- a/docker/production/unit/config.json
+++ b/docker/production/castopod/config.template.json
@@ -22,11 +22,11 @@
       "options": {
         "admin": {
           "file_uploads": "On",
-          "memory_limit": "512M",
-          "upload_max_filesize": "500M",
-          "post_max_size": "512M",
-          "max_execution_time": "300",
-          "max_input_time": "300"
+          "memory_limit": "$CP_PHP_MEMORY_LIMIT",
+          "upload_max_filesize": "$CP_MAX_BODY_SIZE",
+          "post_max_size": "$CP_MAX_BODY_SIZE",
+          "max_execution_time": "$CP_TIMEOUT",
+          "max_input_time": "$CP_TIMEOUT"
         }
       }
     }
@@ -36,8 +36,8 @@
   },
   "settings": {
     "http": {
-      "body_read_timeout": 300,
-      "max_body_size": 536870912
+      "body_read_timeout": $CP_TIMEOUT,
+      "max_body_size": $CP_MAX_BODY_SIZE_BYTES
     }
   }
 }
diff --git a/docker/production/unit/crontab.txt b/docker/production/castopod/crontab.txt
similarity index 100%
rename from docker/production/unit/crontab.txt
rename to docker/production/castopod/crontab.txt
diff --git a/docker/production/unit/entrypoint.sh b/docker/production/castopod/entrypoint.sh
similarity index 67%
rename from docker/production/unit/entrypoint.sh
rename to docker/production/castopod/entrypoint.sh
index 544bda067c..1cd559ba01 100644
--- a/docker/production/unit/entrypoint.sh
+++ b/docker/production/castopod/entrypoint.sh
@@ -3,6 +3,7 @@
 ENV_FILE_LOCATION=/var/www/castopod/.env
 
 . /prepare_environment.sh
+cat /config.template.json | envsubst '$CP_MAX_BODY_SIZE$CP_MAX_BODY_SIZE_BYTES$CP_TIMEOUT$CP_PHP_MEMORY_LIMIT' > /config.json
 
 #Apply configuration after unit is started
 (sleep 2 && curl -X PUT --data-binary @/config.json --unix-socket /var/run/control.unit.sock http://localhost/config/) &
diff --git a/docker/production/unit/supervisord.conf b/docker/production/castopod/supervisord.conf
similarity index 100%
rename from docker/production/unit/supervisord.conf
rename to docker/production/castopod/supervisord.conf
diff --git a/docker/production/common/prepare_environment.sh b/docker/production/common/prepare_environment.sh
index d038a4a4ee..6d149a2c53 100644
--- a/docker/production/common/prepare_environment.sh
+++ b/docker/production/common/prepare_environment.sh
@@ -16,7 +16,8 @@ fi
 
 if [ -z "${CP_MEDIA_BASEURL}" ]
 then
-	echo "CP_MEDIA_BASEURL is empty, leaving empty by default"
+	echo "CP_MEDIA_BASEURL is empty, using CP_BASEURL by default"
+	CP_MEDIA_BASEURL=$CP_BASEURL
 fi
 
 if [ -z "${CP_ADMIN_GATEWAY}" ]
@@ -133,6 +134,28 @@ then
 	fi
 fi
 
+if [ -z "${CP_PHP_MEMORY_LIMIT}" ]
+then
+	export CP_PHP_MEMORY_LIMIT="512M"
+fi
+
+if [ -z "${CP_MAX_BODY_SIZE}" ]
+then
+	export CP_MAX_BODY_SIZE="512M"
+fi
+
+CP_MAX_BODY_SIZE_BYTES=$(numfmt --from=iec "$CP_MAX_BODY_SIZE")
+if [ $? -ne 0 ]
+then
+	log_error "Failed to parse CP_MAX_BODY_SIZE ($CP_MAX_BODY_SIZE) as human readable number"
+fi
+export CP_MAX_BODY_SIZE_BYTES=$CP_MAX_BODY_SIZE_BYTES
+
+if [ -z "${CP_TIMEOUT}" ]
+then
+	export CP_TIMEOUT=900
+fi
+
 cat << EOF > $ENV_FILE_LOCATION
 app.baseURL="${CP_BASEURL}"
 media.baseURL="${CP_MEDIA_BASEURL}"
diff --git a/docker/production/web-server/Dockerfile b/docker/production/web-server/Dockerfile
index 3b2320a246..5d7354997c 100644
--- a/docker/production/web-server/Dockerfile
+++ b/docker/production/web-server/Dockerfile
@@ -9,11 +9,11 @@ WORKDIR /var/www/html
 COPY docker/production/web-server/entrypoint.sh /entrypoint.sh
 
 RUN chmod +x /entrypoint.sh && \
-    apk add --no-cache curl
+    apk add --no-cache curl gettext
 
 HEALTHCHECK --interval=30s --timeout=3s CMD curl --fail http://localhost || exit 1
 
-COPY docker/production/web-server/nginx.conf /etc/nginx/nginx.conf
+COPY docker/production/web-server/nginx.template.conf /nginx.template.conf
 
 COPY castopod/public /var/www/html
 
diff --git a/docker/production/web-server/entrypoint.sh b/docker/production/web-server/entrypoint.sh
index 4365e2cd89..5f6237819e 100644
--- a/docker/production/web-server/entrypoint.sh
+++ b/docker/production/web-server/entrypoint.sh
@@ -2,8 +2,19 @@
 if [ -z "${CP_APP_HOSTNAME}" ]
 then
 	echo "CP_APP_HOSTNAME is empty, using default"
-	CP_APP_HOSTNAME="app"
+	export CP_APP_HOSTNAME="app"
 fi
 
-sed -i "s/CP_APP_HOSTNAME/${CP_APP_HOSTNAME}/" /etc/nginx/nginx.conf
+if [ -z "${CP_MAX_BODY_SIZE}" ]
+then
+	export CP_MAX_BODY_SIZE=512M
+fi
+
+if [ -z "${CP_TIMEOUT}" ]
+then
+	export CP_TIMEOUT=900
+fi
+
+cat /nginx.template.conf | envsubst '$CP_APP_HOSTNAME$CP_MAX_BODY_SIZE$CP_TIMEOUT' > /etc/nginx/nginx.conf
+
 nginx -g "daemon off;"
diff --git a/docker/production/web-server/nginx.conf b/docker/production/web-server/nginx.template.conf
similarity index 94%
rename from docker/production/web-server/nginx.conf
rename to docker/production/web-server/nginx.template.conf
index 669c4f9b2c..58f9ecde67 100644
--- a/docker/production/web-server/nginx.conf
+++ b/docker/production/web-server/nginx.template.conf
@@ -27,7 +27,7 @@ http {
     real_ip_header    X-Real-IP;
 
     upstream php-handler {
-        server CP_APP_HOSTNAME:9000;
+        server $CP_APP_HOSTNAME:9000;
     }
 
     server {
@@ -40,8 +40,8 @@ http {
         add_header Permissions-Policy interest-cohort=();
         add_header X-Content-Type-Options nosniff;
         add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;";
-        client_max_body_size 512M;
-        client_body_timeout 300s;
+        client_max_body_size $CP_MAX_BODY_SIZE;
+        client_body_timeout ${CP_TIMEOUT}s;
 
         fastcgi_buffers 64 4K;
 
diff --git a/docs/src/getting-started/docker.md b/docs/src/getting-started/docker.md
index bae0d0d372..437ca7ad20 100644
--- a/docs/src/getting-started/docker.md
+++ b/docs/src/getting-started/docker.md
@@ -42,29 +42,20 @@ can be added as a cache handler.
         image: castopod/app:latest
         container_name: "castopod-app"
         volumes:
-          - castopod-media:/opt/castopod/public/media
+          - castopod-media:/var/www/castopod/public/media
         environment:
           MYSQL_DATABASE: castopod
           MYSQL_USER: castopod
           MYSQL_PASSWORD: changeme
-          CP_BASEURL: "http://castopod.example.com"
+          CP_BASEURL: "https://castopod.example.com"
           CP_ANALYTICS_SALT: changeme
           CP_CACHE_HANDLER: redis
           CP_REDIS_HOST: redis
         networks:
           - castopod-app
           - castopod-db
-        restart: unless-stopped
-
-      web-server:
-        image: castopod/web-server:latest
-        container_name: "castopod-web-server"
-        volumes:
-          - castopod-media:/var/www/html/media
-        networks:
-          - castopod-app
         ports:
-          - 8080:80
+          - 8000:8000
         restart: unless-stopped
 
       mariadb:
@@ -89,21 +80,6 @@ can be added as a cache handler.
         networks:
           - castopod-app
 
-      # this container is optional
-      # add this if you want to use the videoclips feature
-      video-clipper:
-        image: castopod/video-clipper:latest
-        container_name: "castopod-video-clipper"
-        volumes:
-          - castopod-media:/opt/castopod/public/media
-        environment:
-          MYSQL_DATABASE: castopod
-          MYSQL_USER: castopod
-          MYSQL_PASSWORD: changeme
-        networks:
-          - castopod-db
-        restart: unless-stopped
-
     volumes:
       castopod-media:
       castopod-db:
@@ -125,7 +101,7 @@ can be added as a cache handler.
     ```
     #castopod
     castopod.example.com {
-    	reverse_proxy localhost:8080
+    	reverse_proxy localhost:8000
     }
     ```
 
@@ -146,7 +122,7 @@ can be added as a cache handler.
   | **`CP_DATABASE_PASSWORD`** | ?string          | `MYSQL_PASSWORD` |
   | **`CP_DATABASE_PREFIX`**   | ?string          | `"cp_"`          |
 
-- **castopod/app**
+- **castopod/castopod** and **castopod/app**
 
   | Variable name                         | Type (`default`)        | Default          |
   | ------------------------------------- | ----------------------- | ---------------- |
@@ -181,9 +157,15 @@ can be added as a cache handler.
   | **`CP_MEDIA_S3_PROTOCOL`**            | ?number                 | `undefined`      |
   | **`CP_MEDIA_S3_PATH_STYLE_ENDPOINT`** | ?boolean                | `undefined`      |
   | **`CP_MEDIA_S3_KEY_PREFIX`**          | ?string                 | `undefined`      |
+  | **`CP_DISABLE_HTTPS`**                | ?[`0` or `1`]           | `undefined`      |
+  | **`CP_MAX_BODY_SIZE`**                | ?number (with suffix)   | `512M`           |
+  | **`CP_PHP_MEMORY_LIMIT`**             | ?number (with suffix)   | `512M`           |
+  | **`CP_TIMEOUT`**                      | ?number                 | `900`            |
 
 - **castopod/web-server**
 
-  | Variable name         | Type    | Default |
-  | --------------------- | ------- | ------- |
-  | **`CP_APP_HOSTNAME`** | ?string | `"app"` |
+  | Variable name          | Type                  | Default |
+  | ---------------------- | --------------------- | ------- |
+  | **`CP_APP_HOSTNAME`**  | ?string               | `"app"` |
+  | **`CP_MAX_BODY_SIZE`** | ?number (with suffix) | `512M`  |
+  | **`CP_TIMEOUT`**       | ?number               | `900`   |
-- 
GitLab