Slide 1

Slide 1 text

Handling user-uploaded images with ease and confidence Andrey Novikov, Evil Martians Osaka Web Designers and Developers Meetup 22 July 2023

Slide 2

Slide 2 text

That title is boring! Let’s change!

Slide 3

Slide 3 text

imgproxy is amazing! Andrey Novikov, Evil Martians Osaka Web Designers and Developers Meetup 22 July 2023

Slide 4

Slide 4 text

About me Back-end engineer at Evil Martians Writing Ruby, Go, and whatever SQL, Dockerfiles, TypeScript, bash… Love open-source software Created and maintaining a few Ruby gems Living in Japan for 1 year already Driving a moped And also a bicycle to get kids to kindergarten Hi, I’m Andrey

Slide 5

Slide 5 text

evilmartians.com evilmartians.jp 邪悪な火星人? イービルマーシャンズ!

Slide 6

Slide 6 text

Martian Open Source Yabeda: Ruby application instrumentation framework Lefthook: git hooks manager AnyCable: Polyglot replacement for ActionCable server PostCSS: A tool for transforming CSS with JavaScript Imgproxy: Fast and secure standalone server for resizing and converting remote images Logux: Client-server communication framework based on Optimistic UI, CRDT, and log Overmind: Process manager for Procfile-based applications and tmux Even more at evilmartians.com/oss Today's topic

Slide 7

Slide 7 text

So, you need to handle user images Profile pictures Product photos Recipes Reviews Photos in feedback forms … Surprisingly often you need to do it in a web application!

Slide 8

Slide 8 text

What you will do with them? Generate thumbnails to save bandwidth Crop them to fit design Add watermarks to prevent theft Apply filters However, CSS can do it too Show them in various places, of course!

Slide 9

Slide 9 text

“Classic” way Upload image to the server Probably among other form fields Store it somewhere Often on S3 or other cloud storage Generate all required thumbnails As many as your design requires Store them somewhere Again S3 or other cloud storage Serve them to the user CDN will help here

Slide 10

Slide 10 text

“Classic” way visualized JobQueue Storage Server User Job started Uploads Image Stores Image Queues Job Upload successful Requests thumbnail Retrieves Thumbnail There are no thumbnails yet! “Image is processing” Retrieve image Unpredictable latency here

Slide 11

Slide 11 text

JobQueue ImageStorage Server User Generates thumbnail Stores Thumbnail Requests thumbnail Retrieves Thumbnail Oh yes, of course, here it is Returns thumbnail

Slide 12

Slide 12 text

Problems of “classic” approach Hard to predict latency These “image is processing” fallbacks are ugly Hard to add new variants Need to reprocess all images before changing front-end And hard to clean up old ones Space is cheap, but not free Deployment gets complicated You need to install ImageMagick or something on all servers/containers Security also is your headache Processing images on your servers is a security and stability risk, e.g. PNG decompression bomb.

Slide 13

Slide 13 text

Do we have to do things this way? What if we could just generate thumbnails on the fly?

Slide 14

Slide 14 text

Meet image processing servers There are many of them: imaginary, cloudinary, etc. And, of course, imgproxy! They do just one thing, but do it well imgproxy Storage Server User imgproxy Storage Server User generate thumbnail on the fly Uploads Image Notifies about upload Thumbnail URL Requests thumbnail Retrieves image Respond with thumbnail

Slide 15

Slide 15 text

What the URL! Given original image URL: I need to get 300×150 thumbnail, but for Retina displays, smart cropped, and saturated, also with watermark in right bottom corner. Here is the result URL for such a thumbnail: See https://docs.imgproxy.net/generating_the_url The only thing you need to care about is constructing URLs https://mars.nasa.gov/system/downloadable_items/40368_PIA22228.jpg https:%2F%2Fmars.nasa.gov%2Fsystem%2Fdownloadable_items%2F40368_PIA22228.jpg https://demo.imgproxy.net/ doqHNTjtFpozyphRzlQTHyBloSoYS13lLuMDozTnxqA/ rs:fill:300:150:1/dpr:2/g:ce/sa:1.4/ wm:0.5:soea:0:0:0.2/wmu:aHR0cHM6Ly9pbWdwcm94eS5uZXQvd2F0ZXJtYXJrLnN2Zw/ plain/ Digital signature Processing options Original image URL

Slide 16

Slide 16 text

Original image Original image: 19.9 MB

Slide 17

Slide 17 text

Processed image Image processed with imgproxy: 32 kB

Slide 18

Slide 18 text

imgproxy Written in Go Great concurrency, low memory footprint, squeezes everything from your servers CPU Uses libvips for image handling Along with specially crafted processing pipeline optimized for speed and concurrency Open source and open core Free to use OSS version that covers needs of 99% users, paid PRO version with more features and support for those who really need it Easy to deploy Just spin up a Docker container and forget and it is ready to go. Easy to use Just construct a URL using one of the client libraries, send it to a browser, done! Secure and safe Uses signed URIs, handles image bombs, invalid images, and more.

Slide 19

Slide 19 text

More on security Signed URLs No one can generate URLs without knowing your secret key and use your imgproxy to process their images for free. Or DDoS and cache-poison your CDN by requesting your images with all possible sizes and options. Examples how to sign URL in different languages: https://github.com/imgproxy/imgproxy/tree/master/examples Image compression bombs imgproxy will check metadata and won’t process images that are too large by dimensions Authentication imgproxy can check for authentication headers, and will not process images if someone try to access it bypassing CDN Source restrictions imgproxy can be instructed to allow process images only from sources that you control.

Slide 20

Slide 20 text

How it solves “classic” approach Latency: Dedicated service that do only images processing Very performant per se, and you can scale it independently from your main application, also add CDN in front of it Adding new variants: Just construct new URL Construct new URL, request it, done! Cleaning up old ones: Let CDN caches to expire Do you really need to store thumbnails at all? Care only for originals. Security and stability: it is separate from your main application It handles image bombs, and other nasty stuff, but even if some malicious code will be executed, it will find itself in empty Docker container without anything in it.

Slide 21

Slide 21 text

Recommended setup Use direct-upload to cloud storage (S3, …) No need to pass images through your application servers at all Place a caching CDN in front of imgproxy Take repetitive load off from imgproxy, save some CO₂

Slide 22

Slide 22 text

Migration pitfalls Only back-end can construct signed URLs No more guessing on front-end of what variants are available But you can opt-out from signing URLs if you want Couldn't recall any more 🌚

Slide 23

Slide 23 text

Open source imgproxy will cover you But there are more goodies (and support) in PRO version! Advanced per-image settings Different resizing algirithms, watermarks, compression for individual images Automagic selection of image format and quality settings Maximum per-image compression using most modern format without visible quality loss Even smarter crop with object detection Detect objects using ML algorithms to crop more accurately or blur them SVG processing Inject custom styles, minify Videos, animated GIFs, PDFs support Thumbnailing videos, GIF to video conversion, getting image info OSS version has everything that most web applications need… imgproxy.net/features

Slide 24

Slide 24 text

Read more imgproxy is amazing by John Nunemaker heavily influenced this talk plot (and title, yes) imgproxy: Resize your images instantly and securely by Sergey Alexandrovich (imgproxy author) with more details on how imgproxy works and how to use it Decoding AVIF: Deep dive with cats and imgproxy by Polina Gurtovaya illustrated explanation of modern video and image format internals and how to start using them with imgproxy!

Slide 25

Slide 25 text

Thank you! @Envek @Envek @Envek @Envek github.com/Envek @evilmartians @evilmartians @evil-martians @evil.martians evilmartians.com Our awesome blog: evilmartians.com/chronicles! See these slides at envek.github.io/owddm-imgproxy-is-amazing Go get imgproxy! imgproxy.net