Setting up an ultra-lightweight Nginx + PHP-FPM Alpine container server on openSUSE for CodeIgniter 4 apps
Prerequisites and Base System Setup
This guide assumes a fresh installation of openSUSE Leap or Tumbleweed. We’ll be leveraging Docker for containerization, which is the most efficient way to manage isolated, lightweight environments. Ensure Docker is installed and running on your host system.
On openSUSE, installation is straightforward:
- Install Docker:
sudo zypper install docker docker-compose - Start and enable the Docker service:
sudo systemctl enable docker --now - Add your user to the ‘docker’ group to avoid using
sudofor every Docker command (log out and back in for this to take effect):sudo usermod -aG docker $USER
Crafting the Nginx + PHP-FPM Alpine Dockerfile
We will create a custom Dockerfile to build a minimal Alpine Linux image containing Nginx and PHP-FPM, optimized for serving CodeIgniter 4 applications. This approach offers granular control and reduces the attack surface compared to pre-built images.
Create a directory for your project, e.g., ~/ci4-docker, and inside it, create a file named Dockerfile:
Dockerfile Contents
The following Dockerfile installs Nginx and PHP-FPM, configures them to work together, and sets up a basic Nginx configuration suitable for CodeIgniter 4. We’ll use specific versions for reproducibility.
# Use a minimal Alpine Linux base image
FROM alpine:3.18
# Install Nginx, PHP-FPM, and necessary PHP extensions
# We'll install PHP extensions that are commonly required by CodeIgniter 4
RUN apk add --no-cache \
nginx \
php82 php82-fpm php82-common php82-opcache php82-mbstring php82-xml php82-pdo php82-pdo_mysql php82-tokenizer php82-ctype php82-session php82-json \
supervisor \
tzdata
# Configure PHP-FPM
# Copy custom php-fpm configuration
COPY --chown=nginx:nginx php-fpm.d/www.conf /etc/php82/php-fpm.d/www.conf
# Configure Nginx
# Copy custom Nginx configuration
COPY --chown=nginx:nginx nginx.conf /etc/nginx/nginx.conf
COPY --chown=nginx:nginx conf.d/default.conf /etc/nginx/conf.d/default.conf
# Copy application code (placeholder for now)
# In a real-world scenario, you'd likely use a volume mount or a multi-stage build
COPY --chown=nginx:nginx app/ /var/www/html/
# Ensure correct permissions for Nginx and PHP-FPM
RUN chown -R nginx:nginx /var/www/html \
&& chown -R nginx:nginx /var/lib/nginx \
&& chown -R nginx:nginx /var/log/nginx \
&& chown -R nginx:nginx /var/run/nginx \
&& chown -R nginx:nginx /var/run/php82-fpm
# Expose ports
EXPOSE 80
# Start Nginx and PHP-FPM using Supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
PHP-FPM Configuration (php-fpm.d/www.conf)
Create a directory php-fpm.d in your project root and place the following www.conf file inside it. This configuration sets up PHP-FPM to run as the nginx user and group, which is standard practice in Alpine Linux environments.
[global] pid = /run/php82-fpm.pid error_log = /var/log/php82-fpm.log daemonize = no [www] user = nginx group = nginx listen = /run/php82-fpm.sock listen.owner = nginx listen.group = nginx listen.mode = 0660 pm = dynamic pm.max_children = 50 pm.min_spare_servers = 5 pm.max_spare_servers = 10 pm.start_servers = 2 pm.slowlog = /var/log/php82-fpm.slow.log request_terminate_timeout = 60s request_slowlog_timeout = 10s catch_workers_output = yes clear_env = no
Nginx Configuration (conf.d/default.conf)
Create a directory conf.d in your project root and place the following default.conf file inside it. This Nginx configuration is tailored for CodeIgniter 4, directing all requests to index.php via PHP-FPM.
server {
listen 80;
server_name localhost;
root /var/www/html/public; # CodeIgniter 4's public directory
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php82-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to hidden files
location ~ /\.ht {
deny all;
}
# Serve static files directly
location ~* \.(css|js|jpg|jpeg|gif|png|ico|svg|webp)$ {
expires 1y;
add_header Cache-Control "public";
}
}
Supervisor Configuration (supervisord.conf)
Create a file named supervisord.conf in your project root. Supervisor is used to manage the Nginx and PHP-FPM processes within the container, ensuring they are started and restarted if they crash.
[supervisord] nodaemon=true user=root [program:nginx] command=/usr/sbin/nginx -g "daemon off;" autostart=true autorestart=true priority=10 stdout_logfile=/var/log/supervisor/nginx_stdout.log stderr_logfile=/var/log/supervisor/nginx_stderr.log [program:php-fpm] command=/usr/sbin/php-fpm82 --nodaemonize --fpm-config /etc/php82/php-fpm.conf autostart=true autorestart=true priority=20 stdout_logfile=/var/log/supervisor/php-fpm_stdout.log stderr_logfile=/var/log/supervisor/php-fpm_stderr.log
Building and Running the Docker Image
Navigate to your project directory (~/ci4-docker) in your terminal. You can now build the Docker image. We’ll tag it as ci4-nginx-php-alpine.
docker build -t ci4-nginx-php-alpine .
Once the image is built, you can run it as a container. For development, mapping ports and volumes is crucial. We’ll map host port 8080 to container port 80 and mount your CodeIgniter 4 application code into the container.
Assuming your CodeIgniter 4 application’s public directory is at ~/my-ci4-app/public on your host, and you want to serve it from the container’s web root:
docker run -d \ --name ci4-app-server \ -p 8080:80 \ -v ~/my-ci4-app/public:/var/www/html/public \ -v ~/my-ci4-app:/var/www/html \ ci4-nginx-php-alpine
Explanation of the docker run command:
-d: Run the container in detached mode (in the background).--name ci4-app-server: Assign a name to the container for easier management.-p 8080:80: Map port 8080 on your host machine to port 80 inside the container.-v ~/my-ci4-app/public:/var/www/html/public: Mount your host’s CodeIgniterpublicdirectory to the container’s web root. This is essential for Nginx to find your application’s entry point.-v ~/my-ci4-app:/var/www/html: Mount the entire application directory. This is useful for development so changes are reflected immediately, and for Nginx to access other application files if needed (though thepublicmount is primary for serving).ci4-nginx-php-alpine: The name of the Docker image to run.
Accessing Your Application and Debugging
You should now be able to access your CodeIgniter 4 application by navigating to http://localhost:8080 in your web browser. If you encounter issues, here are some debugging steps:
Checking Container Logs
To view logs from the container, use:
docker logs ci4-app-server
For more detailed logs from Nginx and PHP-FPM, you can inspect the supervisor logs within the container:
docker exec ci4-app-server tail -f /var/log/supervisor/nginx_stderr.log docker exec ci4-app-server tail -f /var/log/supervisor/php-fpm_stderr.log
Inspecting Container Filesystem
If you need to examine the container’s filesystem, you can start an interactive shell:
docker exec -it ci4-app-server sh
Inside the shell, you can check Nginx configuration validity:
nginx -t
And check PHP-FPM status:
php-fpm82 -t
Common Configuration Pitfalls
- Permissions: Ensure the
nginxuser and group have read/write access to necessary directories (e.g.,writable,logs) within your CodeIgniter application. The volume mounts should handle this, but double-check if you’re not using standard paths. - Nginx Root Directive: The
rootdirective indefault.confmust point to your CodeIgniter application’spublicdirectory. - FastCGI Pass: Verify that
fastcgi_passindefault.confcorrectly points to the PHP-FPM socket (unix:/run/php82-fpm.sock). - PHP Extensions: If your CodeIgniter application requires additional PHP extensions, add them to the
apk addcommand in the Dockerfile and rebuild the image.
Production Considerations
For production deployments, several adjustments are recommended:
- Multi-stage Builds: Use multi-stage Docker builds to create a lean production image, copying only necessary artifacts from a build stage.
- Environment Variables: Manage database credentials, API keys, and other configurations via environment variables passed to the container, rather than hardcoding them.
- HTTPS: Configure Nginx for SSL/TLS termination, typically using a reverse proxy like Traefik or Caddy, or by mounting SSL certificates directly into the container.
- Logging: Centralize logs using a dedicated logging service (e.g., ELK stack, Graylog) instead of relying solely on container logs.
- Health Checks: Implement Docker health checks to monitor the status of Nginx and PHP-FPM.
- Database: Run your database in a separate container or use a managed database service.
This setup provides a robust, ultra-lightweight foundation for serving CodeIgniter 4 applications on openSUSE using Docker, offering excellent performance and manageability.
Leave a Reply
You must be logged in to post a comment.