Nginx 리버스 프록시 + URL 재 작성


149

Nginx는 포트 80에서 실행 중이며이 방법 /foo으로 포트 경로 가있는 프록시 URL을 반대로 사용합니다 3200.

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

이것은 잘 작동하지만 port에 응용 프로그램 3200이 있는데 초기 응용 프로그램을 /foo보내고 싶지 않습니다 . 즉-에 액세스 할 때 앱에서받은 경로 http://localhost/foo/bar/bar되고 싶습니다 . 그래서 위의 위치 블록 에이 줄을 추가하려고했습니다.

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

이로 인해 302 리디렉션 (URL 변경)이 발생하지만 301을 원합니다. 어떻게해야합니까?


Grafana 케이스에 문제가있는 경우 다음 레시피를 사용해야합니다. docs.grafana.org/installation/behind_proxy/…
mohsen saeedi

답변:


168

로컬 호스트로의 리디렉션은 원격 시스템 (예 : 클라이언트의 웹 브라우저)에서 의미가 없습니다. 따라서 귀하의 경우 에는 다시 쓰기 플래그 영구 (301) 또는 리디렉션 (302)을 사용할 수 없습니다.

투명한 다시 쓰기 규칙을 사용하여 다음 설정을 시도하십시오.

location  /foo {
  rewrite /foo/(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}

curl -i다시 쓰기를 테스트하는 데 사용하십시오 . 규칙을 매우 미세하게 변경하면 nginx가 리디렉션을 수행 할 수 있습니다.


1
내가 할 때 URL 경로는 여전히 내 응용 프로그램에서 / foo로 시작합니다 ...
jeffreyveon

다른 문제가 있어야합니다. 몇 분 전에이 시나리오를 성공적으로 재현했습니다. 원래 URL : HTTP : // 개발 / foo는 / testme라는 / 1234 - 프록시 백엔드로 연결된 아파치에서 실행되는 PHP 스크립트의 REQUEST_URI '/ testme라는 / 1234'
옌스 Bradler

9
정규식은 아마이어야 /foo(.*)하며 그렇지 않으면 example.com/foo일치하지 않아야합니다. (아마도 jeffreyveon이 경험 한 것입니다)
Benno

이런 종류의 작품이지만 proxy_set_body로 설정하고있는 내 몸은 제거되고 있습니다.
Justin Thomas

/(.*) /socket.io/ break를 다시 작성하십시오. SOCKET.IO를위한 나의 하루를 보내십시오
user956584

123

proxy_pass 지시문에 URI를 지정하는 한 재 작성 규칙을 사용하지 않고 간단한 위치 접두사 일치가 작동합니다.

location /foo {
  proxy_pass http://localhost:3200/;
}

지시문 /끝에 추가 내용 을 확인하십시오 proxy_pass. NGINX는 일치하는 접두사를 제거하고 /foo나머지를 URI의 백엔드 서버로 전달합니다 /. 따라서에 http://myserver:80/foo/bar백엔드에 게시합니다 http://localhost:3200/bar.

proxy_passNGINX 문서에서 :

proxy_pass 지시문이 URI로 지정된 경우 요청이 서버로 전달되면 위치와 일치하는 정규화 된 요청 URI 부분이 지시문에 지정된 URI로 대체됩니다.


12
/ foo / {위치에 추가 한 것보다 나를 위해
Andrei N

이것은 내가 찾던 것입니다!
anbiniyar

6
이것은 매우 깨끗한 해결책입니다.이 질문에 대한 정식 답변보다 선호합니다.
ralien

2
후행 슬래시를 유지하거나 제거하는 것이 중요하다는 것을 깨닫기에는 너무 오래 걸렸습니다.
Parvez

5
그렇게하면 실제로 //xyz호스트로 전달 됩니다.
Archimedes Trajano

60

가장 정확한 방법과 모범 사례는 일반적으로 다음과 같습니다.

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • 후행 슬래시 inproxy_pass 의 심각성이 중요 $uri합니다 /foo/. 그러면 프런트 엔드 /의 백엔드 와 일치 하도록 변수가 자동으로 변경됩니다 . 명시 적 rewrite지시문이 필요하지 않습니다 .

  • 또한, 상기 참고 후행 /에이location 하나의 점 (예를 들어, 작업에서 귀하의 사이트에 이상한 보이는 URL을 위험을 감수, 그것없이 - 물론 매우 중요하다 /fooen첨가에서 /foo/en).

    또한, 후행 /에서 locationproxy_pass도 어떤 보장 특수 처리 의 문서에 따라, location, 지시 효과적으로 암시을 일으킬 location = /foo {return 301 /foo/;}뿐만 아니라.

    따라서 location위와 같이 슬래시를 사용하여을 정의하면 슬래시없는 접미사 URL /fooen이 유효하지 않을뿐만 아니라 /foo뒤에 슬래시가없는 것도 계속 작동합니다.


참조 문서 :


$args잃어버린 것 같습니다 : http://frontend/foo?bar=baz로 프록시됩니다 http://backend/. 인수는 URL의 일부가 아닙니다.
Vanuan

@Vanuan, 확실합니까? $args위 코드를 사용하는 경우 $uri와 별개 이므로 명시 적으로 변수를 사용하지 않는 한 다시 올바르게 처리해야한다고 확신 합니다 proxy_pass.
cnst November

@cnst 아, 알겠습니다. 호스트 변수를 사용하고 있습니다. 그것은 직관적 인 카운터입니다.
Vanuan

1
@ArchimedesTrajano, 당신은 /foo리디렉션 할 수있는 특별한 처리가 있기 때문에 잘못 되었습니다 /foo/. 따라서 백엔드에서 이상한 일을하지 않으면 /foo요청 조차도 위의 코드로 계속 작동합니다. (이것은 실제로 BTW의 답변의 일부입니다.)
cnst

3
이 솔루션은 이러한 모든 포럼에서 승리하는 것으로 간주되지만 Nginx는 URL을 URL 디코딩하고 디코딩 된 URL을 프록시 서버로 전달한다는 답변에 주목해야합니다. 따라서 URL에 URL 인코딩 된 부분이 있으면이 솔루션이 작동하지 않습니다.
코딩

1

시험

location /foo {
    proxy_pass http://localhost:3200/;
    ....

또는

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....

13
위와 같이 구성해야하는 이유를 설명하면이 답변이 좋습니다.
masegaloeh

그렇게하면 실제로 //xyz호스트로 전달 됩니다.
Archimedes Trajano

1

@Terabuck 아직 답글을 보내지 않은 것에 대해 죄송합니다.

응용 프로그램이 호스트 파일이있는 서버에서 실행되고 있다는 사실에 의존하기 때문에 localhost를 사용하지 않아야합니다. 로컬 호스트는 기본적으로 127.0.0.1로 변환됩니다. 이 호스트 파일이 있어야한다는 내용은 없습니다. 하나를 갖는 것이 매우 일반적입니다.

루프백 인터페이스를 갖는 것은 다시 의존해야 할 또 다른 일반적인 사항이지만 여전히 네트워킹 스택의 루프백 인터페이스에 의존합니다. 이 두 가지가없는 드문 경우입니다. 당신이 이것에 대해 걱정한다면. 적어도 유닉스 / 리눅스에서는 소켓 옵션이 있습니다. 따라서 네트워크 스택이 로컬 호스트에 도달 할 필요가 없습니다. 호스트 OS에서 발생할 수있는 몇 가지 요소가 있으므로이 방법에주의하십시오. 열린 파일 수 등과 같은

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.