88 votes

Nginx proxy des ressources Amazon S3

J'effectue quelques tâches de WPO, et PageSpeed m'a suggéré d'utiliser la mise en cache du navigateur. Je l'ai amélioré avec succès pour certains fichiers statiques dans mon serveur Nginx, mais mes fichiers d'images stockés dans le serveur Amazon S3 sont toujours absents.

J'ai lu une approche consistant à mettre à jour chaque fichier dans S3 afin d'inclure des métatags d'en-tête (Expires et Cache-Control). Je pense que ce n'est pas une bonne approche. J'ai des milliers de fichiers, donc ce n'est pas faisable pour moi.

Je pense que l'approche la plus pratique est de configurer mon serveur Nginx 1.6.0 pour qu'il serve de proxy aux fichiers S3. J'ai lu des choses à ce sujet, mais je ne suis pas du tout compétent en matière de configuration de serveur, alors j'ai pris quelques exemples sur ces sites : https://gist.github.com/benjaminbarbe/1961db5ffbaad57eff12

J'ai ajouté ce code d'emplacement à l'intérieur de mon bloc serveur dans mon fichier de configuration nginx :

#inside server block
location /mybucket.s3.amazonaws.com/ {

        proxy_http_version     1.1;
        proxy_set_header       Host mybucket.s3.amazonaws.com;
        proxy_set_header       Authorization '';
        proxy_hide_header      x-amz-id-2;
        proxy_hide_header      x-amz-request-id;
        proxy_hide_header      Set-Cookie;
        proxy_ignore_headers   "Set-Cookie";
        proxy_buffering        off;
        proxy_intercept_errors on;      
        proxy_pass             http://mybucket.s3.amazonaws.com;
      }

En tout cas, ça ne marche pas pour moi. Aucun en-tête n'est inclus dans mes demandes. Donc, d'abord je pense que les demandes ne correspondent pas aux emplacements.

Accept-Ranges:bytes
Content-Length:90810
Content-Type:image/jpeg
Date:Fri, 23 Jun 2017 04:53:56 GMT
ETag:"4fd0be549fbcaf9b47c18a15146cdf16"
Last-Modified:Tue, 09 Jun 2015 09:47:13 GMT
Server:AmazonS3
x-amz-id-2:cKsq1qRra74DqVsTewh3P3sgzVUoPR8aAT2NFCuwA+JjCdDZfk7/7x/C0WPjBa51GEb4C8LyAIc=
x-amz-request-id:94EADB4EDD3DE1C1

0 votes

Peut-être modifier le Cache-Control pour les objets existants via un script, par exemple. chriskief.com/2014/07/13/réglage du cache-métadonnées 3 .

0 votes

Je ne vois rien dans la configuration de Nginx pour ajouter des en-têtes. De plus, le proxy_hide_header sont ignorées, et nginx, par défaut, aurait dû supprimer les directives Server: . Donc... êtes-vous sûr que cette requête a été effectivement traitée par Nginx ?

0 votes

@Michael-sqlbot Non. Je ne connais presque rien à la configuration des serveurs. Toute aide est appréciée.

198voto

mikhailov Points 4981

Votre approche du proxy des fichiers S3 via Nginx est tout à fait pertinente. Elle résout un certain nombre de problèmes et offre des avantages supplémentaires tels que le masquage des URL, le cache du proxy, l'accélération du transfert en déchargeant SSL/TLS. Vous le faites presque correctement, laissez-moi vous montrer ce qu'il reste à faire pour le rendre parfait.

Pour les requêtes d'exemple, j'utilise le seau S3 et l'URL d'une image mentionnée dans le document commentaire public à la question initiale.

Nous commençons par inspecter les en-têtes des fichiers Amazon S3.

curl -I http://yanpy.dev.s3.amazonaws.com/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg

HTTP/1.1 200 OK
Date: Sun, 25 Jun 2017 17:49:10 GMT
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Accept-Ranges: bytes
Content-Type: binary/octet-stream
Content-Length: 378843
Server: AmazonS3

Nous pouvons voir qu'il manque Cache-Control mais que les en-têtes GET conditionnels ont déjà été configurés. Lorsque nous réutilisons E-Tag/Last-Modified (c'est ainsi que fonctionne le cache côté client d'un navigateur), nous obtenons HTTP 304 avec un Content-Length vide. Une interprétation de cela est que le client (curl dans notre cas) interroge la ressource en disant qu'aucun transfert de données n'est nécessaire à moins que le fichier ait été modifié sur le serveur :

curl -I http://yanpy.dev.s3.amazonaws.com/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg 
--header "If-None-Match: 37a907fc5dd7cfd0c428af78f09e95a9"

HTTP/1.1 304 Not Modified
Date: Sun, 25 Jun 2017 17:53:33 GMT
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Server: AmazonS3

curl -I http://yanpy.dev.s3.amazonaws.com/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg 
--header "If-Modified-Since: Wed, 21 Jun 2017 07:42:31 GMT"

HTTP/1.1 304 Not Modified
Date: Sun, 25 Jun 2017 18:17:34 GMT
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Server: AmazonS3

"PageSpeed a suggéré de tirer parti de la mise en cache du navigateur", cela signifie que Cache=control est manquant. Nginx en tant que proxy pour les fichiers S3 résout non seulement le problème des en-têtes manquants mais aussi l'économie de trafic. en utilisant le cache du proxy Nginx.

J'utilise macOS mais la configuration de Nginx fonctionne sous Linux exactement de la même manière sans modifications. Pas à pas :

1. installer Nginx

brew update && brew install nginx

2. configurer Nginx pour qu'il serve de proxy au seau S3, voir la configuration ci-dessous.

3. demander le fichier via Nginx. Veuillez jeter un coup d'œil à la Serveur nous voyons maintenant Nginx plutôt qu'Amazon S3 :

curl -I http://localhost:8080/s3/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg

HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Sun, 25 Jun 2017 18:30:26 GMT
Content-Type: binary/octet-stream
Content-Length: 378843
Connection: keep-alive
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Accept-Ranges: bytes
Cache-Control: max-age=31536000

Request the file via Nginx

Demander le fichier en utilisant le proxy Nginx avec GET conditionnel :

curl -I http://localhost:8080/s3/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg 
--header "If-None-Match: 37a907fc5dd7cfd0c428af78f09e95a9"

HTTP/1.1 304 Not Modified
Server: nginx/1.12.0
Date: Sun, 25 Jun 2017 18:32:16 GMT
Connection: keep-alive
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Cache-Control: max-age=31536000

Request the file using Nginx proxy with Conditional GET

5. demander le fichier en utilisant le cache du proxy de Nginx, veuillez consulter le site suivant X-Cache-Status sa valeur est MISS jusqu'à ce que le cache soit réchauffé après la première demande.

curl -I http://localhost:8080/s3_cached/img/blog/sailing-routes-around-croatia-central-dalmatia-islands/yachts-anchored-paradise-cove-croatia-3.jpg
HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Sun, 25 Jun 2017 18:40:45 GMT
Content-Type: binary/octet-stream
Content-Length: 378843
Connection: keep-alive
Last-Modified: Wed, 21 Jun 2017 07:42:31 GMT
ETag: "37a907fc5dd7cfd0c428af78f09e95a9"
Expires: Fri, 21 Jul 2018 07:41:49 UTC
Cache-Control: max-age=31536000
X-Cache-Status: HIT
Accept-Ranges: bytes

Request the file using Nginx proxy cache

Sur la base de Documentation officielle de Nginx Je fournis la configuration Nginx S3 avec des paramètres de mise en cache optimisés qui prennent en charge les options suivantes :

  • proxy_cache_revalidate indique à NGINX d'utiliser des requêtes GET conditionnelles lors du rafraîchissement du contenu des serveurs d'origine
  • le paramètre de mise à jour de la proxy_cache_utilisation_stale indique à NGINX de livrer du contenu périmé lorsque les clients demandent un article alors qu'une mise à jour de celui-ci est en cours de téléchargement depuis le serveur d'origine, au lieu de transmettre les demandes répétées au serveur
  • avec proxy_cache_lock activé, si plusieurs clients demandent un fichier qui n'est pas à jour dans le cache (un MISS), seule la première de ces demandes est autorisée à passer au serveur d'origine. demandes est autorisée par le serveur d'origine

Configuration de Nginx :

worker_processes  1;
daemon off;

error_log  /dev/stdout info;
pid        /usr/local/var/nginx/nginx.pid;

events {
  worker_connections  1024;
}

http {
  default_type       text/html;
  access_log         /dev/stdout;
  sendfile           on;
  keepalive_timeout  65;

  proxy_cache_path   /tmp/ levels=1:2 keys_zone=s3_cache:10m max_size=500m
                     inactive=60m use_temp_path=off;

  server {
    listen 8080;

    location /s3/ {
      proxy_http_version     1.1;
      proxy_set_header       Connection "";
      proxy_set_header       Authorization '';
      proxy_set_header       Host yanpy.dev.s3.amazonaws.com;
      proxy_hide_header      x-amz-id-2;
      proxy_hide_header      x-amz-request-id;
      proxy_hide_header      x-amz-meta-server-side-encryption;
      proxy_hide_header      x-amz-server-side-encryption;
      proxy_hide_header      Set-Cookie;
      proxy_ignore_headers   Set-Cookie;
      proxy_intercept_errors on;
      add_header             Cache-Control max-age=31536000;
      proxy_pass             http://yanpy.dev.s3.amazonaws.com/;
    }

    location /s3_cached/ {
      proxy_cache            s3_cache;
      proxy_http_version     1.1;
      proxy_set_header       Connection "";
      proxy_set_header       Authorization '';
      proxy_set_header       Host yanpy.dev.s3.amazonaws.com;
      proxy_hide_header      x-amz-id-2;
      proxy_hide_header      x-amz-request-id;
      proxy_hide_header      x-amz-meta-server-side-encryption;
      proxy_hide_header      x-amz-server-side-encryption;
      proxy_hide_header      Set-Cookie;
      proxy_ignore_headers   Set-Cookie;
      proxy_cache_revalidate on;
      proxy_intercept_errors on;
      proxy_cache_use_stale  error timeout updating http_500 http_502 http_503 http_504;
      proxy_cache_lock       on;
      proxy_cache_valid      200 304 60m;
      add_header             Cache-Control max-age=31536000;
      add_header             X-Cache-Status $upstream_cache_status;
      proxy_pass             http://yanpy.dev.s3.amazonaws.com/;
    }

  }
}

2 votes

Cher Anatoly, merci pour votre travail. J'essaie de l'utiliser, mais il produit toujours un cache "MISS" alors que j'ajoute proxy_cache_valid 200 60m; J'espère que cela aidera quelqu'un.

0 votes

La configuration ci-dessus devrait fonctionner, je ne suis pas sûr de comprendre ce que vous entendez par problème aider quelqu'un, résolvons plutôt le problème :). Pouvez-vous joindre la commande curl et la configuration Nginx pour que je puisse la reproduire ?

0 votes

@OlegMykolaichenko Je rencontre le même problème. C'est toujours MISS. Avez-vous une idée de la raison pour laquelle il se comporte ainsi ?

5voto

Abhishek Ghosh Points 938

Sans connaître les détails des modules avec lesquels Nginx est compilé, nous pouvons dire qu'il existe deux façons d'ajouter les en-têtes Expires et Cache-Control à tous les fichiers.

Nginx S3 proxy

C'est ce que vous avez demandé : utiliser Nginx pour ajouter des en-têtes d'expiration et de contrôle du cache sur les fichiers S3.

Nginx ce set-misc-nginx-module nécessaire pour prendre en charge le proxy S3 de Nginx et modifier/ajouté l'expiration, le contrôle de cache à la volée. Il s'agit d'un guide complet standard de la compilation à l'utilisation, c'est excellent guide pour nginx-extras pour un serveur Ubuntu . C'est guide complet avec exemple avec WordPress .

Il y a plus de modules S3 pour des choses supplémentaires. Sans ces modules, Nginx ne pourra pas comprendre et configurer le test ( nginx -t ) passera le test avec une mauvaise configuration. set-misc-nginx-module est le minimum pour votre besoin. Ce que vous voulez a meilleur exemple sur ce gist Github .

Comme tous ne sont pas utilisés avec la compilation et que la configuration est vraiment un peu difficile, j'écris également la manière de définir les en-têtes Expires et Cache-Control pour tous les fichiers dans un seau Amazon S3.

En-tête Amazon S3 Bucket Expires et Cache-Control

Il est également possible de définir les en-têtes Expires et Cache-Control pour tous les objets d'un même seau AWS S3 avec script ou la ligne de commande. Il existe plusieurs bibliothèques et scripts gratuits de ce type sur Github. comme celui-ci , explorateur de seaux , L'outil d'Amazon , Amazon a ce document y ce document . La commande sera comme ceci pour cet outil CLI cp :

aws s3 cp s3://mybucket/ s3://mybucket/ --recursive --metadata-directive REPLACE \
--expires 2027-09-01T00:00:00Z --acl public-read --cache-control max-age=2000000,public

-4voto

cnst Points 1699

D'un point de vue architectural, ce que vous essayez de faire est une mauvaise façon de procéder :

  • Amazon S3 est vraisemblablement optimisé pour être un cache hautement disponible ; en introduisant une couche de proxy par-dessus, vous introduisez simplement un délai supplémentaire inutile et un énorme point de défaillance, et vous perdez également tous les avantages qui découleraient de S3.

  • Votre analyse des performances en ce qui concerne le nombre de fichiers est incorrecte. Si vous avez des milliers de fichiers sur S3, la solution correcte serait d'écrire un script unique pour changer les attributs requis sur S3, au lieu de dérouler manuellement un mécanisme de proxy que vous ne comprenez pas entièrement et qui serait exécuté de nombreuses fois (ad nauseam). La mise en place du proxy ne serait qu'un pansement et, en réalité, elle diminuerait les performances au lieu de les augmenter (même si un outil automatisé sans état vous dirait le contraire). Sans compter qu'il s'agirait également d'une consommation inutile de ressources, et que cela pourrait contribuer à des problèmes de performance et à des heisenbugs à terme.


Cela dit, si vous êtes toujours prêt à utiliser un proxy en ajoutant les en-têtes, la bonne façon de le faire avec nginx est d'utiliser la fonction expires directive.

Par exemple, vous pouvez placer expires max; avant ou après votre proxy_pass à l'endroit approprié.

El expires prend automatiquement en charge la définition d'un Cache-Control pour vous aussi ; mais vous pouvez aussi utiliser l'en-tête add_header si vous souhaitez ajouter manuellement des en-têtes de réponse personnalisés.

14 votes

Pour information, S3 est sans aucun doute hautement disponible, mais il n'est pas conçu comme un cache et son utilisation est relativement coûteuse pour les gros volumes. C'est pourquoi Amazon propose CloudFront avec le support de S3. Si vous avez l'intention de servir de gros volumes, vous ne devriez pas le faire directement à partir de S3. La mise en place d'une forme de cache n'est donc pas une mauvaise idée du tout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X