A webstack container built on Alpine, running Nginx, PHP, and S6-overlay.
Docker Webstack
About
This container is a fairly simple Nginx / PHP-FPM container that can be used as a base for your own web containers. It makes use of s6-overlay as it's init daemon / process supervisor, and comes in various PHP versions (see below). It is rebuilt and tested every day on Travis-CI, so you will always have the latest security patches of Nginx and PHP on hand.
Why?
I can hear you thinking "aren't there already plenty good Nginx / PHP containers out there?". To me, there weren't, as I found that all existing containers either run some kind of bash script to start both Nginx and PHP, or use supervisord to start one or more processes in the background. The former felt really hacky to me, and the latter is not meant to be used as an init daemon as it does not handle the different signals for process 1 properly and makes your container possibly end up with zombie processes.
So I started looking for proper init daemons that can take care of this situation and I found s6-overlay which explains in great detail how they overcame the aforementioned problems.
The goals of this container
- Be always up to date with the latest packages from Alpine Linux
- Minimize the lines of code needed in your own Dockerfile and optimize readibility.
- Have sane defaults for Nginx, PHP, and FPM that can be easily overwritten if needed.
How can I use it?
You can create your own containers based upon this container with a simple FROM in your Dockerfile.
Before you start
Before start hacking away, you should know this:
- By default, Nginx runs under the system's nginx user, and PHP-FPM runs under the system's php user. For rootless, see below.
- The code should be copied into
/www, as this is the default directory Nginx and PHP work with in this container. - When not using a CMS or framework like Laravel / Symfony / WordPress that brings its own public folder, copy to
/www/publicinstead. - Any PHP modules needed in your project should be installed by using apk, Alpine Linux's package manager and the package names for installing can be looked up in the version table below.
- S6-overlay can set permissions when the container starts up, but this can be slow if a lot of permissions need to be set, so just do this when building the container.
Rootless mode
Starting from PHP 8.3, this container supports rootless mode for enhanced security.
What is rootless mode?
In rootless mode, both Nginx and PHP-FPM run as the same non-root user (typically nobody). This eliminates the need for root privileges inside the container, reducing the attack surface. The container is configured to:
- Run on port 8080 instead of port 80 (non-privileged port)
- Remove user directives from Nginx and PHP-FPM configurations
- Set appropriate permissions for directories that need write access
Running rootless containers
When running rootless containers, you must specify a non-root user for the user id. Permissions to various folders have been set to the nobody user (id 65534) so it's easiest to go with that. If you want to use a different user id, make sure to set the correct owner on certain folders when building the container. For specifics, see the rootless target in any Dockerfile.
Also the port is no longer on port 80 because that's a privileged port. Instead, the port has been set to 8080.
Basic example
Now that we know all that, we can do something like this:
FROM existenz/webstack:8.3
COPY --chown=php:nginx src/ /www
RUN find /www -type d -exec chmod -R 555 {} \; \ && find /www -type f -exec chmod -R 444 {} \; \ && find /www/var -type d -exec chmod -R 755 {} \; \ && find /www/var -type f -exec chmod -R 644 {} \; \ && apk -U --no-cache add \ php83-ctype \ php83-json \ php83-mbstring
And you should now have a working container that runs your PHP project!
Or, when picking a rootless container:
FROM existenz/webstack:8.5-rootless
COPY --chown=nobody:nobody src/ /www
Versions
Tags ending with a -edge install packages from the edge repository to keep up with the latest PHP versions. These
are probably short-lived and will be replaced with their default counterpart as soon as these PHP versions make it
into the default Alpine repositories. You can use them, just keep in mind you will have to switch over to the default
container at one point.>
Codecasts containers are no longer provided, see this issue for
more information.
See the table below to see what versions are currently available:
| Image tag | Based on | PHP Packages from | S6-Overlay | |--------------|-------------------|-------------------------------------------------------------------------------------------------|------------| | 8.2 | Alpine Linux 3.22 | Alpine Linux repo | Version 1 | | 8.3 | Alpine Linux 3.22 | Alpine Linux repo | Version 3 | | 8.3-rootless | Alpine Linux 3.22 | Alpine Linux repo | Version 3 | | 8.4 | Alpine Linux 3.22 | Alpine Linux repo | Version 3 | | 8.4-rootless | Alpine Linux 3.22 | Alpine Linux repo | Version 3 | | 8.5 | Alpine Linux 3.23 | Alpine Linux repo | Version 3 | | 8.5-rootless | Alpine Linux 3.23 | Alpine Linux repo | Version 3 | | 8.5-edge | Alpine Linux Edge | Alpine Linux repo | Version 3 |
Overriding or extending the configuration
If you want to augment of replace the configuration of Nginx, PHP or FPM, there are multiple options:
- Place one or more configuration files in specific directories to augment the configuration
- If that does not suit your needs, you can also simply overwrite the configuration files altogether
| Application | Copy files into this directory | Overwrite this file if needed | |---------------------------|--------------------------------|-------------------------------| | PHP core directives (8.2) | /etc/php82/conf.d/ | /etc/php82/php.ini | | PHP-FPM (8.2) | /etc/php82/php-fpm.d/ | /etc/php82/php-fpm.conf | | PHP core directives (8.3) | /etc/php83/conf.d/ | /etc/php83/php.ini | | PHP-FPM (8.3) | /etc/php83/php-fpm.d/ | /etc/php83/php-fpm.conf | | PHP core directives (8.4) | /etc/php84/conf.d/ | /etc/php84/php.ini | | PHP-FPM (8.4) | /etc/php84/php-fpm.d/ | /etc/php84/php-fpm.conf | | PHP core directives (8.5) | /etc/php85/conf.d/ | /etc/php85/php.ini | | PHP-FPM (8.5) | /etc/php85/php-fpm.d/ | /etc/php85/php-fpm.conf | | Nginx | /etc/nginx/conf.d/ | /etc/nginx/nginx.conf |
Bugs, questions, and improvements
If you found a bug or have a question, please open an issue on the GitHub Issue tracker. Improvements can be sent by a Pull Request against the master branch and are greatly appreciated!
Contributors
Thanks everyone for helping out with this project!