9

I'm trying to configure a php webapp using docker. The idea is to run the app using php-fpm in a standalone container and have another container that will run nginx. The idea for this setup is to use that same nginx container to proxy requests to other webapps that are already working on the same machine. The problem is that I can't get nginx to properly process static files (js, css, etc.), as the requests to those keep going to fpm.

This is what the filesystem looks like:

/
├── Makefile
├── config
│   └── webapp.config
└── webapp
    └── web
        ├── index.php
        └── static.js

I'm running the whole thing using a Makefile that looks like this (not interested in docker-compose for this):

PWD:=$(shell pwd)
CONFIG:='/config'
WEBAPP:='/webapp'

run: | run-network run-webapp run-nginx

run-network:
    docker network create internal-net

run-webapp:
    docker run --rm \
    --name=webapp \
    --net=internal-net \
    --volume=$(PWD)$(WEBAPP):/var/www/webapp:ro \
    -p 9000:9000 \
    php:5.6.22-fpm-alpine

run-nginx:
    docker run --rm \
    --name=nginx \
    --net=internal-net \
    --volume=$(PWD)$(CONFIG)/webapp.conf:/etc/nginx/conf.d/webapp.domain.com.conf:ro \
    -p 80:80 \
    nginx:1.11.0-alpine

This is what my config/webapp.conf looks like.

server {
    listen 80;
    server_name webapp.domain.com;

    # This is where the index.php file is located in the webapp container
    # This folder will contain an index.php file and some static files that should be accessed directly
    root /var/www/webapp/web;

    location / {
        try_files $uri $uri/ @webapp;
    }

    location @webapp {
        rewrite ^(.*)$ /index.php$1 last;
    }

    location ~ ^/index\.php(/|$) {
        include fastcgi_params;

        fastcgi_pass webapp:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    }
}

Whatever action that needs to get processed using that index.php file will work. However, static files won't be served, resulting in nasty 404 errors (as the php webapp doesn't really have routes configured for those). I believe nginx tries to load those from its own container filesystem, when they are actually in the webapp container, failing back into @webapp.

Is there a way I can configure nginx to serve those files that reside in another container?

  • 3
    Are you using docker to isolate nginx from php applications while requiring that nginx has access to files within the php applications? – Stefan Schmiedl Jun 5 '16 at 19:09
  • I'm not sure I understand your comment... I'm using docker to manage my infrastructure. However, I'm not making nginx request files within the php application, I'm proxying to fpm to do so and I do need nginx to access static non-php files. – ThisIsErico Jun 5 '16 at 20:26
  • The files "reside in another container", i.e. not where nginx can see them, right? – Stefan Schmiedl Jun 5 '16 at 22:17
  • That's right @Stefan, they only get mounted as volumes in the webapp container, not in the nginx one. – ThisIsErico Jun 6 '16 at 4:48
1

I managed to solve the problem by mounting the webapp volume in the nginx container. This is what the run-nginx job looks like now:

run-nginx:
    docker run --rm \
    --name=nginx \
    --net=internal-net \
    --volume=$(PWD)$(CONFIG)/webapp.conf:/etc/nginx/conf.d/webapp.domain.com.conf:ro \
    --volume=$(PWD)$(WEBAPP)/web:/var/www/webapp/web:ro \
    -p 80:80 \
    nginx:1.11.0-alpine

And this is the webapp.conf file, that will try to load the static files from the container and, if that's not possible will proxy the request to the fpm worker:

server {
    listen 80;
    server_name webapp.domain.com;

    root /var/www/webapp/web;

    location ~ \.(js|css|png) {
        try_files $uri $uri/;
    }

    location / {
        rewrite ^(.*)$ /index.php$1 last;
    }

    location ~ ^/index\.php(/|$) {
        include fastcgi_params;

        fastcgi_pass webapp:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    }
}

However, I'd like to know if there's a better way to do so instead of sharing the same volume twice. Thanks a lot!

  • 4
    Given your separation of nginx and php into different containers, I don't think so. You need the data in two different locations, you have to provide it twice. I'm very curious, too, if somebody comes up with a better idea. – Stefan Schmiedl Jun 6 '16 at 18:21
0

Maybe this could be achieved using NFS

One docker container running NFS could be made where the code resides, which could be linked to the containers running nginx and php. The files would be stored in one container only. This could provide another layer of isolation as well.

0

I have two suggested options: The first one is to put your static assets in e.g. /static and instruct nginx to call a different backend service for those. Steps:

1) Update your websites to point to /static/* for any static assets, so e.g. /styles.css becomes /static/styles.css

2) Put your assets either in a separate container served by maybe another nginx (so you can reuse the container for several sites)

3) Edit nginx.conf to send all requests to /static/* to the new container:

location /static/ {
   proxy_pass http://static-container;
}

The second option is to just move your static assets to a CDN, so you just need to update your website to load each static asset from an external URL (https://cdnwebsite/asdsadasda/styles.css instead of /styles.css or /static/styles.css)

The second option has several advantages over the others, mainly around performance. A CDN will serve those faster and you're also working around the simultaneous connection limit a browser can make to each FQDN, so your page might load faster due to more simultaneous connections being used to load your site.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.