I need to deploy a PHP application (including source) as a single docker image.
During development, I used docker-compose to setup two docker images: One is derived from nginx, one is from php-fpm.
I was hoping that I can just combine the original dockerfile definitions into one single dockerfile in order to get a single docker image for deployment. I would imagine something like this for the (minimal example) dockerfile:
# Install PHP-FPM
FROM --platform=linux/amd64 php:8.1-fpm
RUN docker-php-ext-install pdo_mysql # do some installations
# Install nginx
FROM --platform=linux/amd64 nginx
ADD src/public /usr/share/nginx/html/public # the directory public contains index.html and index.php
ADD conf/nginx.conf /etc/nginx/conf.d/default.conf # see below
The nginx config file looks something like this:
server {
server_name localhost;
root /usr/share/nginx/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
I was able to build and run this new dockerfile, but the PHP part seems to be ignored. The resulting image is able to serve html files and the PHP files are just downloaded. Obviously, the PHP setup is not working, but I cannot figure out what I am missing.
I read that I somehow need to "copy" the first build into the second build part. However, I am not sure what that would be.
How can I adjust the Dockerfile above to make PHP work as well?
Is it possible to run a Laravel app on two separated server, one with NGINX, another with PHP-FPM?
I wanted to create an upstream of PHP-FPM servers for load balancing. I've tried some NGINX configurations but it seems that both NGINX and PHP-FPM needs Laravel app files.
Note: I have separate server for static files.
[user] -request-> [nginx without laravel files] -> [php-fpm upstream with laravel files]
UPDATE
upstream php_pool {
server 192.168.1.1:9000;
}
server {
listen 80;
server_name www.example.com;
index index.php;
access_log /var/log/nginx/q_access.log;
error_log /var/log/nginx/q_error.log info;
location / {
try_files $uri $uri/index.php /index.php;
}
location ~ \.php$ {
index index.php;
fastcgi_pass php_pool;
fastcgi_index index.php;
include fastcgi_params;
}
}
I don't know what should i set for root directory cause there isn't any Laravel app files in that server. And how config \.php$ location properly?
We found solution for our scenario. PHP location should be like this:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php_pool;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/app/public$fastcgi_script_name;
}
With this change (SCRIPT_FILENAME) there isn't need for Laravel app files to be on the NGINX server cause all PHP requests will proxied to PHP-FPM servers.
I am trying to configure nginx to serve PHP from another server.
The files can be located within a directory under /sample on the other server
Fast CGI is running on port 9000 on the other server
Here is what I have tried, which is not working at the moment.
location ~ [^/]\.php(/|$) {
proxy_pass http://192.168.x.xx;
proxy_redirect http://192.168.x.xx /sample;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name)
{
return 404;
}
# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";
fastcgi_read_timeout 150;
fastcgi_buffers 4 256k;
fastcgi_buffer_size 128k;
fastcgi_busy_buffers_size 256k;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
I also need to configure nginx to serve static files from the same server
The following configuration does exactly what you need:
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root {STATIC-FILES-LOCATION};
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {PHP-FPM-SERVER}:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
All you have to do is replace {STATIC-FILES-LOCATION} with the location of your static files on the Nginx server and {PHP-FPM-SERVER} with the IP of the PHP-FPM server.
This way you will serve all files without the PHP extension statically from the Nginx server and all the PHP files will be interpreted with the PHP-FPM server.
Here's a working example of a dockerised version of what you are trying to achieve - https://github.com/mikechernev/dockerised-php/. It serves the static files from Nginx and interprets the PHP files via the PHP-FPM container. In the accompanying blog post (http://geekyplatypus.com/dockerise-your-php-application-with-nginx-and-php7-fpm/) I go in lengths about the whole connection between Nginx and PHP-FPM.
EDIT: One important thing to keep in mind is that the paths in both the Nginx and PHP-FPM servers should match. So you will have to put your php files in the same directory on the PHP-FPM server as your static files on the Nginx one ({STATIC-FILES-LOCATION}).
An example would be to have /var/www/ on Nginx holding your static files and /var/www on PHP-FPM to hold your php files.
Hope this helps :)
You don't have to use proxy_ directives, because they work with HTTP protocol, but in this case FastCGI protocol is used. Also, as it was said in comments, no need for if statement, because Nginx server cannot determine if the file on a remote server exists.
You could try this configuration:
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";
fastcgi_read_timeout 150;
fastcgi_buffers 4 256k;
fastcgi_buffer_size 128k;
fastcgi_busy_buffers_size 256k;
fastcgi_pass 192.168.x.xx:9000; #not 127.0.0.1, because we must send request to remote PHP-FPM server
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /path/to/site/root$fastcgi_script_name;
}
You will need to replace /path/to/site/root with a real path on the PHP-FPM server. For example, if the request http://example.com/some/file.php must be handled by /var/www/some/file.php, then set it like this:
fastcgi_param SCRIPT_FILENAME /var/www$fastcgi_script_name;
Also, to make PHP-FPM server be able to receive requests from outside, edit your FPM pool configuration (on Debian it usually located in /etc/php5/fpm/pool.d/www.conf, on Centos - /etc/php-fpm.d/www.conf):
Replace
listen = 127.0.0.1:9000
with:
listen = 9000
or:
listen = 192.168.x.xx:9000 # FPM server IP
Probably you will also need to edit allowed_clients directive:
listen.allowed_clients = 127.0.0.1,192.168.y.yy # Nginx server IP
I also need to configure nginx to serve static files from the same server
If I understand correctly, and you want to serve static files from the server, Nginx is working on, then you may just add another location to your Nginx configuration.
You should not use proxy_* directives. using Nginx as a proxy would be done only if a distant server has rendered the page (and you would request it with HTTP protocol).
Here the thing you want to proxy is a fastcgi server, not an HTTP server.
So the key is:
fastcgi_pass 127.0.0.1:9000;
Where you currently say you want to reach a fastcgi server on IP 127.0.0.1 port 900, which seems quite wrong.
Use instead:
fastcgi_pass 192.168.x.xx:9000;
And remove proxy_* stuff.
Edit: also, as stated in comments by #Bart, you should not use an if testing that a local file in the document root, matching the php script name does exists. The php files are not on this server. So remove this file.
If you want to apply some security check, you would, later, alter your very generic location [^/]\.php(/|$) to something more specific, like location=/index\.php, or some others variations.
No need to give /sample path
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";
fastcgi_pass IP:9000;
fastcgi_index index.php;
include fastcgi_params;
}
For static files from nginx server you need to use try_files for that.
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
// other CGI parameters
}
Make sure you're aware of common pitfalls.
If you want to access static files from another server you need to run a webserver there and just proxy pass from Nginx
I'm currently trying to setup a generic, multi-project development environment in Vagrant for students of a web-development mentoring project. The idea is the domain <project>.vagrant maps to ~/code/<project>
I thought I had enough experience with Nginx to solve this, but it turns out I don't.
Assuming that PHP-FPM is correctly setup, I need help with the try_files/routing for the site-configuration.
Whilst the homepage (/) works fine, any request to a non-static file (which should therefore be passed to PHP-FPM) results in either a 301 Moved Permanently to the homepage, or downloads the contents of the PHP script instead of executing it.
And yes I know listing so many index files is not ideal but the students will be dealing with multiple projects (phpMyAdmin, WordPress) and frameworks (Symfony, Silex, Laravel, etc).
Any help with this would be greatly appreciated!
The contents of the single site-available configuration file so far is:
map $host $projectname {
~^(?P<project>.+)\.vagrant$ $project;
}
upstream phpfpm {
server unix:/var/run/php5-fpm.sock;
}
server {
listen 80;
server_name *.vagrant;
server_tokens off;
root /home/vagrant/code/$projectname/web;
index app_dev.php app.php index.php index.html;
autoindex on;
client_max_body_size 5M;
location / {
try_files $uri $uri/ / =404;
}
# Pass all PHP files onto PHP's Fast Process Manager server.
location ~ [^/]\.php(/|\?|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Specify the determined server-name, not the literal "*.vagrant".
fastcgi_param SERVER_NAME $projectname.vagrant;
fastcgi_pass phpfpm;
}
}
I've just installed Laravel 4 with nginx on my ubuntu vps following this tutorial:
https://www.digitalocean.com/community/articles/how-to-install-laravel-with-nginx-on-an-ubuntu-12-04-lts-vps
Evertything seemed to be installed fine, however when browsing it's ip adress, I still get:
It works!
This is the default web page for this server. The web server software is running but no content has been added, yet.
I thought this could have something to do with the virtual host, but that one seems to be configured correctlt aswell
server {
listen 80 default_server;
root /var/www/laravel/public/;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# pass the PHP scripts to FastCGI server listening on /var/run/php5-fpm.sock
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Would anynone know what I'm doing wrong?
Thank you!
Your web server should point to the /public folder not the root of your laravel application.
That is /var/www/laravel/public not /var/www/laravel/.
Also make sure you restart your server to load up configuration files.