You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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ỹ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:40:49