Kirby and Nginx

This is a suggestion for the Docs. Can we get documentation on the Nginx setup for Kirby? @bastianallgeier

Edit: Not looking for a solution but proper documentation. Might help those switching from Apache to Nginx.

Hmm… Just setup nginx+php-fpm/fastcgi and setup/convert the .htaccess rules. There exist online converter and I saw in the old forum some basic nginx rules. Just adapt the paths, names, ports and stuff to your needs.

I got kirby running on centos7/nginx1.6.2 with php-fpm. No problems here.

I’m not an nginx expert but I can share my own rules. I’m afraid I can’t really document them. Maybe some nginx expert can join in here:

Thanks. I have had Kirby running on Nginx for the past year or so now. I’m not looking for a solution as I tried explaining above.

That’s unfortunate. Kirby gives Apache users an htaccess file out of the box. I just think that if Nginx is an alternative in the requirements, it should come with some documentation. Perhaps in the future.

@chrisburton I absolutely agree. With Apache this kind of stuff is just super straight forward as you don’t have to mess around with your main Apache conf in most cases. You just add the rewrite rules on top of it. With Nginx you always have to touch the virtual host config and I don’t want to give any hints here which might lead to a unprofessional or even insecure setup. The only way to solve this professionally would be to hire an nginx expert and let him write an example config. But this would still probably not be applicable for all users as virtual host setups can be anything from very simple up to super complex.

That’s very accurate but all you need really is to document the configuration of the location blocks as you’ve done in the gist posted above. Anything else the user needs to take responsibility for.

Do you need anything more detailed for the docs? I think the rules I’ve added are pretty clear. Or what kind of documentation do you have in mind?

I just figured it would be helpful for others that may be switching to a LEMP stack or new to Nginx altogether. Even if you don’t want to document it, it might be helpful to link to that gist somewhere in the docs.

I just patched together what Bastian had already done and mixed that in with the nginX server stuff from h5bp.
Seems quite a good solution.

@AudioBear: Can you please post your config here? thx!

Sorry Svnt, totally missed this. This is our local (localhost like) conf - mostly stuff moved in from the h5bp stuff. It’s not SSL (local) and you will need to set your nginx.conf accordingly. Obviously you will need to alter the paths etc.

# shoes for industry nginx conf for Kirby 2 CMS
# 2016/08/19
# Mostly adapted from
# Local OSX - NO SSL
# v 0.0.3

server {
  listen 80;
  access_log  off;
  # Redirect to the non-www host (declared below)
  return 301 http://$host$request_uri;

server {
  listen 80;
  root       /pathtofolder/Sites/test;
  access_log  /usr/local/etc/nginx/logs/test-access.log;
  error_log  /usr/local/etc/nginx/logs/test-error.log crit;

  # Kirby Cachebuster Plugin for JS & CSS  -
  # Also works with our cachebusterimg Plugin  - shoesforindustry
  location ~*(.+)\.(?:\d+)\.(js|css|jpg|svg|png)$ {
    try_files $uri $1.$2;
  # These are normally seperate config file in h5pb as indicated, 
  # but we are putting them here.
  # ----------------------------
    # Force the latest IE version - h5bp/basic.conf/directive-only/x-ua-compatible.conf
    add_header "X-UA-Compatible" "IE=Edge";
    # Expire rules for static content - h5bp/basic.conf/location/x-ua-compatible.conf
    # No default expire rule. This config mirrors that of apache as outlined in the
    # html5-boilerplate .htaccess file. However, nginx applies rules by location,
    # the apache rules are defined by type. A consequence of this difference is that
    # if you use no file extension in the url and serve html, with apache you get an
    # expire time of 0s, with nginx you'd get an expire header of one month in the
    # future (if the default expire rule is 1 month). Therefore, do not use a
    # default expire rule with nginx unless your site is completely static

    # cache.appcache, your document html and data - remove 'xml' from below if you want sitemap.xml to work
    location ~* \.(?:manifest|appcache|html?|json)$ { 
      expires -1;
      access_log /usr/local/etc/nginx/logs/static.log;

    # Feed
    location ~* \.(?:rss|atom)$ {
      expires 1h; #expires 1h;
      add_header Cache-Control "public";

    # Media: images, icons, video, audio, HTC
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
      expires 1M; #expires 1M;
      access_log off;
      add_header Cache-Control "public";

    # CSS and Javascript
    location ~* \.(?:css|js)$ {
      expires 1y;  #expires 1y;
      access_log off;
      add_header Cache-Control "public";

    # WebFonts
    # If you are NOT using cross-domain-fonts.conf, uncomment the following directive
    location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
      expires 1y;  #expires 1y;
      access_log off;
      add_header Cache-Control "public";

    # Expire rules for static content - h5bp/basic.conf/location/protect-system-files.conf
    # Prevent clients from accessing hidden files (starting with a dot)
    # This is particularly important if you store .htpasswd files in the site hierarchy
    location ~* (?:^|/)\. {
        deny all;

    # Prevent clients from accessing to backup/config/source files
    location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
        deny all;
    # Extra security - h5bp/basic.conf/directive-only/extra-security.con
    # The X-Frame-Options header indicates whether a browser should be allowed
    # to render a page within a frame or iframe.
    add_header X-Frame-Options SAMEORIGIN;
    # MIME type sniffing security protection
    # There are very few edge cases where you wouldn't want this enabled.
    add_header X-Content-Type-Options nosniff;
    # The X-XSS-Protection header is used by Internet Explorer version 8+
    # The header instructs IE to enable its inbuilt anti-cross-site scripting filter.
    add_header X-XSS-Protection "1; mode=block";
    # with Content Security Policy (CSP) enabled (and a browser that supports it (,
    # you can tell the browser that it can only download content from the domains you explicitly allow
    # CSP can be quite difficult to configure, and cause real issues if you get it wrong
    # There is website that helps you generate a policy here
    # add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self';";

    # Prevent mobile network providers from modifying your site- h5bp/basic.conf/directive-only/no-transform.conf
    # Prevent mobile network providers from modifying your site
    # (!) If you are using `ngx_pagespeed`, please note that setting
    # the `Cache-Control: no-transform` response header will prevent
    # `PageSpeed` from rewriting `HTML` files, and, if
    # `pagespeed DisableRewriteOnNoTransform off` is not used, also
    # from rewriting other resources.
    add_header "Cache-Control" "no-transform";
  # ----------------------------
  # Character Set
  charset UTF-8;

  # php
  location ~\.php$ {
      include   /usr/local/etc/nginx/conf.d/php-fpm;

  # block content
  location ~ ^/content/(.*).(txt|md|mdown)$ {
    rewrite ^/content/(.*).(txt|md|mdown)$ /error redirect;

  # block all files in the site folder from being accessed directly
  location ~ ^/site/(.*)$ {
    rewrite ^/site/(.*)$ /error redirect;

  # block all files in the kirby folder
  location ~ ^/kirby/(.*)$ {
    rewrite ^/kirby/(.*)$ /error redirect;

  # site links
  location / {
    try_files $uri $uri/ /index.php?$uri&$args;

  # panel links
  location /panel {
    try_files $uri $uri/ /panel/index.php?$uri&$args;

  # Error pages
  error_page  404     /error;
  error_page  403     /error;

}# End