From 540bc1fd84b7ae51ddef2f6a6472f31d28ebb12b Mon Sep 17 00:00:00 2001 From: Mac Siri Date: Thu, 29 Oct 2020 09:03:55 -0400 Subject: [PATCH] [deploy] Add Imgproxy docs (#11104) Co-authored-by: Molly Struve Co-authored-by: Vaidehi Joshi --- docs/installation/imgproxy.md | 74 +++++++++++++++++++++ docs/installation/readme.md | 1 + docs/technical-overview/stack.md | 4 +- spec/services/images/optimizer_spec.rb | 41 ++++++------ spec/views/dashboards/show.html.erb_spec.rb | 8 +-- 5 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 docs/installation/imgproxy.md diff --git a/docs/installation/imgproxy.md b/docs/installation/imgproxy.md new file mode 100644 index 000000000..1e530382d --- /dev/null +++ b/docs/installation/imgproxy.md @@ -0,0 +1,74 @@ +--- +title: Imgproxy +--- + +# Imgproxy + +Imgproxy is a standalone server for resizing images. It is optional and you do +not need it to start Forem locally. We are currently only using it in Forem Cloud. + +## Installation + +- MacOS: install via homebrew with `brew install imgproxy`. +- Window: please install + [via docker](https://docs.imgproxy.net/#/installation?id=docker). +- Linux: you can either use + [docker installation](https://docs.imgproxy.net/#/installation?id=docker) or + [build from source](https://docs.imgproxy.net/#/installation?id=from-the-source). + +For more options not covered here, please take a look at the +[official installation documentation](https://docs.imgproxy.net/#/installation). + +## Usage + +1. Generate a key/salt pair by running the following in your terminal twice. + Copy those values to your `.env` in the next step + + ``` + echo $(xxd -g 2 -l 64 -p /dev/random | tr -d '\n') + ``` + +1. In your `.env`, add the following. + + ``` + export IMGPROXY_ENDPOINT='http://localhost:8080' + export IMGPROXY_KEY='1b1c9aae804e070b0864f2547fba7ce8ff31bf7..........' + export IMGPROXY_SALT='8c6d449d4fc2cada5bab538826cae709d2ade9f.........' + ``` + +1. Start the Forem app server normally. + +1. Start Imgproxy in a terminal with the key and salt. + + ``` + # If you installed via homebrew or using the binary. + > IMGPROXY_KEY='your key' IMGPROXY_SALT='your salt' imgproxy + + # If you are using Docker or Podman. The commands are identical for both + > docker run -p 8080:8080 \ + -e IMGPROXY_KEY="your key" \ + -e IMGPROXY_SALT="your salt" \ + -it darthsim/imgproxy + ``` + +1. That's it :) + +You should verify it's working by starting the Forem app locally and see that +each image is loaded properly, or run the following command while the Forem app +is running: + +``` +> curl -I http://localhost:8080/unsafe/aHR0cDovL2xvY2Fs/aG9zdDozMDAwL2Fz/c2V0cy8xLnBuZw + +HTTP/1.1 200 OK +Server: imgproxy +X-Request-Id: GYvCGXb98JUwL3ujwpjzh +Date: Tue, 27 Oct 2020 16:11:37 GMT +``` + +## Sidenote + +- Because Imgproxy is a standalone server of its own, all image URLs given to it + need to be absolute URLs. +- When working with Docker or Podman on Linux, provide the host network option + (`--network="host"`) so Imgproxy can properly access the localhost. diff --git a/docs/installation/readme.md b/docs/installation/readme.md index 456a9f7d3..73f469ba4 100644 --- a/docs/installation/readme.md +++ b/docs/installation/readme.md @@ -6,6 +6,7 @@ items: - containers.md - gitpod.md - postgresql.md + - imgproxy.md - vault.md - others.md --- diff --git a/docs/technical-overview/stack.md b/docs/technical-overview/stack.md index 583ad187b..be9f08bd5 100644 --- a/docs/technical-overview/stack.md +++ b/docs/technical-overview/stack.md @@ -11,7 +11,9 @@ For the Forem tech stack we use: - [_Redis_](https://redis.io/) to store cached data - [_Fastly_](https://www.fastly.com/) for [edge caching](https://dev.to/ben/making-devto-insanely-fast) -- [_Cloudinary_](https://cloudinary.com/) for image manipulation/serving +- [_Cloudinary_](https://cloudinary.com/) and/or + [_Imgproxy_](https://github.com/imgproxy/imgproxy) for image + manipulation/serving - [_Honeybadger_](https://www.honeybadger.io/) for error monitoring - [_Timber_](https://timber.io/) for logging - [_Sidekiq_](https://github.com/mperham/sidekiq) and diff --git a/spec/services/images/optimizer_spec.rb b/spec/services/images/optimizer_spec.rb index 5957b44cb..4a91a378a 100644 --- a/spec/services/images/optimizer_spec.rb +++ b/spec/services/images/optimizer_spec.rb @@ -5,15 +5,6 @@ RSpec.describe Images::Optimizer, type: :service do let(:image_url) { "https://i.imgur.com/fKYKgo4.png" } - def stub_imgproxy - imgproxy_config_stub = Imgproxy::Config.new.tap do |config| - config.key = "secret" - config.salt = "secret" - config.base64_encode_urls = true - end - allow(Imgproxy).to receive(:config).and_return(imgproxy_config_stub) - end - describe "#call" do before do allow(described_class).to receive(:cloudinary) @@ -31,15 +22,9 @@ RSpec.describe Images::Optimizer, type: :service do expect(described_class).to have_received(:cloudinary) end - it "calls cloudinary if imgproxy's key and salt is missing" do - allow(Imgproxy).to receive(:config).and_return(Imgproxy::Config.new) - described_class.call(image_url, service: :imgproxy) - expect(described_class).to have_received(:cloudinary) - end - - it "calls imgproxy if imgproxy's key and salt is provided" do - stub_imgproxy - described_class.call(image_url, service: :imgproxy) + it "calls imgproxy if imgproxy is enabled" do + allow(described_class).to receive(:imgproxy_enabled?).and_return(true) + described_class.call(image_url) expect(described_class).to have_received(:imgproxy) end end @@ -72,12 +57,30 @@ RSpec.describe Images::Optimizer, type: :service do describe "#imgproxy" do it "works" do - stub_imgproxy + allow(described_class).to receive(:imgproxy_enabled?).and_return(true) imgproxy_url = described_class.imgproxy(image_url, service: :imgproxy, width: 500, height: 500) expect(imgproxy_url).to match(%r{/s:500:500/aHR0cHM6Ly9pLmlt/Z3VyLmNvbS9mS1lL/Z280LnBuZw}) end end + describe "#imgproxy_enabled?" do + it "returns false if key and salt are missing" do + allow(Imgproxy).to receive(:config).and_return(Imgproxy::Config.new) + expect(described_class.imgproxy_enabled?).to eq(false) + end + + it "returns true if key and salt are provided" do + imgproxy_config_stub = Imgproxy::Config.new.tap do |config| + config.key = "secret" + config.salt = "secret" + config.base64_encode_urls = true + end + allow(Imgproxy).to receive(:config).and_return(imgproxy_config_stub) + + expect(described_class.imgproxy_enabled?).to eq(true) + end + end + describe "#translate_cloudinary_options" do it "Set resizing_type to fill if crop: fill is provided" do options = { width: 100, height: 100, crop: "fill" } diff --git a/spec/views/dashboards/show.html.erb_spec.rb b/spec/views/dashboards/show.html.erb_spec.rb index f0f14946c..77c045482 100644 --- a/spec/views/dashboards/show.html.erb_spec.rb +++ b/spec/views/dashboards/show.html.erb_spec.rb @@ -6,16 +6,10 @@ RSpec.describe "dashboards/show.html.erb", type: :view do stub_template "dashboards/_analytics.html.erb" => "stubbed content" stub_template "dashboards/_actions.html.erb" => "stubbed content" - Imgproxy.config.key = "secret" - Imgproxy.config.salt = "secret" + allow(Images::Optimizer).to receive(:imgproxy_enabled?).and_return(true) allow(SiteConfig).to receive(:mascot_image_url).and_return("https://i.imgur.com/fKYKgo4.png") end - after do - Imgproxy.config.key = nil - Imgproxy.config.endpoint = nil - end - context "when using Imgproxy" do it "renders mascot image properly" do assign(:user, create(:user))