How to optimize ALL images in ubuntu / linux server everyday!

So maybe you have a server, maybe it is running wordpress, and maybe you want to get your images compressed. There are various tools and ways to accomplish this, many of them are paid for, but you can very easily do this automatically yourself and with incredibly results!

ImageMagick is an old tool that has withstood the test of time, it provides efficient results and optimizes images to an incredible extent. So to provide the best web experience I could, one of the first things I looked into for performance was just literally ensuring images are optimized in a generic way that works no matter what. I have further optimizations that I set up on top of this, but this is a good way to get the ball rolling.

There are numerous tutorials on installing ImageMagick on your distro of choice, but for Ubuntu here is what you will need.

sudo apt update
sudo apt install imagemagick

If you are using php and need it accessible via php you may need to do the following:

sudo apt install php-imagick
sudo service apache2 restart

In my case, php 8.1 is being released, so when I tried to install it kept trying to install as version 8.1 instead of 8.0 which is the version I was running, so in that case you may need to specifically call out your version like the following:

sudo apt install php8.0-imagick
sudo service apache2 restart

You can verify that this has been installed and is running by using the following command:

php -m | grep imagick

If you see “imagick” on your terminal you are in good shape, and it should also show up in phpinfo.

So how do I make my server update images on its own?

First we are going to create a script that will update all of our images for us. If you do not understand shell scripting then simply follow this and it should work without any problems, but if you do understand it, then feel free to edit this as necessary. So let’s create a new file called imageoptimizer.sh and then edit it.

sudo touch /usr/local/bin/imageoptimizer.sh
sudo nano /usr/local/bin/imageoptimizer.sh

Now that we created our file, let’s take the below code and paste it in. This is assuming that you want to optimize ALL .jpg and .png images in any folders inside of the /var/www/ directory. This is particularly helpful if you have numerous virtual hosts that may be located at locations like /var/www/wordpress, /var/www/example, and /var/www/example2.

#!/bin/bash
# set initial files optimized to 0
FilesOptimized=0

#change IFS to handle file names with space!
IFS=$'\n'

# setup our current time
CURTIME=$(date +%s)
OLDTIME=82800
NOW="$(date +'%d/%m/%Y')"

#start from home directory then find our web files usually in /var/www/
cd
list=`find /var/www -type d`
for directory in $list; do
cd $directory

# get list of jpg files
jpglist=`ls | grep "\.jpg$|\.jpeg$"`
for file in $jpglist; do
FILETIME=$(stat $file -c %Y)
TIMEDIFF=$(expr $CURTIME - $FILETIME)

# check if we have any new jpg files that need to be optimized
if [ $TIMEDIFF -lt $OLDTIME ]; then
mogrify -format jpg -filter Triangle -define filter:support=2 -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -interlace none -colorspace sRGB $file
((FilesOptimized+=1))
fi
done

# get list of png files
pnglist=`ls | grep "\.png$"`
for file in $pnglist; do
FILETIME=$(stat $file -c %Y)
TIMEDIFF=$(expr $CURTIME - $FILETIME)

# check if we have any new png files that need to be optimized
if [ $TIMEDIFF -lt $OLDTIME ]; then
mogrify -format png -filter Triangle -define filter:support=2 -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB $file
((FilesOptimized+=1))
fi
done

# let's wrap things up, print out the files that were optimized, and send an update to our logs to keep track of how many files were updated
cd
done
echo "I optimized $FilesOptimized images for you today"
echo "$NOW - $FilesOptimized files optimized" >> /var/log/imagesoptimized.log

So now we have a file that will automatically update all of our images inside of /var/www/. Now all that we need to do is set it up to run in a cron job. So let’s enter into a crontab and set that up. It is important to use sudo when opening the crontab, and you need to run this file with sudo privileges!

sudo crontab -e

Inside of your crontab go to the very bottom and input the following line:

45 2 * * * sh /usr/local/bin/imageoptimizer.sh

That’s it! Now your image files will be automatically optimized everyday at 2:45am. It is important to note that optimizing these images is CPU intensive, it can take a while if you are optimizing thousands of images, so make sure the first time you run it, that it has time to do its work without having other resource intensive tasks happening. This checks the last time a file was modified and will ONLY optimize it if it is less than one day old. This is important, because over time optimizing an image over and over will degrade the quality and cause problems. Also this cuts down on how long this script takes to run, and it will simply optimize new images and not re-optimize old images.

So give it a few days, and then check to see how many images are being optimized by running the following command:

tail /var/log/imagesoptimized.log

November 19, 2021