• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..26-Oct-2021-

third_party/http/H26-Oct-2021-167128

.gitignoreH A D26-Oct-2021188 1311

DockerfileH A D26-Oct-2021607 2918

LICENSEH A D26-Oct-20219.9 KiB179150

README.mdH A D26-Oct-202118 KiB369259

cache.goH A D26-Oct-20211.3 KiB3811

data.goH A D26-Oct-202112.8 KiB381198

go.modH A D26-Oct-20212.4 KiB5246

go.sumH A D26-Oct-202130.2 KiB311310

imageproxy.goH A D26-Oct-202113.1 KiB484323

metrics.goH A D26-Oct-20211.1 KiB3733

transform.goH A D26-Oct-20217.6 KiB325237

README.md

1# imageproxy
2
3[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/willnorris.com/go/imageproxy)
4[![Test Status](https://github.com/willnorris/imageproxy/workflows/tests/badge.svg)](https://github.com/willnorris/imageproxy/actions?query=workflow%3Atests)
5[![Test Coverage](https://codecov.io/gh/willnorris/imageproxy/branch/master/graph/badge.svg)](https://codecov.io/gh/willnorris/imageproxy)
6[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2611/badge)](https://bestpractices.coreinfrastructure.org/projects/2611)
7
8imageproxy is a caching image proxy server written in go.  It features:
9
10 - basic image adjustments like resizing, cropping, and rotation
11 - access control using allowed hosts list or request signing (HMAC-SHA256)
12 - support for jpeg, png, webp (decode only), tiff, and gif image formats
13   (including animated gifs)
14 - caching in-memory, on disk, or with Amazon S3, Google Cloud Storage, Azure
15   Storage, or Redis
16 - easy deployment, since it's pure go
17
18Personally, I use it primarily to dynamically resize images hosted on my own
19site (read more in [this post][]).  But you can also enable request signing and
20use it as an SSL proxy for remote images, similar to [atmos/camo][] but with
21additional image adjustment options.
22
23[this post]: https://willnorris.com/2014/01/a-self-hosted-alternative-to-jetpacks-photon-service
24[atmos/camo]: https://github.com/atmos/camo
25
26
27## URL Structure ##
28
29imageproxy URLs are of the form `http://localhost/{options}/{remote_url}`.
30
31### Options ###
32
33Options are available for cropping, resizing, rotation, flipping, and digital
34signatures among a few others.  Options for are specified as a comma delimited
35list of parameters, which can be supplied in any order.  Duplicate parameters
36overwrite previous values.
37
38See the full list of available options at
39<https://godoc.org/willnorris.com/go/imageproxy#ParseOptions>.
40
41### Remote URL ###
42
43The URL of the original image to load is specified as the remainder of the
44path, without any encoding.  For example,
45`http://localhost/200/https://willnorris.com/logo.jpg`.
46
47In order to [optimize caching][], it is recommended that URLs not contain query
48strings.
49
50[optimize caching]: http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/
51
52### Examples ###
53
54The following live examples demonstrate setting different options on [this
55source image][small-things], which measures 1024 by 678 pixels.
56
57[small-things]: https://willnorris.com/2013/12/small-things.jpg
58
59Options | Meaning                                  | Image
60--------|------------------------------------------|------
61200x    | 200px wide, proportional height          | <a href="https://imageproxy.willnorris.com/200x/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/200x/https://willnorris.com/2013/12/small-things.jpg" alt="200x"></a>
62x0.15   | 15% original height, proportional width  | <a href="https://imageproxy.willnorris.com/x0.15/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/x0.15/https://willnorris.com/2013/12/small-things.jpg" alt="x0.15"></a>
63100x150 | 100 by 150 pixels, cropping as needed    | <a href="https://imageproxy.willnorris.com/100x150/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/100x150/https://willnorris.com/2013/12/small-things.jpg" alt="100x150"></a>
64100     | 100px square, cropping as needed         | <a href="https://imageproxy.willnorris.com/100/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/100/https://willnorris.com/2013/12/small-things.jpg" alt="100"></a>
65150,fit | scale to fit 150px square, no cropping   | <a href="https://imageproxy.willnorris.com/150,fit/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/150,fit/https://willnorris.com/2013/12/small-things.jpg" alt="150,fit"></a>
66100,r90 | 100px square, rotated 90 degrees         | <a href="https://imageproxy.willnorris.com/100,r90/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/100,r90/https://willnorris.com/2013/12/small-things.jpg" alt="100,r90"></a>
67100,fv,fh | 100px square, flipped horizontal and vertical | <a href="https://imageproxy.willnorris.com/100,fv,fh/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/100,fv,fh/https://willnorris.com/2013/12/small-things.jpg" alt="100,fv,fh"></a>
68200x,q60 | 200px wide, proportional height, 60% quality | <a href="https://imageproxy.willnorris.com/200x,q60/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/200x,q60/https://willnorris.com/2013/12/small-things.jpg" alt="200x,q60"></a>
69200x,png | 200px wide, converted to PNG format | <a href="https://imageproxy.willnorris.com/200x,png/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/200x,png/https://willnorris.com/2013/12/small-things.jpg" alt="200x,png"></a>
70cx175,cw400,ch300,100x | crop to 400x300px starting at (175,0), scale to 100px wide | <a href="https://imageproxy.willnorris.com/cx175,cw400,ch300,100x/https://willnorris.com/2013/12/small-things.jpg"><img src="https://imageproxy.willnorris.com/cx175,cw400,ch300,100x/https://willnorris.com/2013/12/small-things.jpg" alt="cx175,cw400,ch300,100x"></a>
71
72The [smart crop feature](https://godoc.org/willnorris.com/go/imageproxy#hdr-Smart_Crop)
73can best be seen by comparing crops of [this source image][judah-sheets], with
74and without smart crop enabled.
75
76Options | Meaning                                  | Image
77--------|------------------------------------------|------
78150x300 | 150x300px, standard crop | <a href="https://imageproxy.willnorris.com/150x300/https://judahnorris.com/images/judah-sheets.jpg"><img src="https://imageproxy.willnorris.com/150x300/https://judahnorris.com/images/judah-sheets.jpg" alt="200x400,sc"></a>
79150x300,sc | 150x300px, smart crop          | <a href="https://imageproxy.willnorris.com/150x300,sc/https://judahnorris.com/images/judah-sheets.jpg"><img src="https://imageproxy.willnorris.com/150x300,sc/https://judahnorris.com/images/judah-sheets.jpg" alt="200x400"></a>
80
81[judah-sheets]: https://judahnorris.com/images/judah-sheets.jpg
82
83Transformation also works on animated gifs.  Here is [this source
84image][material-animation] resized to 200px square and rotated 270 degrees:
85
86[material-animation]: https://willnorris.com/2015/05/material-animations.gif
87
88<a href="https://imageproxy.willnorris.com/200,r270/https://willnorris.com/2015/05/material-animations.gif"><img src="https://imageproxy.willnorris.com/200,r270/https://willnorris.com/2015/05/material-animations.gif" alt="200,r270"></a>
89
90## Getting Started ##
91
92Install the package using:
93
94    go get willnorris.com/go/imageproxy/cmd/imageproxy
95
96Once installed, ensure `$GOPATH/bin` is in your `$PATH`, then run the proxy
97using:
98
99    imageproxy
100
101This will start the proxy on port 8080, without any caching and with no allowed
102host list (meaning any remote URL can be proxied).  Test this by navigating to
103<http://localhost:8080/500/https://octodex.github.com/images/codercat.jpg> and
104you should see a 500px square coder octocat.
105
106### Cache ###
107
108By default, the imageproxy command does not cache responses, but caching can be
109enabled using the `-cache` flag.  It supports the following values:
110
111 - `memory` - uses an in-memory LRU cache.  By default, this is limited to
112   100mb. To customize the size of the cache or the max age for cached items,
113   use the format `memory:size:age` where size is measured in mb and age is a
114   duration.  For example, `memory:200:4h` will create a 200mb cache that will
115   cache items no longer than 4 hours.
116 - directory on local disk (e.g. `/tmp/imageproxy`) - will cache images
117   on disk
118
119 - s3 URL (e.g. `s3://region/bucket-name/optional-path-prefix`) - will cache
120   images on Amazon S3.  This requires either an IAM role and instance profile
121   with access to your your bucket or `AWS_ACCESS_KEY_ID` and `AWS_SECRET_KEY`
122   environmental variables be set. (Additional methods of loading credentials
123   are documented in the [aws-sdk-go session
124   package](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/)).
125
126   Additional configuration options ([further documented here][aws-options])
127   may be specified as URL query string parameters, which are mostly useful
128   when working with s3-compatible services:
129   - "endpoint" - specify an alternate API endpoint
130   - "disableSSL" - set to "1" to disable SSL when calling the API
131   - "s3ForcePathStyle" - set to "1" to force the request to use path-style addressing
132
133   For example, when working with [minio](https://minio.io), which doesn't use
134   regions, provide a dummy region value and custom endpoint value:
135
136       s3://fake-region/bucket/folder?endpoint=minio:9000&disableSSL=1&s3ForcePathStyle=1
137
138   Similarly, for [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces/),
139   provide a dummy region value and the appropriate endpoint for your space:
140
141       s3://fake-region/bucket/folder?endpoint=sfo2.digitaloceanspaces.com
142
143   [aws-options]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
144
145 - gcs URL (e.g. `gcs://bucket-name/optional-path-prefix`) - will cache images
146   on Google Cloud Storage. Authentication is documented in Google's
147   [Application Default Credentials
148   docs](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application).
149 - azure URL (e.g. `azure://container-name/`) - will cache images on
150   Azure Storage.  This requires `AZURESTORAGE_ACCOUNT_NAME` and
151   `AZURESTORAGE_ACCESS_KEY` environment variables to bet set.
152 - redis URL (e.g. `redis://hostname/`) - will cache images on
153   the specified redis host. The full URL syntax is defined by the [redis URI
154   registration](https://www.iana.org/assignments/uri-schemes/prov/redis).
155   Rather than specify password in the URI, use the `REDIS_PASSWORD`
156   environment variable.
157
158For example, to cache files on disk in the `/tmp/imageproxy` directory:
159
160    imageproxy -cache /tmp/imageproxy
161
162Reload the [codercat URL][], and then inspect the contents of
163`/tmp/imageproxy`.  Within the subdirectories, there should be two files, one
164for the original full-size codercat image, and one for the resized 500px
165version.
166
167[codercat URL]: http://localhost:8080/500/https://octodex.github.com/images/codercat.jpg
168
169Multiple caches can be specified by separating them by spaces or by repeating
170the `-cache` flag multiple times.  The caches will be created in a [tiered
171fashion][]. Typically this is used to put a smaller and faster in-memory cache
172in front of a larger but slower on-disk cache.  For example, the following will
173first check an in-memory cache for an image, followed by a gcs bucket:
174
175    imageproxy -cache memory -cache gcs://my-bucket/
176
177[tiered fashion]: https://godoc.org/github.com/die-net/lrucache/twotier
178
179### Allowed Referrer List ###
180
181You can limit images to only be accessible for certain hosts in the HTTP
182referrer header, which can help prevent others from hotlinking to images. It can
183be enabled by running:
184
185    imageproxy  -referrers example.com
186
187
188Reload the [codercat URL][], and you should now get an error message.  You can
189specify multiple hosts as a comma separated list, or prefix a host value with
190`*.` to allow all sub-domains as well.
191
192### Allowed and Denied Hosts List ###
193
194You can limit the remote hosts that the proxy will fetch images from using the
195`allowHosts` and `denyHosts` flags.  This is useful, for example, for locking
196the proxy down to your own hosts to prevent others from abusing it.  Of course
197if you want to support fetching from any host, leave off these flags.
198
199Try it out by running:
200
201    imageproxy -allowHosts example.com
202
203Reload the [codercat URL][], and you should now get an error message.
204Alternately, try running:
205
206    imageproxy -denyHosts octodex.github.com
207
208Reloading the [codercat URL][] will still return an error message.
209
210You can specify multiple hosts as a comma separated list to either flag, or
211prefix a host value with `*.` to allow or deny all sub-domains as well.
212
213If a host matches both an allowed an a denied host, the request will be denied.
214
215### Allowed Content-Type List ###
216
217You can limit what content types can be proxied by using the `contentTypes`
218flag. By default, this is set to `image/*`, meaning that imageproxy will
219process any image types. You can specify multiple content types as a comma
220separated list, and suffix values with `*` to perform a wildcard match. Set the
221flag to an empty string to proxy all requests, regardless of content type.
222
223### Signed Requests ###
224
225Instead of an allowed host list, you can require that requests be signed.  This
226is useful in preventing abuse when you don't have just a static list of hosts
227you want to allow.  Signatures are generated using HMAC-SHA256 against the
228remote URL, and url-safe base64 encoding the result:
229
230    base64urlencode(hmac.New(sha256, <key>).digest(<remote_url>))
231
232The HMAC key is specified using the `signatureKey` flag.  If this flag
233begins with an "@", the remainder of the value is interpreted as a file on disk
234which contains the HMAC key.
235
236Try it out by running:
237
238    imageproxy -signatureKey "secretkey"
239
240Reload the [codercat URL][], and you should see an error message.  Now load a
241[signed codercat URL][] (which contains the [signature option][]) and verify
242that it loads properly.
243
244[signed codercat URL]: http://localhost:8080/500,sXyMwWKIC5JPCtlYOQ2f4yMBTqpjtUsfI67Sp7huXIYY=/https://octodex.github.com/images/codercat.jpg
245[signature option]: https://godoc.org/willnorris.com/go/imageproxy#hdr-Signature
246
247Some simple code samples for generating signatures in various languages can be
248found in [docs/url-signing.md](/docs/url-signing.md).  Multiple valid signature
249keys may be provided to support key rotation by repeating the `signatureKey`
250flag multiple times, or by providing a space-separated list of keys.  To use a
251key with a literal space character, load the key from a file using the "@"
252prefix documented above.
253
254If both a whiltelist and signatureKey are specified, requests can match either.
255In other words, requests that match one of the allowed hosts don't necessarily
256need to be signed, though they can be.
257
258### Default Base URL ###
259
260Typically, remote images to be proxied are specified as absolute URLs.
261However, if you commonly proxy images from a single source, you can provide a
262base URL and then specify remote images relative to that base.  Try it out by
263running:
264
265    imageproxy -baseURL https://octodex.github.com/
266
267Then load the codercat image, specified as a URL relative to that base:
268<http://localhost:8080/500/images/codercat.jpg>.  Note that this is not an
269effective method to mask the true source of the images being proxied; it is
270trivial to discover the base URL being used.  Even when a base URL is
271specified, you can always provide the absolute URL of the image to be proxied.
272
273### Scaling beyond original size ###
274
275By default, the imageproxy won't scale images beyond their original size.
276However, you can use the `scaleUp` command-line flag to allow this to happen:
277
278    imageproxy -scaleUp true
279
280### WebP and TIFF support ###
281
282Imageproxy can proxy remote webp images, but they will be served in either jpeg
283or png format (this is because the golang webp library only supports webp
284decoding) if any transformation is requested.  If no format is specified,
285imageproxy will use jpeg by default.  If no transformation is requested (for
286example, if you are just using imageproxy as an SSL proxy) then the original
287webp image will be served as-is without any format conversion.
288
289Because so few browsers support tiff images, they will be converted to jpeg by
290default if any transformation is requested. To force encoding as tiff, pass the
291"tiff" option. Like webp, tiff images will be served as-is without any format
292conversion if no transformation is requested.
293
294
295Run `imageproxy -help` for a complete list of flags the command accepts.  If
296you want to use a different caching implementation, it's probably easiest to
297just make a copy of `cmd/imageproxy/main.go` and customize it to fit your
298needs... it's a very simple command.
299
300### Environment Variables ###
301
302All configuration flags have equivalent environment variables of the form
303`IMAGEPROXY_$NAME`.  For example, an on-disk cache could be configured by calling
304
305    IMAGEPROXY_CACHE="/tmp/imageproxy" imageproxy
306
307## Deploying ##
308
309In most cases, you can follow the normal procedure for building a deploying any
310go application.  For example:
311
312 - `go build willnorris.com/go/imageproxy/cmd/imageproxy`
313 - copy resulting binary to `/usr/local/bin`
314 - copy [`etc/imageproxy.service`](etc/imageproxy.service) to
315   `/lib/systemd/system` and enable using `systemctl`.
316
317Instructions have been contributed below for running on other platforms, but I
318don't have much experience with them personally.
319
320### Heroku ###
321
322It's easy to vendorize the dependencies with `Godep` and deploy to Heroku. Take
323a look at [this GitHub repo](https://github.com/oreillymedia/prototype-imageproxy)
324
325### Docker ###
326
327A docker image is available at [`willnorris/imageproxy`](https://registry.hub.docker.com/u/willnorris/imageproxy/dockerfile/).
328
329You can run it by
330```
331docker run -p 8080:8080 willnorris/imageproxy -addr 0.0.0.0:8080
332```
333
334Or in your Dockerfile:
335
336```
337ENTRYPOINT ["/app/imageproxy", "-addr 0.0.0.0:8080"]
338```
339
340If running imageproxy inside docker with a bind-mounted on-disk cache, make sure
341the container is running as a user that has write permission to the mounted host
342directory.  See more details in
343[#198](https://github.com/willnorris/imageproxy/issues/198).
344
345### nginx ###
346
347Use the `proxy_pass` directive to send requests to your imageproxy instance.
348For example, to run imageproxy at the path "/api/imageproxy/", set:
349
350```
351  location /api/imageproxy/ {
352    proxy_pass http://localhost:4593/;
353  }
354```
355
356Depending on other directives you may have in your nginx config, you might need
357to alter the precedence order by setting:
358
359```
360  location ^~ /api/imageproxy/ {
361    proxy_pass http://localhost:4593/;
362  }
363```
364
365## License ##
366
367imageproxy is copyright Google, but is not an official Google product.  It is
368available under the [Apache 2.0 License](./LICENSE).
369