如何解决Swagger在Ubuntu生产服务器上无法正常运行的问题?
生产环境Swagger无法访问的排查与修复
环境信息
- 开发环境:Windows 11 Pro x64、JDK/Java 19、Spring Boot 2.7.4
- 生产环境:Ubuntu 22.04.1 LTS、Oracle JDK/Java 19、Nginx 1.18.0
问题描述
开发环境中Swagger可正常访问,但生产服务器上完成Nginx反向代理配置、Swagger路径设置、Spring Security放行规则配置后,Swagger仍无法正常工作。
当前配置详情
Nginx配置(/etc/nginx/conf.d/mydomain.com.conf)
server { listen 80; listen [::]:80; server_name mydomain.com; location / { # proxy_pass http://localhost:8081/; proxy_pass http://localhost:8081/swagger-ui/index.html; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; } }
application.properties配置
server.port=8081 spring.datasource.url=jdbc:postgresql://103.48.xxx.xxx:5432/fooXXX spring.datasource.username=MySecretUser spring.datasource.password=MyScret spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true # Application properties app.jwtSecret=pXpYPZ8d8FQv7UDepXpYPZ8d8FQv7UDegMxYPZ8d8FQv7UDepXpYPZ8d8FQv7UDepXpYPZ8d8FQv7UDepXpYPZ8d8FQv7UDe app.jwtExpirationMs=86400000 # swagger-ui custom path. Run ok. # http://localhost:8081/swagger-ui/index.html springdoc.swagger-ui.path=/swagger-ui.html springdoc.packagesToScan=com.example.controller, com.example.controllers #logging.level.root=ERROR logging.level.root=INFO # Write logs to the current directory. logging.file.path=./log #spring.sql.init.mode=always #spring.jpa.defer-datasource-initialization=true #spring.jpa.hibernate.ddl-auto=none
Spring Security配置类
package com.example.security; import com.example.security.jwt.AuthEntryPointJwt; import com.example.security.jwt.AuthTokenFilter; import com.example.security.services.UserDetailsServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsServiceImpl userDetailsService; @Autowired private AuthEntryPointJwt unauthorizedHandler; @Bean public AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); } @Override public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests().antMatchers("/api/auth/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll() .antMatchers("/app/**").permitAll() .antMatchers("/api/test/**").permitAll() .anyRequest().authenticated(); http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); } }
生产服务器hosts配置
127.0.0.1 localhost 127.0.1.1 localhost 127.0.0.1 mydomain.com 127.0.0.1 www.mydomain.com 103.48.YYY.XXX mydomain.com # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 103.48.YYY.XXX vypc.foo.net vypc
解决方法
1. 修正Nginx反向代理配置
当前Nginx的location /直接代理到Swagger的index.html,会导致Swagger依赖的JS、CSS等静态资源无法正确加载。应改为代理根路径,让Nginx转发所有请求到Spring Boot应用,由应用自行处理路由:
server { listen 80; listen [::]:80; server_name mydomain.com; location / { proxy_pass http://localhost:8081/; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; } }
修改后重启Nginx:sudo systemctl restart nginx
2. 启用生产环境Swagger开关
Spring Boot默认会在生产环境禁用Swagger,需在application.properties中手动开启:
springdoc.swagger-ui.enabled=true springdoc.api-docs.enabled=true # 适配反向代理的基础路径 springdoc.swagger-ui.base-url=/
3. 补全Spring Security放行路径
当前配置遗漏了Swagger静态资源的放行规则,需补充相关路径:
.authorizeRequests().antMatchers("/api/auth/**", "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").permitAll()
4. 排查网络与域名解析问题
- 确认服务器8081端口对外开放:
sudo ufw allow 8081(使用ufw防火墙时) - 在服务器本地测试Swagger可用性:
curl http://localhost:8081/swagger-ui.html,若返回正常HTML内容,说明应用本身无问题 - 清理hosts文件冲突映射:
127.0.0.1 mydomain.com与公网IP映射共存可能导致解析异常,建议保留公网IP映射,删除本地回环映射
5. 查看日志定位问题
- 查看Nginx错误日志:
sudo tail -f /var/log/nginx/error.log,检查代理请求是否失败 - 查看Spring Boot应用日志:
tail -f ./log/spring.log,检查是否有认证拦截或资源访问被拒绝的记录
内容的提问来源于stack exchange,提问作者Đỗ Như Vỹ
相关产品推荐
相关产品推荐

