18

Just to start off, I have seen this. But he/she uses build, and I use image.

I have a docker-compose file that pulls an image that I have made previously onto my server.

app:
  restart: always
  image: some-app-image:latest

nginx config

location /static/ {
    root /data/app/web_interface;  <--- this exists in some-app-image container
}

Normally, I would have a volume mounted onto the app image that contains the static files.

However, this is becoming redundant since the app container has the static files in itself.

All the nginx container needs to do is "peer" into the app container and serve those static files. Like:

location /static/ {
    root http://app:8000/web_interface;
}

or

location /static/ {
    root app/web_interface;
}

Any chance there is a way to serve static files located in another container from a nginx container?

Andrew Graham-Yooll
  • 2,148
  • 4
  • 24
  • 49
  • Your container setup is a bit unclear. You have an nginx container working as a reverse proxy already serving data from your `app` container (virtual host)? Why can't the `app` container serve its own static files? – Grimmy Jul 18 '17 at 15:25
  • I have nginx serving static files as I don't want the gunicorn server handling them. https://stackoverflow.com/a/13947418/5779280 – Andrew Graham-Yooll Jul 18 '17 at 15:32
  • Just to be clear: The app container runs gunicorn and your nginx container serves that though a uwsgi_pass? – Grimmy Jul 18 '17 at 16:03
  • More or less, a `proxy_pass` to be specific. – Andrew Graham-Yooll Jul 19 '17 at 07:19

4 Answers4

5

All the ideas I've had in the past:

Sharing a docker volume from app to nginx

You can make a volume in the app's Dockefile and copy in the staticfiles when the container runs. Then share the volume with nginx container using volumes_from. This is kind of ugly and doesn't work at all if your app depends_on nginx. I'd say this is definitely a no-go as it works terribly when scale up your app container.

The idea of also mapping staticfiles from the host into the nginx container is also not optimal. You'll have an extra weird step to deal with them.

Separate static container

Build another nginx container serving only the static files on a different virtualhost. static.foo.bar.

Use a CDN

There are tons of CDNs out there you can put your staticfiles and most frameworks have plugins for handling that. I have some projects doing this. Works great.

Use uWSGI

You can serve staticfiles with uWSGI using --static-map. See docs. This is what I ended up doing as it was a cheap and easy... and friendly when it comes to scaling. Then you probably also need to use http-socket so uWSGI talks http instead.

Grimmy
  • 3,992
  • 22
  • 25
  • Hey thanks for this answer. I like the CDN option however we need to move pretty quickly and I feel like that would take a longer time to set up than the uWSGI solution. I always thought that serving static files from the application server was a no-no. I guess the method has evolved. – Andrew Graham-Yooll Jul 19 '17 at 07:28
  • 1
    I'd say it's not optimal to serve static files from the app server, but it's not necessarily bad. If you need to move quick, that is the safe and easy way. It just works. php have been doing that for ages. – Grimmy Jul 19 '17 at 11:47
  • It's not perfectly clear, but one of the options (the one you not recommend) you mentioned seems to describe [my solution](https://stackoverflow.com/a/56855338/52499). Can you elaborate? Under which conditions I'm going to face issues? What kind of issues exactly? – x-yuri Jul 02 '19 at 15:12
  • I concur -- why is a docker volume between app and nginx bad here? – SethGoodluck Apr 29 '20 at 18:43
  • It get gets too messy when running in clustered environments in my opinon, but I'm probably a purist when it comes to docker. – Grimmy Apr 30 '20 at 02:13
  • I've tried a docker volume to share static files between php and nginx (for drupal) and found that its just to messy. Volumes dont get reinstalled when you recreate the container (narurally) so how to upgrade, remove volume to, but how to persist uploads... ended up with apache image as a base for my app. – Johan Nov 11 '21 at 09:31
  • One could perhaps create two Dockerfiles, one for nginx and one for the "app", copy all static content and boostrapper to nginx, and everything else to the app. Share uploads on a volume. – Johan Nov 11 '21 at 09:36
5

This is a very late answer, but adding it in case someone else finds this.

Perhaps you could make use of server caching so that NGINX will effectively serve the static files from it's file system after the first request to the app being proxied.

Here is a good guide to caching with NGINX

You could set the inactive flag to a long time as the assets are static.


Basic example based on the guide above:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=30d use_temp_path=off;

server {
  ...

  location /static {
    proxy_cache my_cache;
    proxy_pass http://app:8000/static; # <--- wherever static files are on app server
  }

  ...
}
Steve Holgado
  • 11,508
  • 3
  • 24
  • 32
2

One of the solutions is to copy assets to a shared volume on app service's start:

docker-stack.yml:

volumes:
  docroot:
services:
  site:
    volumes:
      - docroot:/docroot
  nginx:
    volumes:
      - docroot:/docroot

app service's entrypoint.sh:

#!/usr/bin/env sh
rsync -a --delete --exclude /uploads public/ /docroot
# start the site

WORKDIR is at /app. docroot at /app/public. Here I additionally make it not copy uploads dir.

More on it here.

x-yuri
  • 16,722
  • 15
  • 114
  • 161
2

I did something similar but different:

I have docker-compose running two containers: nginx and flaskapp. I have the nginx container serve static requests and forward the rest to the flask app. Here's my nginx config (flaskapp.conf):

server {
listen 80;
server_name $SERVER_NAME;

location ^~ /static/  {
    include  /etc/nginx/mime.types;
    root /;
}

location / {
    proxy_set_header Host $host;
    proxy_pass http://frontend:8000;
}
}

and the dockerfile for my nginx container:

FROM nginx

RUN rm /etc/nginx/conf.d/default.conf
RUN mkdir static
COPY /static/ /static/
COPY flaskapp.conf /etc/nginx/conf.d/

I copy over a static folder that has the assets I need and now I can load them into the front end.

grantr
  • 878
  • 8
  • 16