From c09f345cff283c12eb069a89f87021b566c8cb06 Mon Sep 17 00:00:00 2001 From: Matt Palmer Date: Mon, 28 Sep 2015 21:41:57 +1000 Subject: [PATCH 1/4] Proxy letter avatars by default On sites that don't otherwise configure an avatar fallback, Discourse will now tell the client to get its letter avatars from a location which nginx proxies to the centralised `avatars.discourse.org` service. This alleviates privacy concerns, whilst still providing some degree of performance benefit (no need for every site to delay avatar response by 300ms for image rendering). It is still possible to gain the benefits of global image caching and the lower latency of requesting directly from a CDN, by explicitly changing the `external_system_avatars_url` site setting to `https://avatars.discourse.org/letter/{first_letter}/{color}/{size}.png`. --- app/models/user.rb | 1 + config/nginx.sample.conf | 5 +++++ config/site_settings.yml | 4 ++-- spec/models/user_spec.rb | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index cca5693bbfd..8f42ac3c786 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -475,6 +475,7 @@ class User < ActiveRecord::Base url.gsub! "{color}", letter_avatar_color(username.downcase) url.gsub! "{username}", username url.gsub! "{first_letter}", username[0].downcase + url.gsub! "{hostname}", RailsMultisite::ConnectionManagement.current_hostname url else "#{Discourse.base_uri}/letter_avatar/#{username.downcase}/{size}/#{LetterAvatar.version}.png" diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf index 6e846f2a95e..fa29fe8c85c 100644 --- a/config/nginx.sample.conf +++ b/config/nginx.sample.conf @@ -192,6 +192,11 @@ server { break; } + location /letter_avatar_proxy { + rewrite /letter_avatar_proxy/(.*)$ /$1 break; + proxy_pass https://avatars.discourse.org; + } + # this means every file in public is tried first try_files $uri @discourse; } diff --git a/config/site_settings.yml b/config/site_settings.yml index 14971387278..81453913b25 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -593,9 +593,9 @@ files: client: true shadowed_by_global: true external_system_avatars_url: - default: "https://avatars.discourse.org/v2/letter/{first_letter}/{color}/{size}.png" + default: "//{hostname}/letter_avatar_proxy/v2/letter/{first_letter}/{color}/{size}.png" client: true - regex: '^https?:\/\/.+[^\/]' + regex: '^((https?:)?\/)?\/.+[^\/]' default_opengraph_image_url: '' trust: diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2f3fbfd2730..1a6f028b2c9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -912,7 +912,7 @@ describe User do expect(user.small_avatar_url).to eq("//test.localhost/letter_avatar/sam/45/#{LetterAvatar.version}.png") SiteSetting.external_system_avatars_enabled = true - expect(user.small_avatar_url).to eq("https://avatars.discourse.org/v2/letter/s/5f9b8f/45.png") + expect(user.small_avatar_url).to eq("//test.localhost/letter_avatar_proxy/v2/letter/s/5f9b8f/45.png") end end From af4a48a67c92e37cdbe8187ab23cd27ae6b78ef8 Mon Sep 17 00:00:00 2001 From: Matt Palmer Date: Fri, 2 Oct 2015 17:27:54 +1000 Subject: [PATCH 2/4] Use Discourse.current_hostname Much cleaner. --- app/models/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index 8f42ac3c786..c39e75a4d97 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -475,7 +475,7 @@ class User < ActiveRecord::Base url.gsub! "{color}", letter_avatar_color(username.downcase) url.gsub! "{username}", username url.gsub! "{first_letter}", username[0].downcase - url.gsub! "{hostname}", RailsMultisite::ConnectionManagement.current_hostname + url.gsub! "{hostname}", Discourse.current_hostname url else "#{Discourse.base_uri}/letter_avatar/#{username.downcase}/{size}/#{LetterAvatar.version}.png" From ab2e9a0beb9e95cd7faed90ffa29e1613ca8fc82 Mon Sep 17 00:00:00 2001 From: Matt Palmer Date: Fri, 2 Oct 2015 17:28:49 +1000 Subject: [PATCH 3/4] Don't put the current hostname in external avatar URL --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index 81453913b25..0c41d6f2771 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -593,7 +593,7 @@ files: client: true shadowed_by_global: true external_system_avatars_url: - default: "//{hostname}/letter_avatar_proxy/v2/letter/{first_letter}/{color}/{size}.png" + default: "/letter_avatar_proxy/v2/letter/{first_letter}/{color}/{size}.png" client: true regex: '^((https?:)?\/)?\/.+[^\/]' default_opengraph_image_url: '' From 952d07599a95d0a01822220587f571980dc7a1e6 Mon Sep 17 00:00:00 2001 From: Matt Palmer Date: Fri, 9 Oct 2015 08:45:09 +1100 Subject: [PATCH 4/4] More tweaks for the letter avatar proxy config --- config/nginx.sample.conf | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf index fa29fe8c85c..35cbd520dc8 100644 --- a/config/nginx.sample.conf +++ b/config/nginx.sample.conf @@ -173,7 +173,7 @@ server { # This big block is needed so we can selectively enable # acceleration for backups and avatars # see note about repetition above - location ~ ^/(letter_avatar|user_avatar|highlight-js|stylesheets|favicon/proxied) { + location ~ ^/(letter_avatar/|user_avatar|highlight-js|stylesheets|favicon/proxied) { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -192,9 +192,23 @@ server { break; } - location /letter_avatar_proxy { - rewrite /letter_avatar_proxy/(.*)$ /$1 break; - proxy_pass https://avatars.discourse.org; + location /letter_avatar_proxy/ { + # Don't send any client headers to the avatars service + proxy_method GET; + proxy_pass_request_headers off; + proxy_pass_request_body off; + + # Don't let cookies interrupt caching, and don't pass them to the + # client + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + + proxy_cache one; + proxy_cache_key $uri; + proxy_cache_valid 200 7d; + proxy_cache_valid 404 1m; + + proxy_pass https://avatars.discourse.org/; } # this means every file in public is tried first