How to Deploy ImgProxy - Process, Resize, Convert Images on the Fly
Introduction
Imgproxy is an open-source image-processing application that lets you process, convert, and resize images using URL requests. Imgproxy acts as an image processor that enhances source images with better resolutions and settings. It's compatible with modern web applications that may require standardized image formats or sizes to improve performance and user experience.
Imgproxy integrates with services such as CDNs, load balancers, and proxy servers to cache and deliver images on your web applications as an intermediate service. This article explains how to deploy ImgProxy on a Ubuntu server to process, resize, and convert images on the fly.
Prerequisites
Before you begin:
- Deploy a Ubuntu server instance on Vultr.
- Create a new domain A record that points to the ImgProxy server IP. For example,
imgproxy.example.com
. - Access the server using SSH as a non-root user with sudo privileges.
- Update the server.
Install ImgProxy
ImgProxy uses the libvips
image processing library to process and deliver images from source files on your server. You can install ImgProxy using Docker or build the application from source using Go. Follow the steps below to install ImgProxy using the application source code and enable all necessary dependencies to optimize your server performance.
Add the
libvips
package to your APT repository sources using thedhor/myway
PPA.console$ sudo add-apt-repository ppa:dhor/myway
Update the server package index.
console$ sudo apt update
Install the
libvips
dependency package.console$ sudo apt install libvips-dev -y
Install the latest Go version using Snap.
console$ sudo snap install --classic --channel=latest/stable go
Clone the official ImgProxy GitHub repository using Git.
console$ git clone https://github.com/imgproxy/imgproxy.git
The above command creates a new
imgproxy
directory on your server with all necessary application files. When the process is successful, your output should appear like the one below.remote: Compressing objects: 100% (578/578), done. remote: Total 15968 (delta 3055), reused 3088 (delta 2875), pack-reused 12499 Receiving objects: 100% (15968/15968), 36.14 MiB | 19.91 MiB/s, done. Resolving deltas: 100% (7920/7920), done.
Switch to the
imgproxy
directory.console$ cd imgproxy
Build and compile the ImgProxy binary using Go.
console$ sudo CGO_LDFLAGS_ALLOW="-s|-w" go build -o /usr/local/bin/imgproxy
The above command compiles a new ImgProxy binary on your server using the
"-s|-w"
linker flags that optimize the binary file using Go. Thego build
process outputs the resultant binary file to the/usr/local/bin/
directory to enable system-wide access. When the build process is complete, your output should be similar to the one below.go: downloading github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 go: downloading github.com/go-openapi/swag v0.23.0 go: downloading github.com/go-openapi/jsonreference v0.21.0 go: downloading github.com/emicklei/go-restful/v3 v3.12.0 go: downloading github.com/mailru/easyjson v0.7.7 go: downloading github.com/go-openapi/jsonpointer v0.21.0 go: downloading github.com/josharian/intern v1.0.0
Create a new ImgProxy environment configuration file in the
/usr/local/bin
directory.console$ sudo touch /usr/local/bin/imgproxy.env
Open the file using a text editor like Nano.
console$ sudo nano /usr/local/bin/imgproxy.env
Add the following environment configurations to the file.
iniIMGPROXY_BIND=:8080 IMGPROXY_NETWORK=tcp IMGPROXY_READ_TIMEOUT=10 IMGPROXY_WRITE_TIMEOUT=10 IMGPROXY_WORKERS=2 IMGPROXY_REQUESTS_QUEUE_SIZE=0 IMGPROXY_QUALITY=100 IMGPROXY_PREFERRED_FORMATS=webp,jpeg,png,gif,avif IMGPROXY_LOG_FORMAT="pretty" IMGPROXY_LOG_LEVEL="INFO" IMGPROXY_WATERMARK_URL=https://www.vultr.com/_images/og/default.png IMGPROXY_WATERMARK_OPACITY=1
Save and close the file.
The above ImgProxy environment configuration enables the application to run on your server with specific runtime options. Within the configuration:
IMGPROXY_BIND
: Enables ImgProxy to run on a specific port on your server. By default, ImgProxy uses the TCP port8080
.IMGPROXY_NETWORK
: Sets the ImgProxy network protocol to use with the port.IMGPROXY_READ_TIMEOUT
: Sets the maximum duration in seconds to read source image requests.IMGPROXY_WRITE_TIMEOUT
: The maximum duration in seconds to write a response including the body.IMGPROXY_WORKERS
: The maximum number of images ImgProxy can process on your server. The value is calculated using the number of CPU cores * 2. For example, if your server has4
vCPUs, set the maximum workers value to8
.IMGPROXY_REQUESTS_QUEUE_SIZE
: The maximum number of image processing requests to allow in a queue.0
sets the queue size to unlimited.IMGPROXY_QUALITY
: Sets the maximum processed image quality.IMGPROXY_PREFERRED_FORMATS
: Sets the default image formats to convert images on your server.IMGPROXY_LOG_FORMAT
: Sets the ImgProxy log messages format.IMGPROXY_LOG_LEVEL
: Enables the type of ImgProxy log messages.IMGPROXY_WATERMARK
: Enables watermarking of processed images on the server. The URLhttps://www.vultr.com/_images/og/default.pnghttps://www.vultr.com/_images/og/default.png
loads a Vultr promotional banner to use as the watermark file in this article while the opacity value1
enables watermarking on the server.
Create a new
IMGPROXY_ENV_LOCAL_FILE_PATH
environment variable to set the location of your ImgProxy configuration.console$ export IMGPROXY_ENV_LOCAL_FILE_PATH=/usr/local/bin/imgproxy.env
ImgProxy uses the above variable to read all environment configuration options while running on the server.
Switch to your user home directory.
console$ cd
Run the
imgproxy
command to verify that ImgProxy is available on your server.console$ imgproxy
Output:
WARNING [2024-05-28T00:40:42Z] No keys defined, so signature checking is disabled WARNING [2024-05-28T00:40:42Z] No salts defined, so signature checking is disabled INFO [2024-05-28T00:40:42Z] Starting server at :8080
Press Ctrl + C to cancel the ImgProxy process and configure your server to run the application as a system service.
Set Up ImgProxy as a System Service
ImgProxy is installed and available in the /usr/local/bin/
directory on your server. You can run the imgproxy
command to start the application, but all changes are lost when the server session ends. Follow the steps below to set up ImgProxy as a system service to manage the application processes and monitor events such as error logs on your server.
Create a new ImgProxy system user account without a home directory, login or shell privileges.
console$ sudo useradd -r -s /bin/false imgproxy
Grant the user full privileges to the ImgProxy binary file
/usr/local/bin/imgproxy
.console$ sudo chown imgproxy:imgproxy /usr/local/bin/imgproxy
Grant the user ownership privileges to the environment configuration file
/usr/local/bin/imgproxy.env
.console$ sudo chown imgproxy:imgproxy /usr/local/bin/imgproxy.env
Create a new systemd unit file.
console$ sudo nano /etc/systemd/system/imgproxy.service
Add the following configurations to the file.
systemd[Unit] Description=IMGProxy Image Processing Application After=network.target [Service] Environment="IMGPROXY_ENV_LOCAL_FILE_PATH=/usr/local/bin/imgproxy.env" ExecStart=/usr/local/bin/imgproxy User=imgproxy Group=imgproxy Restart=always StandardOutput=append:/var/log/imgproxy/access.log [Install] WantedBy=multi-user.target
Save and close the file.
The above configuration creates a new ImgProxy service owned by the
imgproxy
user and group you created earlier. The service uses theIMGPROXY_ENV_LOCAL_FILE_PATH=
variable to set your ImgProxy environment configuration. In addition, all application logs are written to the/var/log/imgproxy/
directory using the human-readable formatpretty
defined in your environment configuration.Create the ImgProxy application logs directory.
console$ sudo mkdir -p /var/log/imgproxy/
Grant the ImgProxy user full privileges to the directory.
console$ sudo chown -R imgproxy:imgproxy /var/log/imgproxy
Restart the systemd daemon to enable the new ImgProxy service on your server.
console$ sudo systemctl daemon-reload
Enable ImgProxy to start at boot time.
console$ sudo systemctl enable imgproxy
Start the ImgProxy system service.
console$ sudo systemctl start imgproxy
View the ImgProxy system service status and verify that it's actively running on your server.
console$ sudo systemctl status imgproxy
Your output should be similar to the one below.
● imgproxy.service - IMGProxy Image Processing Application Loaded: loaded (/etc/systemd/system/imgproxy.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2024-05-28 00:49:40 UTC; 6s ago Main PID: 164531 (imgproxy) Tasks: 5 (limit: 1005) Memory: 19.8M CPU: 119ms CGroup: /system.slice/imgproxy.service └─164531 /usr/local/bin/imgproxy
Set Up Nginx as a Reverse Proxy to Access ImgProxy
ImgProxy runs on the server port 8080
defined in your environment configuration. Install and configure Nginx as a reverse proxy to enable secure access to the ImgProxy without exposing the main application port on your server. Follow the steps below to create a new Nginx reverse proxy configuration to accept connections using your domain name and forward all requests to the backend ImgProxy application port.
Install Nginx on your server.
console$ sudo apt install nginx -y
Create a new Nginx configuration file. For example,
imgproxy.example.com
.console$ sudo nano /etc/nginx/sites-available/imgproxy.example.com
Add the following configurations to the file.
nginxserver { listen 80; server_name imgproxy.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } }
Save and close the file.
The above Nginx configuration creates a new reverse proxy connection to the ImgProxy application port
8080
and accepts HTTP connections using your domainimgproxy.example.com
.Activate the configuration file.
console$ sudo ln -s /etc/nginx/sites-available/imgproxy.example.com /etc/nginx/sites-enabled/
Test Nginx for configuration errors.
console$ sudo nginx -t
Restart Nginx to apply the new configuration changes.
console$ sudo systemctl restart nginx
Allow the HTTP port
80
through the default UFW firewall.console$ sudo ufw allow 80 comment 'ImgProxy Http'
Restart the firewall to apply the new changes.
console$ sudo ufw reload
Generate Trusted SSL Certificates to Encrypt ImgProxy Requests
ImgProxy supports extended security features such as URL signing to protect and limit requests on your server. Generate trusted SSL certificates to encrypt connections between all requesting clients and the ImgProxy server. Follow the steps below to install the Certbot Let's Encrypt client and generate new SSL certificates to use on the server.
Install the Certbot plugin for Nginx.
console$ sudo apt install python3-certbot-nginx -y
Generate new Let's Encrypt SSL certificates using your domain name. Replace
imgproxy.example.com
with your actual domain.console$ sudo certbot --nginx -d imgproxy.example.com --agree-tos
Restart Nginx to apply the configuration changes.
console$ sudo systemctl restart nginx
Allow the HTTPS port
443
through the firewall.console$ sudo ufw allow 443 comment 'ImgProxy Https'
Restart UFW to apply the configuration changes.
console$ sudo ufw reload
Access ImgProxy to Process and Modify Images
ImgProxy accepts source images using HTTP GET
requests and delivers processed images as a response. The application uses the following URL request format to load and process images on your server.
```
https://imgproxy-url/[processing-options]/source-image-url
```
ImgProxy supports plain, encoded, and encrypted source URL formats as valid request types. Follow the steps below to process sample source images using the plain URL format on your server.
Access your ImgProxy domain using a web browser such as Firefox.
https://imgproxy.example.com
Verify that the default ImgProxy web page displays in your browser.
In a new browser tab, load a sample source image using the plain URL format. For example, load a sample image of a train from Pexels using the direct URL:
https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
https://imgproxy.example.com/insecure/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
The above URL loads the source image using the insecure plain URL format. It’s recommended to use encrypted formats when working with single images to tighten your server security. Use the
plain
format when working with multiple image files to simultaneously process requests on your server.Press Enter to load the web page and verify that ImgProxy displays the image with your default processing settings.
Modify the URL with a new image processing value to resize the image to a resolution such as
800*800
.https://imgproxy.example.com/insecure/rs:fill:800:800/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
The above
rs
resize option modifies the source image with afill
type to keep the original image aspect ratio while resizing the image to the new800*800
resolution.Press Enter to view the processed image and verify that the image is resized to the new resolution.
Right-click the resized image and select Inspect from the list of browser options to convert the image to a new format.
Navigate to the Network tab and reload your ImgProxy URL to view the request details.
Verify that the processed image name is available in the Name column. Then, click the image name to view the ImgProxy request data.
Find Content-Type in the Response Headers section and verify the image file format depending on your source image. For example,
image/jpeg
.Keep the Network tab open and modify your ImgProxy URL request to include a new image format using the
@
option. For example,@webp
to convert and process the image to the Webp format.https://imgproxy.example.com/insecure/rs:fill:800:800/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg@webp
Monitor the processing data in your Network tab and verify that the image displays in your browser.
Click the image name in your Network tab and verify that the Content-Type field in your Response Headers changes to your new format. For example,
/image/webp
.Right-click the image and select
Save Image As
from your browser options to verify that you can save the new processed image format.Modify your ImgProxy URL again and include the
/watermark:1:ce:2:2/
processing option to test the ImgProxy watermarking option on your server.https://imgproxy.example.com/insecure/rs:fill:800:800/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
The above URL request watermarks the processed images using the source watermark URL in your ImgProxy configuration. The value
1
enables the watermark whilece
positions the image to the center, and2:2
sets thex|y
offsets.Press Enter to view the new watermarked image in your browser.
ImgProxy offers multiple processing options to modify source images on your server. Visit the ImgProxy
processing options
documentation to view all supported functions.
Protect ImgProxy with URL Signing
ImgProxy protects your server using key/salt pairs to enable URL signing on all server requests. When a valid signature is not attached to an ImgProxy URL request, it’s not processed by the server which safeguards your server from unpermitted client requests. Follow the steps below to create a new key/salt pair and generate a URL signature to protect your ImgProxy server requests.
Generate a new random 32-byte
key
using OpenSSL.console$ openssl rand -hex 32
Output:
5e6bd8d49b263182c252c89d8401502ddb81ecc2a20ece77b8e04680663da0f6
Generate a new 16-byte
salt
to use with the key.console$ openssl rand -hex 16
Output:
8ef6be20fe6b1c888289718e8c0f40f3
Open the ImgProxy environment configuration file.
console$ sudo nano /usr/local/bin/imgproxy.env
Add the following key/salt pair configurations at the end of the file. Replace the random hex-encoded values with your generated values.
iniIMGPROXY_KEY=5e6bd8d49b263182c252c89d8401502ddb81ecc2a20ece77b8e04680663da0f6 IMGPROXY_SALT=8ef6be20fe6b1c888289718e8c0f40f3
Save and close the file.
The above key/salt pair enables ImgProxy URL signing on every server request.
Create a new bash script to generate a valid signature using your key/salt pair.
console$ nano improxy-signing.sh
Add the following configurations to the file.
ini#!/bin/bash # Generate a new ImgProxy signature based on your source image URL such as `https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg`. Replace this value with a source image on your web app domain such as: https://example.com/wp-content/image.png KEY_VALUE="5e6bd8d49b263182c252c89d8401502ddb81ecc2a20ece77b8e04680663da0f6" SALT_VALUE="8ef6be20fe6b1c888289718e8c0f40f3" KEY=$(echo -n "$KEY_VALUE" | xxd -r -p) SALT=$(echo -n "$SALT_VALUE" | xxd -r -p) URL_PATH="/rs:fill:800:800/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg" IMGPROXY_URL="https://imgproxy.example.com/" DATA="$SALT$URL_PATH" SIGNATURE=$(echo -n "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64 -w 0 | tr '+/' '-_' | tr -d '=') echo "The Signature based on your key/salt pair is: $SIGNATURE \n" echo "The Signed ImgProxy URL is: $IMGPROXY_URL$SIGNATURE$URL_PATH"
Save and close the file.
The above script calculates a new HMAC digest using SHA256 and your
salt
value. In the above configuration, a new signature is generated for the source image URLhttps://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
.Run the script to generate a new signed ImgProxy URL.
console$ bash improxy-signing.sh
Output:
The Signed ImgProxy URL is: https://imgproxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/rs:fill:800:800/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
Copy the generated signed URL to use with your ImgProxy requests.
Restart ImgProxy to apply your new configuration changes.
console$ sudo systemctl restart imgproxy
Access the generated ImgProxy URL in your web browser to securely access your processed image.
https://improxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
Verify that ImgProxy displays the processed image in your web browser.
You have successfully protected ImgProxy with URL signing on your server. However, you cannot use the same signature with multiple source URLs.
Create a new ImgProxy request using your valid signature with a different processing option such as
blur
to test the access limits.https://improxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/resizing_type:fill/blur:10/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg
Verify that ImgProxy returns a
439
error with aForbidden
message and the following log entry.WARNING [2024-05-26T13:33:00Z] Completed in 101.015µs KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/resizing_type:fill/blur:10/watermark:1:ce:2:2/plain/https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg@webp request_id=pq-l1OajkhkU684GVP_nC method=GET status=403 client_ip=41.190.134.12 error="Invalid signature"
Add the signature to your ImgProxy environment configuration to enable access and usage with multiple source image URLs.
console$ sudo nano /usr/local/bin/imgproxy.env
Add your trusted signature using the
IMGPROXY_TRUSTED_SIGNATURES
option at the end of the file. Separate multiple signatures with,
.iniIMGPROXY_TRUSTED_SIGNATURES=KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0
Save and close the file.
Restart ImgProxy to apply the new configuration changes.
console$ sudo systemctl restart imgproxy
Create a new ImgProxy request with a different source image URL such as
https://i.imgur.com/iPsORz6.jpeg
and convert it to a new format such as.png
to test your new signature limits.https://improxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/plain/https://i.imgur.com/iPsORz6.jpeg@png
Verify that the processed ImgProxy image displays in your web browser.
ImgProxy accepts all requests on your server without limiting access to the image URL. A trusted signature enables ImgProxy to ignore the key/salt pair in your configuration and process images with any included options. This enables ImgProxy integration with dynamic web application frameworks such as WordPress that use multiple image names and requests.
Process Images using Vultr Object Storage and ImgProxy
ImgProxy supports multiple image sources including local files, URLs, and S3-compatible storage. Follow the steps below to configure ImgProxy to process images using Vultr Object Storage.
Create a new Vultr Object Storage bucket such as
imgproxy-data
.Download the example image you applied earlier and upload it to your bucket using a tool such as S3 Browser. Then, save the image as
image1.jpeg
.Open the ImgProxy configuration file.
console$ sudo nano /usr/local/bin/imgproxy.env
Add the following configuration to enable S3 storage sources on your server. Replace all example values with your actual Vultr Object Storage details.
iniIMGPROXY_USE_S3=true IMGPROXY_S3_ENDPOINT=ewr1.vultrobjects.com AWS_ACCESS_KEY_ID=your-access-key AWS_SECRET_ACCESS_KEY=your-secret-key
Save and close the file.
The above configuration enables ImgProxy to process images from your
imgproxy-data
bucket. To access the processed images, you must replace your source URL format with the object storages3://
URI format.ImgProxy uses the following URL format to process images using a Vultr Object Storage bucket.
https://IMGPROXY-URL/PROCESSING-OPTONS/s3://bucket_name/file-name
Create a new signed ImgProxy URL request using the
image.jpeg
file in your Vultr Object Storage bucket. Then, rotate it by90
degrees and convert it to a new format such aspng
.consolehttps://improxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/plain/s3://imgproxy-data/image1.jpeg@png
Verify that your processed image displays in your web browser.
If your web application uploads and serves image files using Vultr Object Storage, configure your web server to securely serve the processed files using ImgProxy to optimize your web application performance.
Conclusion
You have successfully deployed ImgProxy and delivered processed images on the fly on your server. ImgProxy is a processing tool that integrates with your web application to serve optimized images with next-generation formats such as .webp
and .avif
. Set up monitoring applications such as Prometheus and Grafana to enable continuous monitoring of image processing requests on your server. For more information, visit the ImgProxy documentation.