NodeJS and Nginx Image Server

My name is Zach Noren and I am a Software Engineer living in Silicon Valley.

26 05-2015
NodeJS and Nginx Image Server

The Problem:

Recently at work I took a project that had the potential to dramatically streamline a process that is a major portion of our business. Construct a new on-demand image watermarking and caching server. First some backstory on what I do and our current process for watermarking images.

I work for a startup in Silicon Valley as a Sr. Software Engineer. Startups being startups I wear multiple hats (Everything from infrastructure management to running ethernet cables and setting up access points in our warehouses). We have a large home grown ERP system that allows for selling of inventory on multiple ecommerce platforms for multiple seller accounts. We handle everything from order fulfillment, automatically revising and listing items on multiple selling platforms, to inventory management and warehousing.

Images are naturally a very important portion of our business. Our old process was  cumbersome and made it incredibly difficult and time consuming to add a new seller account and watermark existing product images. Here is a brief description of the old process:

1) User uploads SKU images to a FTP server

2) User selects which watermarks to apply to these images and processes them

3) Watermarked SKU images are uploaded to a CDN container for their appropriate seller.

This process worked fine for a while… until we started to grow. Adding a new seller account meant running a script for days to apply a new watermark to pre-existing images and upload them to a new CDN container.


The Redesign:

I went into this redesign with the main goal of creating the most efficient and simple solution possible. The server needed to watermark images on the fly, cache watermarked copies of images, and make it easy for us to add new seller accounts. The immediate solution that jumped out at me was some sort of system that cached images then served them using Apache with a Squid transparent proxy in front of the Apache server. I use Squid on my home router as a transparent proxy and I love it but I knew I could make things much simpler. After receiving suggestions from friends and doing some research on it’s ability to serve static files I ended up choosing Nginx to serve as both my proxy and web server in this solution. When it came to choosing a language the obvious choice was NodeJS with the Express framework. Node’s large ecosystem of packages would help get the job done very quickly and I have a good level of familiarity with Javascript. Node’s job in this is relatively simple. Grab the original image, watermark the image, and save it in a cache folder for the appropriate seller.


The System:


Nginx does a lot of the heavy lifting here. I will attempt to explain this as clear as possible, but for security and IP reasons I cannot get into the specifics of domains or anything like that. Basically when Nginx receives a request it extracts a few things the seller, the last three digits of the SKU, and the requested image. It then uses the ‘try files’ directive to attempt to locate a cached copy of the file within the seller’s virtual host from a folder/bucket based on the last three digits of the SKU. If this image is not found Nginx then takes the extracted information and passes it to the Node service that then watermarks the image, saves it to the appropriate bucket within the seller’s virtual host and serves it back to the user. The below diagram can help illustrate the whole process. 

This is basically it, very few components to the system. The only other piece to the system is a simple bash script which runs every two minutes to detect new images and clear the cache. For the Node piece I utilized Express JS. The actual watermarking is being done by a Node GD port called Easy GD. The NPM page for Easy-GD contains sample code that shows exactly how to overlay a watermark on an image. The cache buckets are created by Node on the fly if they do not exist, and the system also handles thumbnails. Monit and Upstart are being used to keep the node service running and provide alerts in case of failure. This tutorial, helped in setting that up, although it was relatively simple.



How has it been running?

The system has been live for about 5 days now. It runs on dedicated hardware. Here are the specs:

4 Cores

4 Gb Ram

On a normal day it appears to have a RAM footprint of around 1.5Gb. Under peak load I have seen things top out at around 3.5Gb but usually for no longer than a few minutes. CPU usage is incredibly low. When watermarking images, usage will spike to about 30% and then quickly drop back down.



Overall our users seem happy with the new simpler process (They just have to upload photos now), and the system has been running incredibly well. Nginx and Node are a great combination for something like this.


Leave comments

Your email address will not be published.