Building a Custom Alpine-Based LNP Stack Docker Image
To create a lightweight Docker image based on Alpine Linux that includes Nginx and PHP-FPM (an LNP stack), start by defining a base PHP layer.
For compatibility with legacy applications, use PHP 5.6 on Alpine 3.3:
# php5.dockerfile
FROM alpine:3.3
ENV TIMEZONE=Asia/Shanghai \
PHP_MEMORY_LIMIT=512M \
MAX_UPLOAD=50M \
PHP_MAX_FILE_UPLOAD=200 \
PHP_MAX_POST=100M
RUN echo "http://dl-4.alpinelinux.org/alpine/v3.3/main" > /etc/apk/repositories && \
apk update && \
apk add tzdata && \
cp /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && \
echo "${TIMEZONE}" > /etc/timezone && \
apk add \
php-intl php-mcrypt php-openssl php-gmp php-json php-dom \
php-pdo php-zip php-zlib php-mysqli php-bcmath php-gd \
php-xcache php-pdo_mysql php-gettext php-xmlreader php-xmlrpc \
php-bz2 php-memcache php-iconv php-curl php-ctype php-fpm \
php-phar php && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && \
sed -i 's/;daemonize\s*=\s*yes/daemonize = no/g' /etc/php/php-fpm.conf && \
sed -i 's/listen\s*=\s*127.0.0.1:9000/listen = 9000/g' /etc/php/php-fpm.conf && \
sed -i "s|;date.timezone =.*|date.timezone = ${TIMEZONE}|" /etc/php/php.ini && \
sed -i "s|memory_limit =.*|memory_limit = ${PHP_MEMORY_LIMIT}|" /etc/php/php.ini && \
sed -i "s|upload_max_filesize =.*|upload_max_filesize = ${MAX_UPLOAD}|" /etc/php/php.ini && \
sed -i "s|max_file_uploads =.*|max_file_uploads = ${PHP_MAX_FILE_UPLOAD}|" /etc/php/php.ini && \
sed -i "s|post_max_size =.*|post_max_size = ${PHP_MAX_POST}|" /etc/php/php.ini && \
sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php/php.ini && \
mkdir -p /www && \
apk del tzdata && \
rm -rf /var/cache/apk/*
Build this as the foundational image:
docker build -t alpine-lnp-base:v1 -f php5.dockerfile .
Next, extend this base to include Nginx and process supervision using Supervisor:
# nginx.dockerfile
FROM alpine-lnp-base:v1
ENV TIME_ZONE=Asia/Shanghai
RUN mkdir -p /opt/www /var/log/www && \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && \
apk add nginx supervisor
COPY nginx.conf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
COPY supervisord.conf /etc/supervisord.conf
CMD ["supervisord", "-c", "/etc/supervisord.conf"]
The main Nginx configuration (nginx.conf) enables performance tuning and logging:
worker_processes auto;
error_log /var/log/nginx/error.log;
events {
worker_connections 65535;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
keepalive_timeout 120;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain text/css application/json application/javascript text/xml application/rss+xml image/svg+xml;
gzip_vary on;
client_max_body_size 50m;
client_body_buffer_size 256k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
include conf.d/*.conf;
}
The site-specific configuration (default.conf) sets up PHP handling via FastCGI:
server {
listen 80;
server_name localhost;
root /opt/www;
index index.html index.php;
charset utf-8;
error_log /var/log/www/error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Supervisor manages both Nginx and PHP-FPM processes in the foreground:
[supervisord]
nodaemon=true
[program:php-fpm]
command=php-fpm
autostart=true
autorestart=true
stdout_events_enabled=true
stderr_events_enabled=true
[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true
startsecs=5
[program:crond]
command=crond -f
autostart=true
autorestart=true
Build the final image:
docker build -t alpine-lnp:v1 -f nginx.dockerfile .
Run the container with port 80 exposed:
docker run -d -p 80:80 --name lnp-container alpine-lnp:v1
Access the runing container for debugging if needed:
docker exec -it lnp-container sh