Nginx configuration for Sylius

Recently we started using the increasingly popular Sylius platform for one of our e-commerce projects. Sylius is based on Symfony2, the leading PHP framework which we have worked with on our photography website. Even though we use WooCommerce for smaller projects, Sylius provides a more modern and powerful solution that we believe is definitely better suited for more ambitious e-commerce websites.

A problem that we initially struggled with was getting Sylius to work properly on our Nginx + PHP-FPM + Ubuntu 14.04 web server. We started with a standard Symfony2 configuration file plus some optimizations, but could not get any product thumbnails to work. Turns out that LiipImagineBundle is used to generate thumbnails on-the-fly, and this was interfering with our cache expiry rule-set, resulting in 404s for any image thumbnails that we tried to display.

Here is what we were incorrectly using to set an expiry date of 1 year in the future for static files:

location ~ \.(js|css|png|jpeg|jpg|gif|ico|swf|flv|pdf|zip)$ { # Set expiry date to 1 year in the future. expires 365d; }
Code language: Nginx (nginx)

While this normally works without a problem, it also means that any URL ending with one of those extensions will completely bypass the app.php file, whether or not the actual image file exists. Since thumbnails in Sylius are created on-the-fly upon a URL request, this completely breaks thumbnail creation.

The fix is very straightforward: We only set the expiry date for requested files that actually exist. Otherwise, we rewrite them to the app.php file, as usual. Here is the final Nginx configuration file that we used:

server { server_name example.com; root /var/www/example.com/web; location / { try_files $uri @rewriteapp; # Redirect to app.php if the requested file does not exist. } # Development rule-set. # This rule should only be placed on your development environment. # In production, don't include this and don't deploy app_dev.php or config.php. location ~ ^/(app_dev|config)\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; } # Production rule-set. location ~ ^/app\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; # Prevents URIs that include the front controller. This will 404: # http://domain.tld/app.php/some-path # Remove the internal directive to allow URIs like this. internal; } # Static files rule-set. location ~ \.(js|css|png|jpeg|jpg|gif|ico|swf|flv|pdf|zip)$ { # Set rules only if the file actually exists. if (-f $request_filename) { # Set expiry date to 1 year in the future. expires 365d; # Further optimize by not logging access to these files. access_log off; } # Rewrite to app.php if the requested file does not exist. try_files $uri @rewriteapp; } # Rewrite rule for PHP files. location @rewriteapp { rewrite ^(.*)$ /app.php/$1 last; } error_log /var/log/nginx/example.com_error.log; access_log /var/log/nginx/example.com_access.log; }
Code language: Nginx (nginx)

That’s it. The thumbnails are now being properly generated on-the-fly, while the existing images are also using proper expiry headers. Let us know if this worked for you, or if you used a different approach. Happy coding!