How to Deploy ImgProxy - Process, Resize, Convert Images on the Fly

Updated on June 14, 2024
How to Deploy ImgProxy - Process, Resize, Convert Images on the Fly header image

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:

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.

  1. Add the libvips package to your APT repository sources using the dhor/myway PPA.

    console
    $ sudo add-apt-repository ppa:dhor/myway
    
  2. Update the server package index.

    console
    $ sudo apt update
    
  3. Install the libvips dependency package.

    console
    $ sudo apt install libvips-dev -y
    
  4. Install the latest Go version using Snap.

    console
    $ sudo snap install --classic --channel=latest/stable go
    
  5. 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.
  6. Switch to the imgproxy directory.

    console
    $ cd imgproxy
    
  7. 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. The go 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
  8. Create a new ImgProxy environment configuration file in the /usr/local/bin directory.

    console
    $ sudo touch /usr/local/bin/imgproxy.env
    
  9. Open the file using a text editor like Nano.

    console
    $ sudo nano /usr/local/bin/imgproxy.env
    
  10. Add the following environment configurations to the file.

    ini
    IMGPROXY_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 port 8080.
    • 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 has 4 vCPUs, set the maximum workers value to 8.
    • 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 URL https://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 value 1 enables watermarking on the server.
  11. 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.

  12. Switch to your user home directory.

    console
    $ cd
    
  13. 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.

  1. Create a new ImgProxy system user account without a home directory, login or shell privileges.

    console
    $ sudo useradd -r -s /bin/false imgproxy
    
  2. Grant the user full privileges to the ImgProxy binary file /usr/local/bin/imgproxy.

    console
    $ sudo chown imgproxy:imgproxy /usr/local/bin/imgproxy
    
  3. 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
    
  4. Create a new systemd unit file.

    console
    $ sudo nano /etc/systemd/system/imgproxy.service
    
  5. 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 the IMGPROXY_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 format pretty defined in your environment configuration.

  6. Create the ImgProxy application logs directory.

    console
    $ sudo mkdir -p /var/log/imgproxy/
    
  7. Grant the ImgProxy user full privileges to the directory.

    console
    $ sudo chown -R imgproxy:imgproxy /var/log/imgproxy
    
  8. Restart the systemd daemon to enable the new ImgProxy service on your server.

    console
    $ sudo systemctl daemon-reload
    
  9. Enable ImgProxy to start at boot time.

    console
    $ sudo systemctl enable imgproxy
    
  10. Start the ImgProxy system service.

    console
    $ sudo systemctl start imgproxy
    
  11. 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.

  1. Install Nginx on your server.

    console
    $ sudo apt install nginx -y
    
  2. Create a new Nginx configuration file. For example, imgproxy.example.com.

    console
    $ sudo nano /etc/nginx/sites-available/imgproxy.example.com
    
  3. Add the following configurations to the file.

    nginx
    server {
        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 domain imgproxy.example.com.

  4. Activate the configuration file.

    console
    $ sudo ln -s /etc/nginx/sites-available/imgproxy.example.com /etc/nginx/sites-enabled/
    
  5. Test Nginx for configuration errors.

    console
    $ sudo nginx -t
    
  6. Restart Nginx to apply the new configuration changes.

    console
    $ sudo systemctl restart nginx
    
  7. Allow the HTTP port 80 through the default UFW firewall.

    console
    $ sudo ufw allow 80 comment 'ImgProxy Http'
    
  8. 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.

  1. Install the Certbot plugin for Nginx.

    console
    $ sudo apt install python3-certbot-nginx -y
    
  2. 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
    
  3. Restart Nginx to apply the configuration changes.

    console
    $ sudo systemctl restart nginx
    
  4. Allow the HTTPS port 443 through the firewall.

    console
    $ sudo ufw allow 443 comment 'ImgProxy Https'
    
  5. 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.

  1. 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.

    The Default ImgProxy webpage

  2. 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.

  3. Press Enter to load the web page and verify that ImgProxy displays the image with your default processing settings.

    View the Unprocessed ImgProxy Image

  4. 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 a fill type to keep the original image aspect ratio while resizing the image to the new 800*800 resolution.

  5. Press Enter to view the processed image and verify that the image is resized to the new resolution.

    View the resized image

  6. Right-click the resized image and select Inspect from the list of browser options to convert the image to a new format.

  7. Navigate to the Network tab and reload your ImgProxy URL to view the request details.

  8. Verify that the processed image name is available in the Name column. Then, click the image name to view the ImgProxy request data.

    View ImgProxy Network Requests

  9. Find Content-Type in the Response Headers section and verify the image file format depending on your source image. For example, image/jpeg.

  10. 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
  11. Monitor the processing data in your Network tab and verify that the image displays in your browser.

  12. 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.

    View the ImgProxy processed image data

  13. Right-click the image and select Save Image As from your browser options to verify that you can save the new processed image format.

  14. 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 while ce positions the image to the center, and 2:2 sets the x|y offsets.

  15. Press Enter to view the new watermarked image in your browser.

    View the Watermarked Image

    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.

  1. Generate a new random 32-byte key using OpenSSL.

    console
    $ openssl rand -hex 32
    

    Output:

    5e6bd8d49b263182c252c89d8401502ddb81ecc2a20ece77b8e04680663da0f6
  2. Generate a new 16-byte salt to use with the key.

    console
    $ openssl rand -hex 16
    

    Output:

    8ef6be20fe6b1c888289718e8c0f40f3
  3. Open the ImgProxy environment configuration file.

    console
    $ sudo nano /usr/local/bin/imgproxy.env
    
  4. Add the following key/salt pair configurations at the end of the file. Replace the random hex-encoded values with your generated values.

    ini
    IMGPROXY_KEY=5e6bd8d49b263182c252c89d8401502ddb81ecc2a20ece77b8e04680663da0f6
    IMGPROXY_SALT=8ef6be20fe6b1c888289718e8c0f40f3
    

    Save and close the file.

    The above key/salt pair enables ImgProxy URL signing on every server request.

  5. Create a new bash script to generate a valid signature using your key/salt pair.

    console
    $ nano improxy-signing.sh
    
  6. 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 URL https://images.pexels.com/photos/72594/japan-train-railroad-railway-72594.jpeg.

  7. 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.

  8. Restart ImgProxy to apply your new configuration changes.

    console
    $ sudo systemctl restart imgproxy
    
  9. 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
  10. Verify that ImgProxy displays the processed image in your web browser.

    View the ImgProxy Signed URL image

    You have successfully protected ImgProxy with URL signing on your server. However, you cannot use the same signature with multiple source URLs.

  11. 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 a Forbidden 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"
  12. 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
    
  13. Add your trusted signature using the IMGPROXY_TRUSTED_SIGNATURES option at the end of the file. Separate multiple signatures with,.

    ini
    IMGPROXY_TRUSTED_SIGNATURES=KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0
    

    Save and close the file.

  14. Restart ImgProxy to apply the new configuration changes.

    console
    $ sudo systemctl restart imgproxy
    
  15. 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
  16. Verify that the processed ImgProxy image displays in your web browser.

    View a processed ImgProxy Image with a signature

    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.

  1. Create a new Vultr Object Storage bucket such as imgproxy-data.

  2. 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.

    Save a new Image to Vultr Object Storage

  3. Open the ImgProxy configuration file.

    console
    $ sudo nano /usr/local/bin/imgproxy.env
    
  4. Add the following configuration to enable S3 storage sources on your server. Replace all example values with your actual Vultr Object Storage details.

    ini
    IMGPROXY_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 storage s3:// URI format.

  5. 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
  6. Create a new signed ImgProxy URL request using the image.jpeg file in your Vultr Object Storage bucket. Then, rotate it by 90 degrees and convert it to a new format such as png.

    console
    https://improxy.example.com/KNk-UQ1Cm1bpUnTsNlSEa-q35YwoMYdYNoVUkF1IvP0/plain/s3://imgproxy-data/image1.jpeg@png
    
  7. Verify that your processed image displays in your web browser.

    View an ImgProxy Processed Object Storage Image

    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.