[2/3] - Dockerising FreshRSS (nginx)

In the previous video we covered how to create a Dockerfile for our PHP code. This is good, as it allows us to serve up our Fresh RSS PHP code on - in our case - PHP 7.2, but in order to actually access that code, we must have a web server in front of it.

I'm going to use nginx.

The official docs recommend Apache, but also provide an nginx config. Personally I prefer nginx, and honestly, there's no specific reason to choose Apache here, I think it's recommendation of the docs author only. However, I may be wrong here, so do shout up if I have overlooked something.

nginx Docker Image

The good news is we already created a working nginx Docker image for our PHP container to work with.

We're going to re-use this, and the nice part is we only need to provide a changed server configuration file. Everything else is the same.

Here's our starting point:

cd {project root}
mkdir web
cd web
touch Dockerfile

Then, into the Dockerfile we add:

FROM nginx:stable


COPY ./conf.d/upstream.conf /etc/nginx/conf.d/
COPY ./conf.d/freshrss.dev.conf /etc/nginx/conf.d/

There is nothing new here, save for the name of the freshrss.dev.conf file.

Let's setup our config:

mkdir conf.d
cd conf.d
touch upstream.conf
touch freshrss.dev.conf

The upstream.conf file is identical to what we covered already:

upstream php-upstream {
  server php:9000;

This says our PHP container will expect to have the hostname of php. We will sort this out using docker-compose.yml shortly.

Server Config

The official docs provides an nginx config.

Here's the one we're going to use:

server {
    listen 80 default;

    # your server’s URL(s)
    server_name freshrss.dev;

    # the folder p of your FreshRSS installation
    root /var/www/freshrss/p/;

    index index.php index.html index.htm;

    # nginx log files
    access_log /var/log/nginx/rss.access.log;
    error_log /var/log/nginx/rss.error.log;

    # php files handling
    # this regex is mandatory because of the API
    location ~ ^.+?\.php(/.*)?$ {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        # By default, the variable PATH_INFO is not set under PHP-FPM
        # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var!
        fastcgi_param PATH_INFO $fastcgi_path_info;

        try_files                  $uri =404;
        fastcgi_param              SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass               php-upstream;
        fastcgi_index              index.php;
        include                    fastcgi_params;

    location / {
        try_files $uri $uri/ index.php;

Ok, so what's different?

Firstly, no SSL.

In my case I wanted to host this project locally, only.

If you need SSL then feel free to add that section back in.

However, when deploying to production I use Rancher, which can be combined with LetsEncrypt at the load balancer layer, which removes the need to have SSL configured on the nginx instance anyway. This is a touch more advanced, and we will cover Rancher deployments in a separate series. At the time of writing, Rancher is just about to go from version 1.0 to 2.0, and the changes will be significant. Therefore I am holding off on the tutorial whilst this major change is released.

Our server name is different. We will access the site either via a local host entry (/etc/hosts) of freshrss.dev, or my preference, and whatever port we have exposed. Don't worry about this just now, we will explore this more when looking at the docker-compose.yml file.

Our site root is different.

This is hardcoded, which is unfortunate, as our WORK_DIR from the PHP video is dynamic. I don't know of an easy way around this without making your Dockerfiles much more complicated. For me, hardcoding here is fine. I've not found a major downside to this, other than having to manually update this path at the start of a new project.

The only other change is to pass PHP requests to our php-upstream. This is because our nginx container doesn't have PHP installed so must hand off requests to our PHP container in order for them to be properly processed.

The good news?

We're done with our nginx config.

Let's now tie this all together with docker-compose.yml.

Code For This Course

Get the code for this course.