18

I'm looking for the recommended way of how to configure Nginx server to run Craft.

Currently, I use the following configuration, it works, but I don't know if it could be better:

server {
    listen 80;
    server_name example.com;
    root /home/vagrant/craft/public;

    index index.html index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/example.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~* (?:^|/)\. {
        deny all;
    }

    location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
        deny all;
    }

    location ~* \.(?:manifest|appcache|html?|xml|json)$ {
        try_files $uri /index.php?$query_string;
        expires -1;
        access_log /var/log/nginx/example.com-access.log;
    }

    location ~* \.(?:rss|atom)$ {
        try_files $uri /index.php?$query_string;
        expires 1h;
        add_header Cache-Control "public";
    }

    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
        try_files $uri /index.php?$query_string;
        expires 1M;
        add_header Cache-Control "public";
    }

    location ~* \.(?:css|js)$ {
        try_files $uri /index.php?$query_string;
        expires 1y;
        add_header Cache-Control "public";
    }

    location ~* \.(?:ttf|ttc|otf|eot|woff)$ {
        try_files $uri /index.php?$query_string;
        expires 1M;
        add_header Cache-Control "public";
    }
}

4 Answers 4

6

This Nginx-Craft configuration is one I've been using in production for some time, and it implements many best-practices that you might want to be using:

https://github.com/nystudio107/nginx-craft

11

Definitely not an nginx expert, but this has been working well for anyone that's tried it so far:

server {
  listen 8080 default;
  charset utf8;
  server_name example.com;
  root /path/to/example.com/public;
  index index.php index.html;

  # Logs
  error_log /usr/local/etc/nginx/logs/example.com.error.log debug;
  access_log /usr/local/etc/nginx/logs/example.com.access.log;

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  location ~ ^(.*)$ {
      try_files $uri $uri/ /index.php?p=$uri&$args;
  }

  location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
    expires max;
    add_header Pragma public;
    add_header Cache-Control "public, must-revalidate, proxy-revalidate";
  }

  location = /robots.txt  { access_log off; log_not_found off; }
  location = /favicon.ico { access_log off; log_not_found off; }
  location ~ /\. { access_log off; log_not_found off; deny all; }
}

Note that it's making a few assumptions about how you've setup php-fpm and what ports things are listening on, so those may need to be adjusted.

6
  • Any idea how you would add cross-domain headers? When I add location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { add_header "Access-Control-Allow-Origin" "*"; } I get 404s on the fonts in the admin. Sep 10, 2014 at 21:50
  • 1
    @TrevorDavis you need to add try_files directive i.e. location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { try_files $uri /index.php?p=$uri&$args; add_header "Access-Control-Allow-Origin" "*"; }
    – mohd4482
    Feb 21, 2015 at 21:44
  • Please don't do this. Adding try_files inside of that location block means that it's going to fire up php, Yii, and Craft when serving any of those matching files, both on the backend and on the front-end. This is going to be very slow and inefficient way to serve static resources. Instead make a location block for the /admin url to route only AdminCP requests through index.php Mar 23, 2016 at 7:16
  • @khalwat: not true. try_files actually makes sure the file doesn't already exist on the server first. In fact, most nginx configs for / start with try_files. Your suggestion would work as well but it's going to be the same outcome: internally since the file doesn't exist, nginx is going eventually route back to the php location block. Apr 11, 2016 at 18:59
  • @RitterKnight I thought so too... however that isn't what ended up happening. It may depend on your exact Nginx config, but in the case I mentioned, the requests for static resources were indeed being routed through index.php Apr 25, 2016 at 14:46
4

craftcms.conf

root /srv/http/current-release/src/public;

index index.php index.html index.htm;

charset utf-8;

# Force the latest IE version
add_header "X-UA-Compatible" "IE=Edge";

error_page 404 /index.php;

location / {
    # try_files $uri $uri/ /index.php?$query_string;
    try_files $uri $uri/ @rewrites;
}

location @rewrites {
    rewrite ^(.*) /index.php?p=$1 last;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

    # With php5-cgi alone:
    # fastcgi_pass 127.0.0.1:9000;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
}

# Expire rules for static content

# 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
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
    try_files $uri /index.php?$query_string;
    expires -1;
}

# Feed
location ~* \.(?:rss|atom)$ {
    try_files $uri /index.php?$query_string;
    expires 1h;
    add_header Cache-Control "public";
}

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

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

# Favicons
location = /favicon.ico {
    access_log off;
    log_not_found off;
}
# Robots.txt
location = /robots.txt {
    access_log off;
    log_not_found off;
}

# 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;
}

sites-available.conf

# http://example.com
# http://www.example.com
# This server redirects users to the authoritive non-WWW https site.
server {
    # don't forget to tell on which port this server listens
    #listen [::]:80;
    listen 80;
    server_name example.com www.example.com;
    # and redirect to the non-www host (declared below)
    return 301 https://example.com$request_uri;
}

# https://www.example.com
# This server redirects users to the secure non-WWW https site.
server {
    listen 443 ssl spdy;
    # listen on the www host
    server_name www.example.com;
    include ssl.conf;
    # and redirect to the non-www host (declared below)
    return 301 https://example.com$request_uri;
}

# http://<IP address>
# Allows HTTP direct to the IP address of the EC2 node
server {
    # don't forget to tell on which port this server listens
    listen 80 default_server;
    # listen on the domain name only
    server_name example.com;
    include craftcms.conf;
}

# https://example.com
# The BE ALL END ALL OF NGINX CONFIGURATIONS AT example.com
server {
    # don't forget to tell on which port this server listens
    listen 443 default_server ssl spdy;
    # listen on the domain name only
    server_name naralogics.com;
    include ssl.conf;
    include craftcms.conf;
}
3
  • Not sure, but it might be helpful if we could see an example of your ssl.conf – thanks.
    – kerns
    Feb 12, 2016 at 20:39
  • only charset isnt valid there
    – Adeerlike
    Oct 17, 2016 at 18:18
  • This helped me:location / { # try_files $uri $uri/ /index.php?$query_string; try_files $uri $uri/ @rewrites; } location @rewrites { rewrite ^(.*) /index.php?p=$1 last; }
    – Chuguniy
    Jul 25, 2019 at 12:24
0

I see this is 2 years old post but just wanted to share my findings. So, if anyone comes for a solution next time, he will be able to find a better solution. Please use this gist created by me for details configuration.

Thnx.

3
  • 1
    Why not post the contents of the gist directly into your answer? This is basically a "link-only" answer, which is frowned upon.
    – Lindsey D
    Aug 18, 2016 at 15:53
  • Well as you can see, whole code will be much bigger and non-friendly. Thats why thought maybe link will serve better than whole code. Aug 18, 2016 at 15:59
  • It may be a large answer, but it would be a comprehensive (and better) answer. As it currently stands, if you hypothetically removed the link, this isn't an answer at all. (Thus it's a "link-only" answer.)
    – Lindsey D
    Aug 18, 2016 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.