redo containers so they are fully rootless

no more annoying useradd/userdel!
allows read only containers!
smaller images!
doesn't crash on restart without recreating anymore! (oops)
configurable children / spare servers!
This commit is contained in:
Robin 2022-01-07 22:32:49 +01:00
parent 578dbd56b9
commit 52ff7f8f33
6 changed files with 55 additions and 100 deletions

View File

@ -11,8 +11,9 @@ services:
target: /data target: /data
# environment: # Change this if you rename the php container # environment: # Change this if you rename the php container
# PHP_FPM: php:9000 # PHP_FPM: php:9000
# user: 'youruser'
depends_on: [php] depends_on: [php]
restart: always # restart: always
php: php:
image: namelessmc/php:v2-pr12 image: namelessmc/php:v2-pr12
@ -20,7 +21,8 @@ services:
- type: bind # same as web container - type: bind # same as web container
source: ./web source: ./web
target: /data target: /data
restart: always # user: 'youruser'
# restart: always
db: db:
image: mariadb image: mariadb
@ -33,4 +35,4 @@ services:
MYSQL_USER: nameless MYSQL_USER: nameless
MYSQL_PASSWORD: nameless MYSQL_PASSWORD: nameless
MYSQL_DATABASE: nameless MYSQL_DATABASE: nameless
restart: always # restart: always

View File

@ -2,14 +2,13 @@ FROM nginx:alpine
ENV PHP_FPM="php:9000" ENV PHP_FPM="php:9000"
ENV WWW_DATA_UID=33 WWW_DATA_GID=33
RUN apk add --no-cache shadow
RUN find /etc/nginx -type f -not -name 'mime.types' -not -name 'fastcgi_params' -delete && \ RUN find /etc/nginx -type f -not -name 'mime.types' -not -name 'fastcgi_params' -delete && \
rm -rf conf.d modules rm -rf conf.d modules
COPY nginx.conf /etc/nginx COPY nginx.conf /etc/nginx
COPY entrypoint.sh / COPY entrypoint.sh /
# The www-data user has uid 33 on Debian/Ubuntu which is what most people are used to
USER 33
ENTRYPOINT [ "sh", "/entrypoint.sh" ] ENTRYPOINT [ "sh", "/entrypoint.sh" ]

View File

@ -1,46 +1,13 @@
#!/bin/sh #!/bin/sh
if [ -n "$(getent passwd "$WWW_DATA_UID")" ] if [ -z "$(find /data -user "$(id -u)" -print -prune -o -prune)" ]; then
then echo "/data is not owned by the correct user, we are uid $(id -u)"
USERNAME=$(getent passwd "$WWW_DATA_UID" | cut -d: -f1) exit 1
echo "Deleting user $USERNAME which already uses UID $WWW_DATA_UID"
userdel "$USERNAME"
else
echo "UID $WWW_DATA_UID not in use"
fi fi
if [ -n "$(getent group "$WWW_DATA_GID")" ] cat > /tmp/fastcgi-pass.conf << EOL
then set \$upstream "${PHP_FPM}";
GROUPNAME=$(getent passwd "$WWW_DATA_GID" | cut -d: -f1) fastcgi_pass \$upstream;
echo "Deleting group $GROUPNAME which already uses GID $WWW_DATA_GID"
groupdel "$GROUPNAME"
else
echo "GID $WWW_DATA_GID not in use"
fi
if [ -n "$(getent group www-data)" ]
then
echo "Modifying existing www-data group, setting GID to $WWW_DATA_GID"
groupmod -g "$WWW_DATA_GID" www-data
else
echo "Adding www-data group with GID $WWW_DATA_GID"
groupadd -g "$WWW_DATA_GID" www-data
fi
if [ -n "$(getent passwd www-data)" ]
then
echo "Modifying existing www-data user, setting GID to $WWW_DATA_GID"
usermod -g "$WWW_DATA_GID" www-data
else
echo "Adding www-data user with UID $WWW_DATA_UID and GID $WWW_DATA_GID"
getent passwd 1000
useradd -u "$WWW_DATA_UID" -g "$WWW_DATA_GID" www-data
fi
cat > /etc/nginx/php.conf << EOL
upstream php-handler {
server ${PHP_FPM};
}
EOL EOL
exec nginx -g "daemon off;" exec nginx -g "daemon off;"

View File

@ -1,4 +1,5 @@
user "www-data"; # We're running rootless so we don't have permission to write to /var/run/nginx.pid
pid /tmp/nginx.pid;
events { events {
worker_connections 1024; worker_connections 1024;
@ -8,10 +9,17 @@ http {
access_log /dev/stdout; access_log /dev/stdout;
error_log /dev/stdout; error_log /dev/stdout;
# Default directory is /var/cache/nginx/ but we're running rootless so that won't work
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
include mime.types; include mime.types;
default_type application/octet-stream; default_type application/octet-stream;
include php.conf; resolver 127.0.0.11 valid=10s;
server { server {
listen 80 default_server; listen 80 default_server;
@ -25,7 +33,7 @@ http {
# Remove X-Powered-By, which is an information leak # Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By; fastcgi_hide_header X-Powered-By;
root /data; root /data/;
location / { location / {
try_files $uri $uri/ /index.php?route=$uri&$args; try_files $uri $uri/ /index.php?route=$uri&$args;
@ -42,14 +50,14 @@ http {
} }
location ~ \.php$ { location ~ \.php$ {
try_files $uri = 404; try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-handler;
fastcgi_index index.php; fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /tmp/fastcgi-pass.conf;
include fastcgi_params; include fastcgi_params;
} }
client_max_body_size 0; client_max_body_size 512M; # This matches our default max body size for php-fpm
} }
} }

View File

@ -5,23 +5,19 @@ ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/do
RUN chmod +x /usr/local/bin/install-php-extensions && \ RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions @composer gd pdo_mysql mysqli zip exif install-php-extensions @composer gd pdo_mysql mysqli zip exif
ENV WWW_DATA_UID=33 WWW_DATA_GID=33 # php-fpm loads configuration in alphabetical order so prefix with zz-
RUN apk add --no-cache shadow
RUN { \ RUN { \
echo "upload_max_filesize = 512M"; \ echo "upload_max_filesize = 512M"; \
echo "post_max_size = 512M"; \ echo "post_max_size = 512M"; \
echo "max_input_time = 300"; \ echo "max_input_time = 300"; \
echo "max_execution_time = 300"; \ echo "max_execution_time = 300"; \
} > /usr/local/etc/php/conf.d/nameless.ini && \ } > /usr/local/etc/php/conf.d/zz-nameless.ini
{ \ # We want to add some additional configuration at runtime, but the entrypoint script doesn't run as root and only has
echo "[www]"; \ # permission to write to /tmp. So, we create a symlink that doesn't exist yet but will before php-fpm is started.
echo "pm.max_children = 32"; \ # This shouldn't allow arbritrary config modifications even though /tmp is publicly writable: a container restart is
echo "pm.start_servers = 1"; \ # required to load new configuration and restarting the container overwrites this config file.
echo "pm.min_spare_servers = 1"; \ # A bit weird, I know, but it's the best I could come up with. Suggestions welcome!
echo "pm.max_spare_servers = 4" ; \ RUN ln -s /tmp/additional-php-fpm-settings.conf /usr/local/etc/php-fpm.d/zz-nameless.conf
} > /usr/local/etc/php-fpm.d/zz-nameless.conf
ADD entrypoint.sh / ADD entrypoint.sh /
@ -37,4 +33,11 @@ ENV NAMELESS_PATH_HIDE=true
# Enable friendly URLs and hide the option by default, they work fine with the included configuration and there is no reason to turn it off. # Enable friendly URLs and hide the option by default, they work fine with the included configuration and there is no reason to turn it off.
ENV NAMELESS_FRIENDLY_URLS=true NAMELESS_FRIENDLY_URLS_HIDE=true ENV NAMELESS_FRIENDLY_URLS=true NAMELESS_FRIENDLY_URLS_HIDE=true
ENV PHP_MAX_CHILDREN=32 \
PHP_MIN_SPARE_SERVERS=2 \
PHP_MAX_SPARE_SERVERS=4
# The www-data user has uid 33 on Debian/Ubuntu which is what most people are used to
USER 33
ENTRYPOINT [ "sh", "/entrypoint.sh" ] ENTRYPOINT [ "sh", "/entrypoint.sh" ]

View File

@ -1,41 +1,9 @@
#!/bin/sh #!/bin/sh
set -e set -e
if [ -n "$(getent passwd "$WWW_DATA_UID")" ] if [ -z "$(find /data -user "$(id -u)" -print -prune -o -prune)" ]; then
then echo "/data is not owned by the correct user, we are uid $(id -u)"
USERNAME=$(getent passwd "$WWW_DATA_UID" | cut -d: -f1) exit 1
echo "Deleting user $USERNAME which already uses UID $WWW_DATA_UID"
userdel "$USERNAME"
else
echo "UID $WWW_DATA_UID not in use"
fi
if [ -n "$(getent group "$WWW_DATA_GID")" ]
then
GROUPNAME=$(getent passwd "$WWW_DATA_GID" | cut -d: -f1)
echo "Deleting group $GROUPNAME which already uses GID $WWW_DATA_GID"
groupdel "$GROUPNAME"
else
echo "GID $WWW_DATA_GID not in use"
fi
if [ -n "$(getent group www-data)" ]
then
echo "Modifying existing www-data group, setting GID to $WWW_DATA_GID"
groupmod -g "$WWW_DATA_GID" www-data
else
echo "Adding www-data group with GID $WWW_DATA_GID"
groupadd -g "$WWW_DATA_GID" www-data
fi
if [ -n "$(getent passwd www-data)" ]
then
echo "Modifying existing www-data user, setting GID to $WWW_DATA_GID"
usermod -g "$WWW_DATA_GID" www-data
else
echo "Adding www-data user with UID $WWW_DATA_UID and GID $WWW_DATA_GID"
getent passwd 1000
useradd -u "$WWW_DATA_UID" -g "$WWW_DATA_GID" www-data
fi fi
if [ -n "$(ls -A /data 2>/dev/null)" ] if [ -n "$(ls -A /data 2>/dev/null)" ]
@ -67,7 +35,7 @@ else
phpstan.neon phpstan.neon
composer install composer install
# fix permissions # fix permissions
chown -R www-data:www-data . # chown -R www-data:www-data .
find . -type d -exec chmod 750 {} \; find . -type d -exec chmod 750 {} \;
find . -type f -exec chmod 640 {} \; find . -type f -exec chmod 640 {} \;
set +x set +x
@ -87,4 +55,12 @@ then
fi fi
fi fi
{ \
echo "[www]"
echo "pm.max_children = $PHP_MAX_CHILDREN"
echo "pm.start_servers = $PHP_MIN_SPARE_SERVERS"
echo "pm.min_spare_servers = $PHP_MIN_SPARE_SERVERS"
echo "pm.max_spare_servers = $PHP_MAX_SPARE_SERVERS"
} > /tmp/additional-php-fpm-settings.conf # this file is symlinked to the correct php-fpm configuration dir
exec php-fpm exec php-fpm