Back to guides

Capture screenshots through Nginx

Last updated december 01, 2022

This guide walks you through a simple and secure setup to capture screenshots through nginx. This guide is particularly useful if you want to:

  • include screenshot URLs directly in img tags
  • serve screenshots from your own domain
  • hide your access key from end users

1. Proxy ApiFlash & hide your access key

Add this location block to your nginx configuration (don't forget to replace your access key).

1
2
3
4
location /screenshot {
    set $args $args&access_key=YOUR_ACCESS_KEY_HERE
    proxy_pass https://api.apiflash.com/v1/urltoimage;
}

This block is proxying each /screenshot request to ApiFlash's screenshot API endpoint. Using the set directive, your access key is directly added by nginx to the query string parameters. As a result your end users cannot get your access key. Screenshots are served from your own domain and you can directly include screenshot URLs into img tags.

1
<img src="https://yourdomain.com/screenshot?url=https://ok.com"/>

Even though this setup is useful already, an end user could use your /screenshot endpoint to capture arbitrary screenshots.

2. Restrict the URLs that can be captured

Another layer of security can be added with an if block to restrict the allowed target URLs.

1
2
3
4
5
6
7
8
9
location /screenshot {

    if ( $arg_url !~* https:\/\/somedomain.com ){
        return 403;
    }

    set $args $args&access_key=YOUR_ACCESS_KEY_HERE
    proxy_pass https://api.apiflash.com/v1/urltoimage;
}

This if block ensures nginx returns an HTTP 403 Forbidden error when URLs don't match the specified regular expression. In particular, in the previous example, only URLs that begin with https://somedomain.com can be captured as screenshots.

End users cannot capture arbitrary screenshots with this setup. But they can still make a lot of HTTP requests to your /screenshot endpoint and potentially consume your subscription quota as a result.

3. Rate limiting your screenshot endpoint

Rate limiting your endpoint is a good way to ensure that end users cannot aggressively call the /screenshot endpoint. Depending on your use case and the volume you're expecting, you might want to adjust the rate limit and the burst size.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
limit_req_zone $binary_remote_addr zone=rate_limit:50m rate=1r/s;

server {

    # The rest of your server configuration...

    location /screenshot {

        limit_req zone=rate_limit burst=10;

        if ( $arg_url !~* https:\/\/google.com ){
            return 403;
        }

        set $args $args&access_key=YOUR_ACCESS_KEY_HERE;
        proxy_pass https://api.apiflash.com/v1/urltoimage;
    }
}

In the previous example, requests are rate limited based on IP address and are limited to 1 request per second. With a burst size of 10, up to 10 requests can be queued per IP address without being dropped by nginx.

4. Public pages & screenshot caching

On public pages with high traffic, if you use the /screenshot endpoint directly in img tags, this will result in a lot of unnecessary requests to ApiFlash. To ensure that ApiFlash's rate limit is not exceeded, you need to configure nginx to cache the generated screenshots.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
proxy_cache_path /screenshot_cache levels=1:2 keys_zone=screenshot_cache:10m
                 max_size=2g inactive=86400s use_temp_path=off;

limit_req_zone $binary_remote_addr zone=rate_limit:50m rate=1r/s;

server {

    # The rest of your server configuration...

    location /screenshot {

        limit_req zone=rate_limit burst=10;

        if ( $arg_url !~* https:\/\/google.com ){
            return 403;
        }

        set $args $args&access_key=YOUR_ACCESS_KEY_HERE;
        proxy_pass https://api.apiflash.com/v1/urltoimage;

        proxy_cache screenshot_cache;
        proxy_cache_lock on;
        proxy_cache_key $request_uri$request_body;
        proxy_cache_bypass $arg_fresh;
        proxy_ignore_headers Vary Set-Cookie;
    }
}

The previous configuration is caching up to 2GB of screenshots for 24 hours in the /screenshot_cache directory. Various nginx proxy directives are used to fine tune the caching behavior. More information about those directives can be found in the nginx documentation .