Como servir todos os arquivos estáticos existentes diretamente com NGINX, mas fazer proxy do resto em um servidor de back-end.

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;
        }
    }

Acima servirá todos os arquivos existentes diretamente usando Nginx (por exemplo, Nginx apenas exibe o código-fonte PHP), caso contrário, encaminhará uma solicitação ao Apache. Preciso excluir arquivos * .php da regra para que as solicitações para * .php também sejam passadas para o Apache e processadas.

Eu quero que o Nginx trate todos os arquivos estáticos e o Apache para processar todas as coisas dinâmicas.

EDIT: Existe uma abordagem de lista branca, mas não é muito elegante, veja todas essas extensões, eu não quero isso.

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: Em versões mais recentes do uso Nginx try_filesvez http://wiki.nginx.org/HttpCoreModule#try_files

Fmalina
fonte
Só para esclarecer as coisas: o código acima servirá um arquivo estático se existir no disco, se o arquivo não existir a solicitação é passada para o Apache. Isso funciona na maioria das vezes, pois todos os URLs em meus aplicativos usam mod_rewrite (ou roteamento) e não existem realmente no disco. Apenas o acesso direto ao nome de arquivo * .php é exceção e precisa ser analisado pelo Apache.
fmalina

Respostas:

152

Use try_files e bloco de localização nomeado ('@apachesite'). Isso removerá a correspondência de regex desnecessária e se bloquear. Mais eficiente.

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;
}

Update: O pressuposto desta configuração é que não existe nenhum script php sob /path/to/root/of/static/files. Isso é comum na maioria dos frameworks php modernos. No caso de seus projetos legados de php terem scripts php e arquivos estáticos misturados na mesma pasta, você pode ter que colocar na lista de permissões todos os tipos de arquivos que deseja que o nginx sirva.

Chuan Ma
fonte
Estou usando o wordpress, então devo colocar a pasta de upload no servidor nginx?
Chameron
7
Meu problema com esta solução: o nginx não usa o outro local (o proxy) e tenta mostrar a listagem do diretório. Portanto, ele lança um 403 porque a lista de diretórios não está ativada. Editar: Ok, se você remover, $uri/então funciona.
ChristophLSA
1
Isso faria proxy / exemplo para apache, mas permitiria o download de /example.php.
Terence Johnson,
1
@TerenceJohnson Não é seguro colocar seus arquivos php na pasta de arquivos estáticos. Observe que eu defini root /path/to/root/of/*static*/files;. Os arquivos php devem ser colocados em uma pasta diferente, não acessível diretamente da Internet.
Chuan Ma,
2
Eu sei que é assim que as coisas deveriam ser, mas se alguém está colocando o Nginx na frente de qualquer um dos muitos aplicativos PHP comuns que têm tudo sob a raiz da web e dependem de arquivos .htaccess, eles não devem copiar e cole sua configuração.
Terence Johnson,
18

Experimente isto:

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;
}

Espero que funcione. Expressões regulares têm maior prioridade do que strings simples, portanto, todas as solicitações que terminam em .phpdevem ser encaminhadas ao Apache se houver apenas um .phparquivo correspondente . O resto será tratado como arquivos estáticos. O algoritmo real de avaliação da localização está aqui .

Jasiu
fonte
6

Se você usa mod_rewrite para ocultar a extensão de seus scripts, ou se você apenas gosta de URLs bonitos que terminam em /, então você pode querer abordar isso de outra direção. Diga ao nginx para deixar qualquer coisa com uma extensão não estática passar para o apache. Por exemplo:

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;
}

Encontrei a primeira parte deste snippet em: http://code.google.com/p/scalr/wiki/NginxStatic

lo_fye
fonte
Isso funcionou muito bem, embora eu ainda receba erros para arquivos minificados (por exemplo, site.min.css e main.min.js etc). Como eu pegaria isso em uma regex de localização? @lo_fye
Garth