2010-01-12 3 views
12

Je me déplace mon site loin de Apache et sur Nginx, et je vais avoir des problèmes avec ce scénario:Nginx Proxy aux fichiers sur le disque local ou S3

utilisateur télécharge une photo. Cette photo est redimensionnée, puis copiée en S3. S'il y a une pièce appropriée sur le disque (ou si le fichier ne peut pas être transféré sur S3), une version locale est conservée.

Je souhaite que les demandes de ces images (telles que http://www.mysite.com/p/1_1.jpg) soient examinées dans le répertoire p /. Si aucun fichier local n'existe, je veux envoyer la requête à S3 et rendre l'image (mais pas rediriger).

Dans Apache, je l'ai fait comme ceci:

RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^p/([0-9]+_[0-9]+\.jpg)$ http://my_bucket.s3.amazonaws.com/$1 [P,L] 

Ma tentative de reproduire ce comportement dans Nginx est ceci:

location /p/ { 
    if (-e $request_filename) { 
     break; 
    } 
    proxy_pass http://my_bucket.s3.amazonaws.com/; 
} 

Ce qui se passe est que chaque demande tente de frapper Amazon S3, même si le fichier existe sur le disque (et s'il n'existe pas sur Amazon, j'obtiens des erreurs.) Si je supprime la ligne proxy_pass, alors les demandes de fichiers sur le disque fonctionnent.

Des idées pour résoudre ce problème?

+0

Pouvez-vous partager le fichier virual.conf. – Thoman

Répondre

33

Si ce pas un exemple d'utilisation try_files?

location /p/ { 
    try_files $uri @s3; 
} 

location @s3{ 
    proxy_pass http://my_bucket.s3.amazonaws.com; 
} 

Assurez-vous qu'il n'y a pas une barre oblique suivante sur l'url S3

+0

Bonne réponse! Solution claire et simple. Merci! –

0

break est de ne pas faire tout à fait ce que vous attendez nginx fera la dernière chose que vous demandez, ce qui est logique si vous commencez à creuser autour de faire des modules ... mais essentiellement protéger votre proxy_pass avec le ne-not-exist Version

if (-f $request_filename) { 
    break; 
} 
if(!-f $request_filename) 
    proxy_pass http://s3; 
} 
+3

J'ai essayé cela au début, mais Nginx ne démarrera pas si j'ai le 'http: // my_bucket.s3.amazonaws.com /' complet dans l'appel 'proxy_pass'. Je reçois l'erreur suivante: 'Redémarrage nginx: 2010/01/11 20:53:36 [émerg] 1485 # 0:" proxy_pass "peut ne pas avoir une partie URI dans l'emplacement donné par l'expression régulière, ou à l'intérieur de l'emplacement nommé, ou à l'intérieur de l'instruction "if", ou à l'intérieur du bloc "limit_except" dans /etc/nginx/sites-enabled/my_site.com: 39' Si je supprime la barre oblique, Nginx démarre, mais mes requêtes ne sont pas routées correctement plus. Des idées? – Coomer

0

J'ai fini par résoudre en vérifiant si le fichier n'existe pas, et si oui, la réécriture de cette demande. Je puis traiter la demande réécrite et faire le proxy_pass là, comme ceci:

location /p/ { 
    if (!-f $request_filename) { 
    rewrite ^/p/(.*)$ /ps3/$1 last; 
    break; 
    } 
} 

location /ps3/ { 
    proxy_pass http://my_bucket.s3.amazonaws.com/; 
} 
+2

Le 'if' de nginx a un comportement très imprévisible. Même si cela fonctionne bien, il est recommandé d'utiliser 'try_files' autant que possible, comme dans la réponse de Dan Gayle. Vérifiez http://wiki.nginx.org/IfIsEvil pour les subtilités de 'if'. –

12

Vous pouvez améliorer votre config proxy s3 comme celui-ci. Adapté de https://stackoverflow.com/a/44749584:

location /p/ { 
    try_files $uri @s3; 
} 

location @s3 { 
    set $s3_bucket  'your_bucket.s3.amazonaws.com'; 
    set $url_full   '$1'; 

    proxy_http_version  1.1; 
    proxy_set_header  Host $s3_bucket; 
    proxy_set_header  Authorization ''; 
    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; 

    resolver    8.8.4.4 8.8.8.8 valid=300s; 
    resolver_timeout  10s; 
    proxy_pass    http://$s3_bucket$url_full; 
} 
2

Merci de garder mon poste coderwall :) Aux fins de la mise en cache, vous pouvez l'améliorer un peu:

http { 

    proxy_cache_path   /tmp/cache levels=1:2 keys_zone=S3_CACHE:10m inactive=24h max_size=500m; 
    proxy_temp_path   /tmp/cache/temp; 

    server { 
    location ~* ^/cache/(.*) { 
     proxy_buffering  on; 
     proxy_hide_header  Set-Cookie; 
     proxy_ignore_headers Set-Cookie; 
     ... 
     proxy_cache   S3_CACHE; 
     proxy_cache_valid  24h; 
     proxy_pass    http://$s3_bucket/$url_full; 
    } 
    } 

} 

Une autre recommandation est d'étendre le cache de résolution jusqu'à 5 min:

resolver     8.8.4.4 8.8.8.8 valid=300s; 
resolver_timeout   10s; 
+1

Vous n'avez pas besoin d'une barre oblique dans la directive ** proxy_pass **, c'est très important. Cela devrait ressembler à ceci: 'proxy_pass http: // $ s3_bucket $ url_full;' –

Questions connexes