How to customize Dokku nginx configuration post

Foreword

In some cases default nginx configuration is insufficient. Of course we can run dedicated server for the app, but what's happen if we want to use dokku? Then we're forced into customize nginx configuration.

Assumptions

I assume you have installed the most recent version of dokku. Here I described how to prepare php app to support dokku.

More info:

Requirements

In our case I'd like to catch only request which are referred to /test/ subdirectory instead of / root.

 #old version               => new version
 http://myapp.dev/          => http://myapp.dev/test/
 http://myapp.dev/admin/    => http://myapp.dev/test/admin/

Dokku nginx architecture

In order to do this you have to understand how dokku works (handle requests). Below image is showing flow.

Dokku Flow

  1. We send request to webserver that handles requests
  2. First nginx webserver (installed on linux with dokku) handle our request and pass them to docker containers
  3. In docker container for PHP buildpack we can choose one of the few configurations. It could be nginx, apache and both them can work with php and hhvm. More info here (click)
  4. In our case nginx configured with php handle our requests and launch them using php-fpm or hhvm

Configuration

Please add below files into your project root directory.

.env - This file describe which heroku buildpack we want to use. What is buildpack? More info here

export BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-php#v90

nginx.conf.template - The base template for first level nginx proxy. Dokku use it to generate a vhost' nginx configuration. It's configured to pass every request (proxy).

server {
  listen      [::]:$NGINX_PORT;
  listen      $NGINX_PORT;
  server_name $NOSSL_SERVER_NAME;
  access_log  /var/log/nginx/${APP}-access.log;
  error_log   /var/log/nginx/${APP}-error.log;

  location /test { ### <- HERE I ADDED ``test`` suffix

    gzip on;
    gzip_min_length  1100;
    gzip_buffers  4 32k;
    gzip_types    text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml  application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
    gzip_vary on;
    gzip_comp_level  6;

    proxy_pass  http://$APP; ### <- HERE IS THE MOST IMPORTANT PART
    proxy_http_version 1.1;
    proxy_set_header Upgrade \$http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host \$http_host;
    proxy_set_header X-Forwarded-Proto \$scheme;
    proxy_set_header X-Forwarded-For \$remote_addr;
    proxy_set_header X-Forwarded-Port \$server_port;
    proxy_set_header X-Request-Start \$msec;
  }

  include $DOKKU_ROOT/$APP/nginx.conf.d/*.conf;
}

nginx.conf.file - This file is used by heroku buildpack and should be fully compatible with heroku/dokku. In order to change default nginx configuration in the app container (based on docker) we have to override default configuration.

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        off;
    keepalive_timeout  65;
    fastcgi_buffers 256 4k;

    # define an easy to reference name that can be used in fastgi_pass
    upstream heroku-fcgi {
        #server 127.0.0.1:4999 max_fails=3 fail_timeout=3s;
        server unix:/tmp/heroku.fcgi.<?=getenv('PORT')?:'8080'?>.sock max_fails=3 fail_timeout=3s;
        keepalive 16;
    }

    server {

        server_name localhost;
        listen <?=getenv('PORT')?:'8080'?>;
        port_in_redirect off;
        root "<?=getenv('DOCUMENT_ROOT')?:getenv('HEROKU_APP_DIR')?:getcwd()?>";

        rewrite_log on;
        error_log stderr notice;
        access_log /tmp/heroku.nginx_access.<?=getenv('PORT')?:'8080'?>.log;

        location /test/ {
            rewrite ^/test/(.*)$ /$1 break;
            try_files $uri @apphandler;
        }

        location @apphandler {
            fastcgi_pass heroku-fcgi;
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME <?=getenv('DOCUMENT_ROOT')?:getenv('HEROKU_APP_DIR')?:getcwd()?>/app.php;
            fastcgi_param SCRIPT_NAME /test/app.php;
            fastcgi_param REQUEST_URI /test$uri?$args;
            fastcgi_param HTTPS off;
        }

        # restrict access to hidden files, just in case
        location ~ /\. {
            deny all;
        }
    }
}

Procfile - This file define that web server (nginx/apache) we want to use and what config should be use to run nginx.

web: bin/heroku-php-nginx -c nginx.conf.php web/

After above steps your project structure should be similar to:

/Procfile
/composer.json
/composer.lock
/nginx.conf.php
/nginx.conf.template
/src
/vendor
/web

Enjoy!


Links

Kategorie: devops, php

Tagi: docker, dokku, heroku, cloud, php, staging