Delivering images with an image proxy

Doug Sillars, DevRel
Jan 23, 2024
When building websites, images play a huge role. The median website has 1 MB of images on each page (State of the images on the web). But, when we get an image from a photographer or designer, the images may be several megabytes each. In order to properly display the images on the web, we don’t want to send a huge raw file. It should be resized to fit the screen, and to ensure that webpage loads quickly, the size should be reduced so that the file can be delivered quickly.

Delivering images with an image proxy

When building websites, images played a huge role.  The median website has 1 MB of images on each page (State of the images on the web). But, when we get an image from a photographer or designer, the images may be several megabytes each. In order to properly display the images on the web, we don’t want to send a huge raw file.  It should be resized to fit the screen, and to ensure that webpage loads quickly, the size should be reduced so that the file can be delivered quickly.

There may be many versions that must be created for each image (a mobile version, a desktop version, a thumbnail, etc.)  This can all be done manually, but it is a tedious and slow process. If the website design changes, every image might require re-processing - requiring thousands of hours of manual work.

One potential solution to automate image creation is to use an image proxy.  Image proxies take the original image as input, instantly create a unique version of the image at the time of request.  That way, raw images can be stored on the server, but optimzied and resized images are delivered to your customers on demand.  When the image requirements for the website change, the proxy rules can be updated, and the new images created on the fly.

In this post, we’ll walk through the steps to deploy imgproxy and create urls with imgproxy to resize and securely deliver images.

Imgproxy

Imgproxy is a free, open source tool that quickly and securely delivers modified images to your customers. Being open source, it requires that you self host the application on your servers.  There is a pre-built docker container, and we will use that to launch imgproxy on Dome.  To make things even easier, Dome offers a one-click install.  This link will install and deploy imgproxy into your Dome project.

Clicking the one-click link brings to to Dome:

Click the Deploy button, and your imgproxy will be up and running in seconds:

That’s it! We’re now ready to learn how to use imgproxy to resize our images!

Using imgproxy to resize images.

In this tutorial, we will deploy a number of frog images into a flask server and deploy them on Dome,  frog2.jpg is a 5MB file and 5184 × 3456 pixels  - which is much too large to serve on a website.  But it is nice to have the raw image available, in case we need to make changes to the image later. Let’s use imgproxy to resize the image to a reasonable size.

Imgproy uses the URL to manipulate images. The URL takes the following format:

https://yourdomain.com/securekey/parameters/url_to_your_image.jpg
  • As seen in the previous section, my domain is: https://imgproxy-1460.dome.tools/
  • For now, we will not use security (we will add this in the next section), so we can just use the string “securekey.”
  • Parameters  Image manipulation instructions. (We’ll go over this in the next section.)
  • URL you your image:  this will be a URL that is live on the internet. If your images are on a Dome server, it will have a dome.tools url.

The parameters section is where the fun occurs. Each manipulation is bracketed between forward slashes, as if they are directories in the URL path:  

  • Format: We can change the format of the image from jpg to a different format. For example, the webp format is supported in all modern browsers, and generally compresses the image to a smaller size.  By adding the /f:webp/ parameter, we are  telling imgproxy that we would like the jpg converted into a webp.
  • Width: The frog2 image is 5184 pixels wide.  By adding /w:200/, we can make the image 200 pixels wide (and keeping the aspect ratio - the height will be correctly scaled as well).  As you might guess w:1000 would be 1000 pixels wide, etc.

The image URL:  In this case, we’ll add a “plain” identifier, as we are using a URL to point to the original image:

To create this image:

https://imgproxy-1460.dome.tools/securekey/w:1000/f:webp/plain/https://<url to frog image>/frog2-2000.jpg

Our new frog image is just 77 KB, which is very suitable for delivery on the web.

More fun with parameters

  • We can add a blur:  (with parameter /blur:10/)
  • Cropping images. Using /c:1000:1000/.  This creates an image 1000x1000, using the center of the image for the crop.

This crop looks a bit odd, as the frog’s head is not in the center of the image, and one eye is cropped out.  Imgproxy offers a smart gravity feature that  centers on the face of the frog (/c:1000:1000:sm/):

The smart gravity filter finds the “most visually interesting” part of the image, and centers the crop on that feature. Now the frog is nicely centered in our cropped image.

With these features, you can programmatically crop, resize and manipulate your raw images at the time of website delivery - making your images incredibly dynamic, while not creating hundreds of images to manage on your server.

Securing Imgproxy

The URL format used in imgproxy could be used by any user who examines the image source.  They could use your imgproxy instance to resize their images for free.  Clearly, we need some security to lock down the urls to images controlled by the team.   This can be done by signing the url using a key and salt.  Imgproxy describes the process in their documentation, and provides several code examples to help with the process.  We first create 2 hexadecimal strings - one for the key and the other for the salt.

Here is the python signature code.  Simply add the key and salt hex strings, and in the path variable, update the url to your image, and add any transformations that are required. In the final print command, update the domain for your imgproxy server:

   

        import base64
        import hashlib
        import hmac

        key = bytes.fromhex("")
        salt = bytes.fromhex("")

        path ="/c:1000:1000/f:webp/plain/".encode()

        #print(path)
        msg=salt+path
        digest = hmac.new(key, msg=salt+path, digestmod=hashlib.sha256).digest()
        signature = base64.urlsafe_b64encode(digest).rstrip(b"=")

        url = b'/%s%s' % (
            signature,
            path,
        )

        print(f"https://{url.decode()}")

   

Next, we need to tell imgproxy our IMGPROXY_KEY and IMGPROXY_SALT.  These are environmental variables.  In your Dome dashboard, find your imgproxy server, and in settings, add two environmental variables for the key and salt:

When these variables are saved, redeploy the server, and we should be all set!

Now, the /securekey/ in the path is replaced with a unique hex string that verifies the user has permission to create the image!

https://imgproxy-1460.dome.tools/gfU-QZIx_Nqkl8DAOlzfSIHHhm3ottRfClrR-Ue-ZOo/c:1000:1000/f:webp/plain/https://<url>frog.jpg

Real world usage

In the examples above we have used custom resizing, updated the format, and even used smart cropping.  On a live website, there might be multiple sizes for each image used: thumbnails, mobile, desktop and more.  By using imgproxy to create the images dynamically, just one image is stored on the server, but the optimal image is delivered to the user.  

No longer does each image require custom resizing and manipulation by a designer, but we can programmatically create the images that appear on the website.  We can now program our backend server to deliver each image, and the same parameters can be used across hundreds of images - simplifying delivery.

Several years ago, I discovered that 1% of websites have Mac Screenshots live on their websites. Using the screenshot tool on your computer is incredibly handy, but the images are not designed to be web friendly.  Simple optimizations like those described above would have made a huge percentage of these images 75% smaller!

Conclusion

Removing the complexity of image creation for a website allows for faster deployments and updates. Using an imgproxy allows for extremely fast delivery of customized images to your customers. Using the one-click Dome installation of the image proxy further simplifies the process, and takes the complexity of image delivery.  If you are looking for a one-stop location to deploy your website, database (imgproxy) and more, try out Dome!

Share this post