티스토리 뷰

반응형

개요 / 문제

기존에 Spring fox를 사용하다가 deprecated 되어 springdoc openapi를 도입하게 되었습니다.

Swggger 인터페이스는 두 라이브러리 다 맞추고 있었기에 의존성 교체와 몇가지 수정만으로도 대체가 가능했는데요.

 

근데 막상 개발서버에 배포를 해보니 다음 사진처럼 Failed to load remote configuration. 메시지와 함께 Swagger 실행이 불가능한 문제가 발생했습니다.

 

뭔가 요청이 제대로 전달되지 않은 것 같아 Chrome 개발자 도구로 확인해보니 Swagger 리소스에 대한 접근이 제대로 되지 않고 있는 것을 발견했습니다.

 

위 문제를 해결하기 위해 이슈를 찾기 시작했습니다.

 


원인 파악하기

1. swagger-config 접근 허용하기

제가 운영하는 애플리케이션은 Spring security로 특정 엔드포인트를 제외하고는 인증이 필요하도록 구성되어져 있습니다.

이런 경우 Springdoc-openapi 도입 시, Swagger 리소스로의 접근이 불가능해지기 때문에 이와 관련된 엔드포인트들은 Spring security 로직을 타지 않도록 구성해야 합니다.

 

제 애플리케이션에서는 다음과 같이 설정되어져 있습니다.

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return web -> web.ignoring().requestMatchers("/h2-console/**",
                                                 "/favicon.ico",
                                                 "/error",
                                                 "/swagger-ui/**",
                                                 "/swagger-resources/**",
                                                 "/v3/api-docs/**");
}

저는 이전부터 Swagger를 사용하고 있었기에 이에 대한 설정이 이미 반영되어져있었는데요. 그러다보니 이 해결방법으로는 문제를 해결할 수 없었습니다.

 

 

2. Reverse Proxy Configuration 확인하기

뭐가 문젤까 하며 오랜 시간 여러가지 찾아보았습니다. 그러던 중, 위 문제 사진에서 이상한 점을 발견했습니다.

 

저는 개발서버의 Swagger를 확인하기 위해 {base-url}/dev/swagger-ui/index.html 로 요청을 보낸 상황이었습니다.

근데 Swagger 리소스를 위해 {base-url}/v3/api-docs/swagger-config 엔드포인트로 접근하고 있었습니다.

위 주소로 접근하면 당연히 제대로 된 Swagger 리소스를 읽을 수가 없습니다. 그래서 404가 오류가 나고 있던 것입니다.

 

이걸 이해시켜드리기 위해선 먼저 서비스 인프라 상황을 이야기드려야 할 것 같네요.

제 서비스 인프라는 단일 엔드포인트를 제공하기 위해 Nginx를 Reverse Proxy로 구성하여 활용하고 있습니다. 도메인 주소 다음 /prd 가 붙으면 실제 상용 서비스 서버로 요청을 전달하고, /dev 가 붙으면 개발 서비스 서버로 요청이 전달됩니다.

 

결국 현재 서비스 인프라 상에서 (위 Swagger config 주소같이) 이러한 profile이 붙지 않는 도메인 주소는 유효한 주소가 아닙니다. 그렇기에 404 오류가 나고 있던 것 입니다.

 


해결하기

이를 해결하기 위해서는 Swagger 리소스를 읽어올 때 전달된 올바른 profile이 붙은 도메인 주소로 요청이 가야합니다.

확실하지는 않지만 springdoc-openapi에서 Swagger 리소스를 읽어올 base 주소를 Host로 설정하는 것 같아 보입니다. 그러면 여기에 profile prefix를 어떻게 추가할 수 있을까요?

 

이에 대한 해결은 springdoc 이슈에 이미 올라와있었습니다.

 

X-Forwarded-Prefix 헤더가 핵심이었습니다. 이 헤더가 존재하면 Swagger 단에서 이를 활용해 {base-url}/prefix 를 host로 잡고 Swagger 리소스 등의 요청을 전달하게 되는 것입니다.

Nginx에서 이를 간단하게 설정할 수 있는데요. proxy_set_header 를 이용하면 됩니다.

아래 제 예시를 참고해주세요.

server {
  listen 443 ssl http2;

    ...

  location /dev/ {
    rewrite ^/dev(/.*)$ $1 break;
    proxy_pass http://base-url;
        proxy_set_header X-Forwarded-Prefix /dev; # 여기 부분을 참고하세요
        ...
  }
    ...
}

 

여기에 추가적으로 해주어야하는 작업이 있습니다.

X-Forwarded 는 Reverse proxy 이용 시 많이 활용되는 헤더(Prefix)이지만, 사실 Official 한 HTTP 정식 헤더는 아닙니다. 즉, Custom HTTP Header 입니다.

그렇기에 Spring boot에서 해당 헤더를 기본적으로는 다루지 않습니다.

이를 다루기 위해서 다음과 같은 Property 설정이 필요합니다.

# .properties
server.forward-headers-strategy=FRAMEWORK

# OR

# .yml
server:
  forward-headers-strategy: FRAMEWORK

 

만약 Property 설정보다 Bean으로 등록하는 것을 선호하신다면, 다음과 같이 ForwardedHeaderFilter Bean을 등록해도 됩니다.

@Bean
ForwardedHeaderFilter forwardedHeaderFilter() {
   return new ForwardedHeaderFilter();
}

 

이와 관련해서 springdoc-openapi 프로젝트의 테스트 코드도 참조해보면 좋습니다.

https://github.com/springdoc/springdoc-openapi/blob/main/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app32/SpringDocBehindProxyTest.java


여기까지 Reverse proxy 상황에서 springdoc-openapi 사용하며 겪은 이슈를 해결해보았습니다.

혹시 잘못된 부분이 있다면 편하게 의견부탁드립니다.

읽어주셔서 감사합니다.

 

 
320x100
반응형
댓글
반응형
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함