Comment servir tous les fichiers statiques existants directement avec NGINX, mais proxy le reste vers un serveur backend.

87
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    if (-f $request_filename) {
        access_log off;
        expires 30d;
        break;
        }

    if (!-f $request_filename) {
        proxy_pass http://127.0.0.1:8080; # backend server listening
        break;
        }
    }

Ci-dessus servira tous les fichiers existants directement en utilisant Nginx (par exemple, Nginx n'affiche que le code source PHP), sinon transmettez une requête à Apache. Je dois exclure les fichiers * .php de la règle afin que les demandes de * .php soient également transmises à Apache et traitées.

Je veux que Nginx gère tous les fichiers statiques et qu'Apache traite tous les éléments dynamiques.

EDIT: Il y a une approche de liste blanche, mais ce n'est pas très élégant, voir toutes ces extensions, je ne veux pas de ça.

location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
    access_log off;
    expires 30d;
    }
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
    }

EDIT 2: Sur les versions plus récentes de Nginx, utilisez try_filesplutôt http://wiki.nginx.org/HttpCoreModule#try_files

fmalina
la source
Juste pour clarifier les choses: le code ci-dessus servira un fichier statique s'il existe sur le disque, si le fichier n'existe pas, la requête est transmise à Apache. Cela fonctionne la plupart du temps car toutes les URL de mes applications utilisent mod_rewrite (ou routage) et n'existent pas vraiment sur le disque. Seul l'accès direct au nom de fichier * .php fait exception et doit être analysé par Apache.
fmalina

Réponses:

152

Utilisez try_files et le bloc d'emplacement nommé ('@apachesite'). Cela supprimera la correspondance regex inutile et si le bloc. Plus efficace.

location / {
    root /path/to/root/of/static/files;
    try_files $uri $uri/ @apachesite;

    expires max;
    access_log off;
}

location @apachesite {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

Mise à jour: L'hypothèse de cette configuration est qu'il n'existe aucun script php sous /path/to/root/of/static/files. Ceci est courant dans la plupart des frameworks PHP modernes. Dans le cas où vos projets php hérités ont à la fois des scripts php et des fichiers statiques mélangés dans le même dossier, vous devrez peut-être mettre en liste blanche tous les types de fichiers que vous souhaitez que nginx serve.

Chuan Ma
la source
J'utilise wordpress, devrais-je donc avoir besoin de mettre le dossier de téléchargement sur le serveur nginx?
Chameron
7
Mon problème avec cette solution: nginx n'utilise pas l'autre emplacement (le proxy) et essaie d'afficher la liste du répertoire. Donc, il lance un 403 car la liste des répertoires n'est pas activée. Edit: Ok si vous supprimez, $uri/cela fonctionne.
ChristophLSA
1
Cela donnerait un proxy / exemple à Apache mais permettrait le téléchargement de /example.php.
Terence Johnson
1
@TerenceJohnson Il n'est pas sûr de placer vos fichiers php dans le dossier des fichiers statiques. Notez que j'ai mis root /path/to/root/of/*static*/files;. Les fichiers php doivent être placés dans un dossier différent, non directement accessible depuis Internet.
Chuan Ma
2
Je sais que c'est ainsi que les choses devraient être, mais si quelqu'un met Nginx devant l'une des nombreuses applications PHP courantes qui ont tout sous la racine Web et reposent sur des fichiers .htaccess, ils ne devraient pas copier et collez votre configuration.
Terence Johnson
18

Essaye ça:

location / {
    root /path/to/root;
    expires 30d;
    access_log off;
}

location ~* ^.*\.php$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

Espérons que cela fonctionne. Les expressions régulières ont une priorité plus élevée que les chaînes simples, donc toutes les requêtes se terminant par .phpdoivent être transmises à Apache si seul un .phpfichier correspondant existe. Le reste sera traité comme des fichiers statiques. L'algorithme réel d'évaluation de l'emplacement est ici .

Jasiu
la source
6

Si vous utilisez mod_rewrite pour masquer l'extension de vos scripts, ou si vous aimez simplement les jolies URL qui se terminent par /, vous voudrez peut-être aborder cela dans l'autre sens. Dites à nginx de laisser tout ce qui a une extension non statique passer à apache. Par exemple:

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$
{
    root   /path/to/static-content;
}

location ~* ^!.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

J'ai trouvé la première partie de cet extrait sur: http://code.google.com/p/scalr/wiki/NginxStatic

lo_fye
la source
Cela a très bien fonctionné, même si j'obtiens toujours des erreurs pour les fichiers minifiés (par exemple site.min.css et main.min.js, etc.). Comment les attraperais-je dans une expression régulière de localisation? @lo_fye
Garth