Yes, there is a Spring way of doing this:

Step 1. Adding an additional Tomcat connector

To add a port to the embedded server an additional connector needs to be configured. We will do it by providing custom WebServerFactoryCustomizer:

@Component
public class TomcatContainerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Value("${swagger.port}")
    private int swaggerPort;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        Connector swaggerConnector = new Connector();
        swaggerConnector.setPort(swaggerPort);
        factory.addAdditionalTomcatConnectors(swaggerConnector);
    }
}

Now Tomcat listens on two ports but it serves the same content on both of them. We need to filter it.

Step 2. Adding a filter

Adding a servlet filter is pretty straightforward with a FilterRegistrationBean. It can be created anywhere, I added it directly to the TomcatContainerCustomizer.

@Component
public class TomcatContainerCustomizer  implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Value("${swagger.port}")
    private int swaggerPort;

    @Value("${swagger.paths}")
    private List<String> swaggerPaths;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        Connector swaggerConnector = new Connector();
        swaggerConnector.setPort(swaggerPort);
        factory.addAdditionalTomcatConnectors(swaggerConnector);
    }

    @Bean
    public FilterRegistrationBean<SwaggerFilter> swaggerFilterRegistrationBean() {

        FilterRegistrationBean<SwaggerFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new SwaggerFilter());
        filterRegistrationBean.setOrder(-100);
        filterRegistrationBean.setName("SwaggerFilter");

        return filterRegistrationBean;
    }

    private class SwaggerFilter extends OncePerRequestFilter {

        private AntPathMatcher pathMatcher = new AntPathMatcher();

        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        FilterChain filterChain) throws ServletException, IOException {

            boolean isSwaggerPath = swaggerPaths.stream()
                    .anyMatch(path -> pathMatcher.match(path, httpServletRequest.getServletPath()));
            boolean isSwaggerPort = httpServletRequest.getLocalPort() == swaggerPort;

            if(isSwaggerPath == isSwaggerPort) {
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            } else {
                httpServletResponse.sendError(404);
            }
        }
    }
}

The properties swagger.port and swagger.paths are configured in the application.yaml:

server.port: 8080
swagger:
  port: 8088
  paths: |
    /swagger-ui.html,
    /webjars/springfox-swagger-ui/**/*,
    /swagger-resources,
    /swagger-resources/**/*,
    /v2/api-docs

So far so good: the swagger-ui is served on the port 8088, our api on the 8080. But there is a problem: when we try to connect to the api from the swagger-ui, the requests are sent to the 8088 instead of 8080.

Step 3. Adjusting SpringFox config.

Swagger assumes that the api runs on the same port as the swagger-ui. We need to explicitly specify the port:

@Value("${server.port}")
private int serverPort;

@Bean
public Docket docket() {
    return new Docket(DocumentationType.SWAGGER_2)
            .host("localhost:" + serverPort);
}

And the last problem: as the ui runs on a different port than the api, the requests are considered cross-origin. We need to unblock them. It can be done globally:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**/*").allowedOrigins("http://localhost:" + swaggerPort);
        }
    };
}

or by adding annotations to the controllers:

@CrossOrigin(origins = "http://localhost:${swagger.port}")

Versions used: SpringBoot 2.2.2.RELEASE, springfox-swagger2 2.9.2

For a working example see https://github.com/mafor/swagger-ui-port

Answer from Mafor on Stack Overflow
Top answer
1 of 2
6

Yes, there is a Spring way of doing this:

Step 1. Adding an additional Tomcat connector

To add a port to the embedded server an additional connector needs to be configured. We will do it by providing custom WebServerFactoryCustomizer:

@Component
public class TomcatContainerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Value("${swagger.port}")
    private int swaggerPort;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        Connector swaggerConnector = new Connector();
        swaggerConnector.setPort(swaggerPort);
        factory.addAdditionalTomcatConnectors(swaggerConnector);
    }
}

Now Tomcat listens on two ports but it serves the same content on both of them. We need to filter it.

Step 2. Adding a filter

Adding a servlet filter is pretty straightforward with a FilterRegistrationBean. It can be created anywhere, I added it directly to the TomcatContainerCustomizer.

@Component
public class TomcatContainerCustomizer  implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Value("${swagger.port}")
    private int swaggerPort;

    @Value("${swagger.paths}")
    private List<String> swaggerPaths;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        Connector swaggerConnector = new Connector();
        swaggerConnector.setPort(swaggerPort);
        factory.addAdditionalTomcatConnectors(swaggerConnector);
    }

    @Bean
    public FilterRegistrationBean<SwaggerFilter> swaggerFilterRegistrationBean() {

        FilterRegistrationBean<SwaggerFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new SwaggerFilter());
        filterRegistrationBean.setOrder(-100);
        filterRegistrationBean.setName("SwaggerFilter");

        return filterRegistrationBean;
    }

    private class SwaggerFilter extends OncePerRequestFilter {

        private AntPathMatcher pathMatcher = new AntPathMatcher();

        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        FilterChain filterChain) throws ServletException, IOException {

            boolean isSwaggerPath = swaggerPaths.stream()
                    .anyMatch(path -> pathMatcher.match(path, httpServletRequest.getServletPath()));
            boolean isSwaggerPort = httpServletRequest.getLocalPort() == swaggerPort;

            if(isSwaggerPath == isSwaggerPort) {
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            } else {
                httpServletResponse.sendError(404);
            }
        }
    }
}

The properties swagger.port and swagger.paths are configured in the application.yaml:

server.port: 8080
swagger:
  port: 8088
  paths: |
    /swagger-ui.html,
    /webjars/springfox-swagger-ui/**/*,
    /swagger-resources,
    /swagger-resources/**/*,
    /v2/api-docs

So far so good: the swagger-ui is served on the port 8088, our api on the 8080. But there is a problem: when we try to connect to the api from the swagger-ui, the requests are sent to the 8088 instead of 8080.

Step 3. Adjusting SpringFox config.

Swagger assumes that the api runs on the same port as the swagger-ui. We need to explicitly specify the port:

@Value("${server.port}")
private int serverPort;

@Bean
public Docket docket() {
    return new Docket(DocumentationType.SWAGGER_2)
            .host("localhost:" + serverPort);
}

And the last problem: as the ui runs on a different port than the api, the requests are considered cross-origin. We need to unblock them. It can be done globally:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**/*").allowedOrigins("http://localhost:" + swaggerPort);
        }
    };
}

or by adding annotations to the controllers:

@CrossOrigin(origins = "http://localhost:${swagger.port}")

Versions used: SpringBoot 2.2.2.RELEASE, springfox-swagger2 2.9.2

For a working example see https://github.com/mafor/swagger-ui-port

2 of 2
0

I don't think so. When you're setting the Spring Boot management port (management.server.port), a second application server gets started to serve the actuator stuff. As far as I know there is no possibility (apart from custom actuator endpoints) to publish something on that server.
What is your use case exactly? Do you want to prevent access to Swagger in production or for non-authenticated users?

🌐
GitHub
github.com › mafor › swagger-ui-port
GitHub - mafor/swagger-ui-port: Serving SpringFox' swagger-ui from a separate port.
@Component public class TomcatContainerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Value("${swagger.port}") private int swaggerPort; @Override public void customize(TomcatServletWebServerFactory factory) { Connector swaggerConnector = new Connector(); swaggerConnector.setPort(swaggerPort); factory.addAdditionalTomcatConnectors(swaggerConnector); } }
Author   mafor
🌐
automateNow
automatenow.io › home › easy swagger-spring boot integration
Easy Swagger-Spring Boot Integration | automateNow
June 18, 2024 - Add the following line to specify a new port (for example, port 8081): ... After that, run the application again. Swagger automatically creates interactive API docs from your Spring Boot application, making it easier for developers to understand ...
🌐
GitHub
github.com › springdoc › springdoc-openapi › issues › 923
exposing swagger-ui on the management port · Issue #923 · springdoc/springdoc-openapi
November 3, 2020 - If it is set to true then expose the swagger ui using the management port.
Author   flamestro
🌐
DEV Community
dev.to › raviyasas › enable-swagger2-with-spring-boot-4dp8
Enable Swagger2 with Spring Boot - DEV Community
June 8, 2021 - Now you are ready. Your REST controllers are now available on Swagger 2. You can access the Swagger documentation via http://localhost:8090/swagger-ui.html You may change the port with the port your application is running.
🌐
Medium
medium.com › @akshitaswami248 › swagger-configuration-in-spring-boot-application-8558492df54b
Swagger Configuration in Spring Boot Application | by Akshitaswami | Medium
July 10, 2023 - Swagger Configuration in Spring Boot Application Below are the steps to configure swagger in spring boot application. Step1: Add below dependencies in pom.xml …
🌐
SpringDoc
springdoc.org › faq.html
F.A.Q
Since Spring Boot 2.2, this is the new property to handle reverse proxy headers: ... If you need to manually adjust the URL displayed in the Swagger UI, implement the ServerBaseUrlCustomizer interface. This might be necessary to remove the port number, for example.
Find elsewhere
🌐
Baeldung
baeldung.com › home › spring › spring boot › change swagger-ui url prefix
Change Swagger-UI URL prefix - Spring Boot
May 11, 2024 - Now let’s say we want to change this URL to http://localhost:8080/myproject/swagger-ui/index.html. Let’s review two approaches that can help us achieve it. Similar to the above example for SpringDoc, adding the following property in the application.properties file will help us change it successfully:
🌐
GitHub
github.com › springfox › springfox › issues › 1387
How to set port? · Issue #1387 · springfox/springfox
July 13, 2016 - This is Springfox sample. https://staging.jakduk.com:8080/swagger-ui.html#!/게시판/getPostsUsingGET It used 8080 port. But, request URL not use 8080 port. https://staging.jakduk.com/api/board/free/posts?category=ALL ...
Author   Pyohwan
🌐
Javatpoint
javatpoint.com › spring-boot-change-port
Spring Boot Change Port
May 30, 2014 - SB Change Port - Spring Boot Change Port with Introduction, Features, Project, Starter Project Wizard, CLI, Application, Annotations, DM, Properties, Actuator, Thymeleaf View, JPA, JDBC etc
🌐
Baeldung
baeldung.com › home › rest › setting up swagger 2 with a spring rest api using springfox
Setting Up Swagger 2 with a Spring REST API | Baeldung
November 12, 2025 - To do so, we have to use the @EnableSwagger2 on our configuration class: @Configuration @EnableSwagger2 public class SpringFoxConfig { } Additionally, without Spring Boot, we don’t have the luxury of auto-configuration of our resource handlers.
🌐
Baeldung
baeldung.com › home › spring › spring boot › how to change the default port in spring boot
How to Change the Default Port in Spring Boot | Baeldung
July 25, 2025 - The fastest and easiest way to customize Spring Boot is by overriding the values of the default properties. For the server port, the property we want to change is server.port.
🌐
iGreenData
igreendata.com.au › home › blogs › configuring swagger in spring boot application
Configuring Swagger in Spring Boot Application - iGreenData
October 7, 2021 - Import it as a Maven project in your IDE. I have chosen Eclipse for this demo. ... Note: For Spring boot 3 version, adding “springfox-boot-starter” dependency is enough and we don’t need to add swagger ui dependency and also not to include @EnableSwagger2 in the starter class.
🌐
CodingNConcepts
codingnconcepts.com › spring-boot › how-to-configure-swagger
How to configure Swagger in spring boot - Coding N Concepts
September 4, 2020 - Instead of hard coding values in swagger configuration we are going to define properties in configuration file. We’re using application.yml to define properties. You may also use application.properties file. app: name: spring boot application api: title: Spring Boot APIs version: 1.0.0 description: Spring Boot APIs description base-package: com.abc.controller contact-name: apisupportgroup contact-email: apisupportgroup@abc.com swagger: enable: true
Top answer
1 of 1
1

I know it's not the question you're asking, but springfox is currently having issues with newer versions of spring. The spring version you're using is still working but as of 2.6 there are bugs, and it looks like the project is not well maintained. Since you're at the beginning of the project, switching is not too hard. You could move to springdocs for example (for migration: https://springdoc.org/#migrating-from-springfox).

With respect to opening a url, there are some good solutions mentioned here: How to open the default webbrowser using java . You could make your swagger url a property and have swagger configure it accordingly, then you can reuse the property to call the url on run-time. If you want to differentiate between environments I'd suggest use profiles. Only open the url in the browser if you start the app on dev environment, and not on prod is then specified by using @Profile("dev"). Create a commandline/application runner with the profile annotation (https://www.tutorialspoint.com/spring_boot/spring_boot_runners.htm), and call the url from there.

That said, combining it gives:

package com.example.demo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

@Profile("dev")
@Component
public class SwaggerRunner implements ApplicationRunner {

    @Value("${springdoc.swagger-ui.path}")
    private String swaggerPath;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log("\nWelcome to Multi Brow Pop.\nThis aims to popup a browsers in multiple operating systems.\nGood luck!\n");

        final String swaggerUrl = "http://localhost:8000/" + swaggerPath; 
        
        log("We're going to this page: " + swaggerUrl);

        String myOS = System.getProperty("os.name").toLowerCase();
        log("(Your operating system is: " + myOS + ")\n");

        try {
            if (Desktop.isDesktopSupported()) { // Probably Windows
                log(" -- Going with Desktop.browse ...");
                Desktop desktop = Desktop.getDesktop();
                desktop.browse(new URI(swaggerUrl));
            } else { // Definitely Non-windows
                Runtime runtime = Runtime.getRuntime();
                if (myOS.contains("mac")) { // Apples
                    log(" -- Going on Apple with 'open'...");
                    runtime.exec("open " + swaggerUrl);
                } else if (myOS.contains("nix") || myOS.contains("nux")) { // Linux flavours
                    log(" -- Going on Linux with 'xdg-open'...");
                    runtime.exec("xdg-open " + swaggerUrl);
                } else
                    log("I was unable/unwilling to launch a browser in your OS :( #SadFace");
            }
            log("\nThings have finished.\nI hope you're OK.");
        } catch (IOException | URISyntaxException eek) {
            log("**Stuff wrongly: " + eek.getMessage());
        }
    }

    private static void log(String log) {
        System.out.println(log);
    }

}

put springdoc.swagger-ui.path=/custom/path in your application.properties to change the path to your swagger-ui

🌐
TutorialsPoint
tutorialspoint.com › spring_boot › spring_boot_enabling_swagger2.htm
Spring Boot - Enabling Swagger2
Next, create Docket Bean to configure Swagger2 for your Spring Boot application.
🌐
Apidog
apidog.com › blog › swagger-ui-url
How to Change Swagger UI URL Defauth Path
February 5, 2026 - const express = require('express'); const app = express(); app.use('/custom-path', express.static('swagger-ui')); app.listen(3000, () => { console.log('Server is running on port 3000'); }); This will allow you to access your Swagger UI on your ‘custom-path’. In a Spring Boot application, you can modify ‘application.properties’ or ‘application.yml’ files.
Top answer
1 of 16
95

I had given up and went to use Spring Boot 2.7 after posting the question. But, after seeing Dmitriy's answer though, I checked Springdoc one last time and found that Springdoc v2 does support Spring Boot 3.

Essentially, one has to place the following in their pom:

<dependency>
   <groupId>org.springdoc</groupId>
   <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
   <version>2.0.0</version>
</dependency>

Then one can access the Swagger page using the following URL: http://localhost:8080/swagger-ui.html (Don't forget to add context path if you need it). For some reason, when opening, it redirects to http://localhost:8080/swagger-ui/index.html although going for that initially returned 404.

2 of 16
18

I agreed with @Ahmed Tawfik because I also faced the same. But today I tried that same approach with the new version of "springdoc-openapi-starter-webmvc-ui" dependency and Spring Boot 3.0.2-SNAPSHOT.

    <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
      <version>2.0.2</version>
    </dependency>

because the previous one "springdoc-openapi-ui" is changed to the above one.

Also, include below the path to the security config for swagger UI.

"/v3/api-docs/**","/swagger-ui/**"

For my project,

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.cors(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .exceptionHandling(exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint(unauthorizedHandler))
                .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> {
                            try {
                                authorizationManagerRequestMatcherRegistry
                                        .requestMatchers(HttpMethod.POST, POST_AUTH_WHITELIST).permitAll()
                                        .requestMatchers(HttpMethod.GET, GET_AUTH_WHITELIST).permitAll()
                                        .requestMatchers("/v3/api-docs/**", "/swagger-ui/**").permitAll()
                                        .anyRequest()
                                        .authenticated()
                                        .and()
                                        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
                            } catch (Exception e) {
                                throw new ResourceNotFoundException(e.getMessage());
                            }
                        }
                )
                .formLogin(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable).addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .authenticationProvider(daoAuthenticationProvider()).build();
    }

The swagger UI link will be:

http://server:port/context-path/swagger-ui.html

Please adjust the server, port, and context-path regarding your personal changes.

All the above steps are working fine with my project. I don't need extra configuration.

Also, you can add the custom path (Optional):

springdoc.swagger-ui.path=/swagger-ui.html

Here is the Official Documentation of OpenApi 3 and Spring Boot : https://springdoc.org/v2/#features

In the above documentation, you can explore additional configurations and other things also.

Happy Learning!

🌐
DevOn
devonblog.com › home › continuous delivery › swagger/openapi with spring boot
Swagger/OpenApi with Spring Boot - Devonblog
October 20, 2022 - and the JSON format of OpenAPI description: http://server:port/context-path/v3/api-docs ... To define a custom path of our documentation. Add it to the application.properties of the Spring Boot project: springdoc.api-docs.path=/docs/api-docs springdoc.swagger-ui.path=/docs/swagger-ui.html