Posts tagged 'nginx'

Docker nginx host not found in upstream error

published on January 30, 2018.

I’ve been toying around with Docker for the past couple of days, mostly to learn more about it, to understand it better. I just didn’t bother with it until now.

I started from scratch. Installing Docker, configuring it (I really don’t appreciate it filling my root partition with images), and, well, using it. I sort of figured out the docker command line interface, I get the difference between images and containers, I know how to write a Dockerfile, and when all the commands and options and flags start get confusing I know where to look in the help for help.

Happy with the progress I made, it was time to start connecting different containers so that they can talk to each other. Starting with a single container with nginx in it, and another container with php-fpm in it. Using their official images even.

To keep my sanity intact, as much as it is possible with software these days, I heeded Vranac’s advice and installed docker-compose for that.

No cheating, so I wrote my own docker-compose.yml file using just the documentation:

version: '3'
services:

    php:
        image: php:7.2-fpm
        expose:
            - "9000"
        volumes:
            - ./app:/app

    nginx:
        image: nginx:stable
        ports:
            - "8080:80"
        volumes:
            - ./site.conf:/etc/nginx/conf.d/default.conf
            - ./app:/app
        depends_on:
            - php

And now let’s build it and bring up the containers:

$ docker-compose build
$ docker-compose up

Aaaaaaand… It dies with an error like:

nginx: [emerg] host not found in upstream "php" in /etc/nginx/conf.d/default.conf:15

Blergh. I guess I missed something from the documentation. Fast-forward 2 hours, dozens of google searches and articles, countless rewrites of the docker-compose.yml file, and zero luck. Whatever I did, same error: “host not found in upstream”.

Then I finally remembered. What is the one thing that always causes me grief when trying to work with a web server? That’s right: SELinux!

Turn off selinux, restart docker, build && up, and it works. Sonofa. Works even with the very first version of docker-compose.yml I wrote.

OK, turning off selinux can’t be the solution, so I searched more… And no one, ever, recommends, or even mentions, that selinux might be the problem. I’ve installed the Docker SELinux package (it’s container-selinux on my Fedora 26). It should be working!

Another hour later, more searches and articles, I end up at the beginning, at the “Get Docker CE for Fedora” documentation page. Docker CE? What the fresh hell is this?

Well, it’s the docker version I should’ve installed in the first place.

Fedora’s repos have docker version 1.13.something. Docker-CE is at 17.12.something.

Remove old docker, re-enable selinux, install new docker, everything works just fine, and run the following:

sudo ausearch -c 'iptables' --raw | audit2allow -M my-iptables
sudo semodule -X 300 -i my-iptables.pp

I have no idea what that does, but it was required to make it work.

sigh

Happy hackin’!

PHP-FPM security limit extensions issue

published on February 03, 2017.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

For the first time ever I saw this error:

2017/02/03 11:45:04 [error] 14656#0: *1 FastCGI sent in stderr: "Access to the script '/var/www/web' has been
denied (see security.limit_extensions)" while reading response header from upstream, client: 127.0.0.1, server:
proj.loc, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm/www.sock:", host: "proj.loc"

I mean… what? security.limit_extensions? I honestly never heard of this before.

The PHP manual describes it as:

Limits the extensions of the main script FPM will allow to parse. This can prevent configuration mistakes on the web server side. You should only limit FPM to .php extensions to prevent malicious users to use other extensions to execute php code. Default value: .php .phar

Basically to avoid executing what an application might consider as a non-PHP file as a PHP file.

OK, cool, but why am I getting this error?

The currently top answer on Google suggests setting the list of limited extensions to an empty string, to practically disable the security.limit_extensions configuration. That fixes the error, but I’m really not comfortable with setting a security related configuration to a blank value, especially when people smarter than me set that configuration to a sane default value.

There must be a better, proper way to fix this, and this does feel like I misconfigured something in the nginx/php-fpm stack.

Accessing a folder as a script?

The Access to the script '/var/www/web' has been denied part of the error messages also looks weird. Why would php-fpm try to access /var/www/web, which is a directory, as a script? Seems like it doesn’t see the actual PHP script, and that sounds awfully similar to that old, dreaded No input file specified error message.

And that one is, in most cases, caused by not including the fastcgi.conf params file in the location block in the nginx configuration files. I double checked the configuration file and yup, I missed to include the fastcgi params file:

server {
    # configuration for the server
    location ~ \.php$ {
        # configuration for php
        include fastcgi.conf; # << I missed this!
    }
}

I restarted nginx and everything works just fine, without touching the security.limit_extensions configuration.

Happy hackin’!

Setting up SSL certificates with Let's Encrypt

published on July 06, 2016.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

SSL Report Summary

This past week I finally got around to setting up SSL certificates using Let’s Encrypt. Let’s Encrypt is an open certificate authority that provides free SSL/TLS certificates. It’s goal is to make creating, renewing and using SSL certs painless.

And it most certainly is. I was expecting a lot more hassle to set up all this, but it was really easy to do.

Install certbot

Certbot is a Let’s Encrypt client that helps setting up a certificate by obtaining and installing it on your servers. There are many more clients out there, but certbot is the recommended one to use.

I simply installed certbot using dnf:

sudo dnf install certbot

but if your OS has no package for it yet, there’s always the manual way.

Creating a certificate

Certbot has a number of plugins that can be used to create and install a certificate on a server. I chose the webroot plugin which only gets the certificate for me and leaves the webserver configuration up to me.

sudo certbot --text --renew-by-default --agree-tos --webroot \
--email youremail@domain.tld \
--domains domain.tld,www.domain.tld \
--webroot-path /path/to/site/public \
certonly

This will create the certificate and it’s private key in the /etc/letsencrypt/live/domain.tld/ directory.

Configuring nginx

The next step is to configure nginx by enabling SSL, providing the paths to the certificate and the private key, and which protocols and ciphers to use. I added these to the server block:

listen 443 ssl;

ssl on;
ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;

After restarting nginx, you should be able to load up your site through https. Just remember to allow traffic on the 443 port:

sudo firewall-cmd -add-service=https --permanent
sudo firewall-cmd reload

Additional configuration

To further harden the Diffie-Helman key exchange, create new parameters for it using openssl:

sudo mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
sudo openssl dhparam -out dhparams.pem 2048

I told nginx to use it by adding it to the same server block where I set up the SSL configuration:

ssl_dhparam /etc/nginx/ssl/dhparams.pem;

I also did some SSL optimizations and enabled Strict Transport Security:

ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_buffer_size 8k;
add_header Strict-Transport-Security max-age=31536000;

This blog post explains HTTP Strict Transport Security nicely.

All this and my website gets an A+ rating on the Qualys SSL Server Test.

Enable OCSP stapling

Thanks to Goran Jurić for pointing out to enable OCSP stapling. I did so by adding this to the nginx server config:

ssl_stapling on;
ssl_stapling_verify on;

According to the nginx documentation the ssl_trusted_certificate directive is needed only when the ssl_certificate file does not contain intermediate certificates, but the fullchain.pem created by Let’s Encrypt does contain them, so I’m skipping that.

To test whether OCSP stapling is enabled, reload nginx, and from a local terminal run the following:

openssl s_client -connect domain.tld:443 -status

The output should have something like:

OCSP response:
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2019
Get the feed