WordPress developer, consultant, nerd

Variable VVV: Avoid 404 errors when loading images by proxy

By using the --images option when creating a site with VV, you can set your local site to load images by proxy; that is, to load images from a remote site at a particular domain. This is great for saving space on your own system, and it also means you can get to work quicker, as you don’t need to download any images that have been uploaded to the WordPress installation.

The drawback to using this method, however, is that it doesn’t look for local files at all. This is a problem if you are uploading images to posts on your local copy with the intention of uploading them to the live site later, as you end up with local 404 errors on those images. The reason this happens is because VV sets up the following location directive inside the site’s .conf file;

location ~ ^/wp-content/uploads/(.*) { rewrite ^/wp-content/uploads/(.*)$ http://mydomain.com/wp-content/uploads/$1 redirect; }

This location directive does exactly what it is supposed to: if any files within the /wp-content/uploads/ directory are requested, the request is rewritten so that the image is served from the domain specified by mydomain.com.

The problem I kept coming up against was the 404 error whenever a local file doesn’t yet exist on the remote server. To get around this, I changed the location directive so that NGINX first checks for a local copy of the requested file and then, if it can’t find one, rewrites the request to the remote domain.

Heads up!

I have submitted this as a feature request on the VV Github repository, so it may very well end up making it’s way into VV in the near future.

Step 1: Open the relevant NGINX configuration file

Open the {your vagrant installation directory}/config/nginx-config/sites/{mydomain.com}.conf file. The file contents will look something like the following;

################################################################
# Example configuration file for nginx
#
# To add a new local WordPress domain to your environment, copy
# this file using a filename that matches the domain you wish to
# setup. For example - mylocaldomain.com.conf would be an ideal 
# filename for http://mylocaldomain.com
#
# Once copied, you will need to modify two settings in the server
# configuration provided:
#
# 1. server_name - Change the server_name parameter in the server
# configuration below to mylocaldomain.com
# 2. root - Change root to the full path that your WordPress
# site lives at inside Vagrant. An example would be
# /srv/var/www/vhosts/philkurth.com.au/httpdocs/mylocal-wordpress
#
# You do not need to worry about modifying the listen or include
# parameters as those are the same across all test sites for most
# basic WordPress configurations.
#
# Once your new domain has been added, make sure to restart the
# nginx process by running `vagrant provision` in your local
# environment or `sudo service nginx restart` after `vagrant ssh`
################################################################
server {
 # Determines the port number that nginx will listen to for this
 # server configuration. 80 is the default http port.
 listen 80;

 # Listen for HTTPS requests as well
 listen 443 ssl;

 # Tells nginx what domain name should trigger this configuration. If
 # you would like multiple domains or subdomains, they can be space
 # delimited here. See http://nginx.org/en/docs/http/server_names.html
 server_name mydomain.com.au.dev ~^mydomain.com.au\.\d+\.\d+\.\d+\.\d+\.xip\.io$;

 # Tells nginx which directory the files for this domain are located
 root /srv/var/www/vhosts/philkurth.com.au/httpdocs/mydomain.com.au/htdocs;

 # Includes a basic WordPress configuration to help with the common
 # rules needed by a web server to deal with WordPress properly.
 include /etc/nginx/nginx-wp-common.conf;

 # This is the location directive we need to modify
 location ~ ^/wp-content/uploads/(.*) { if (!-f $request_filename) { rewrite ^/wp-content/uploads/(.*)$ http://mydomain.com/wp-content/uploads/$1 redirect; } } 
}

Step 2: Modify the NGINX location directive inside the server block

Find the existing location directive, which should be at the bottom of the server{} block, and replace it with the following directive;

location ~ ^/wp-content/uploads/(.*) { 
    if (!-f $request_filename) { 
        rewrite ^/wp-content/uploads/(.*)$ http://mydomain.com/wp-content/uploads/$1 redirect; 
    } 
}

This modified directive tells NGINX to only rewrite the request URL if the requested file does not exist locally.

Note:

If you don’t already have a location directive in your .conf file, you can just add this to the file. Just be sure to place it inside the server{} block’s brackets.

Step 3: Provision vagrant

You’ll now want to run the vagrant provision command from your terminal to ensure the new changes take effect. I found that running sudo service nginx restart wasn’t enough for the new configuration to work, but if someone has a quicker alternative to a full provision, I’d love to hear it. Read about why, here.