0

Development machine: Windows 11 pro x64, JDK/Java 19, Spring Boot 2.7.4 .

Real server: Ubuntu 22.04.1 LTS, Oracle JDK/Java 19, nginx 1.18.0 .

root@vypc:~# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
nano /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;
        }
}

File 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
# https://passwordsgenerator.net/
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

# https://stackoverflow.com/a/49257939/3728901
#spring.sql.init.mode=always
#spring.jpa.defer-datasource-initialization=true
#spring.jpa.hibernate.ddl-auto=none

File

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.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        // securedEnabled = true,
        // jsr250Enabled = true,
        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/**").permitAll()

                .authorizeRequests().antMatchers("/api/auth/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll()

                .antMatchers("/app/**").permitAll()
                .antMatchers("/api/test/**").permitAll()
                .anyRequest().authenticated();
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //;

       // .addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); // VyDN 2022_07_22 // https://www.baeldung.com/spring-security-custom-filter
    }

}

enter image description here

enter image description here

enter image description here

Real sever

sudo vi /etc/hosts

result

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

How to make Swagger working correctly on real server?

Vy Do
  • 46,709
  • 59
  • 215
  • 313
  • 1
    Have you checked there are no errors in the browser console or in the network tab? – Federico klez Culloca Sep 24 '22 at 09:26
  • Has error https://user-images.githubusercontent.com/1328316/192090837-827ae093-df7b-41b6-85a5-30c72fee3bd6.png and https://user-images.githubusercontent.com/1328316/192090974-ea504948-6269-4c77-8877-1c6d139db754.png Seemly due to CORS – Vy Do Sep 24 '22 at 09:29
  • 404...something is missing in target environment, what is available in your DEV..swagger-ui?? (lib/standalone) – xerx593 Sep 24 '22 at 09:31

1 Answers1

1

Check the files that are linked to from Swagger UI's index.html. These are all relative to the index.html file itself.

It works on localhost, because there you don't perform any mapping. You access /swagger-ui/index.html. That means the browser is trying to load files like /swagger-ui/swagger-ui-bundle.js which works because they are available at that URL.

On nginx, you don't call /swagger-ui/index.html but /. The files are still relative to this URL. That means the browser is trying to load files like /swagger-ui-bundle.js. That's not the correct path for them, so all of the linked files give 404 errors. That's why you don't see anything.

Try mapping /.* to /swagger-ui/.* (no idea how to do that in nginx). That way, when the browser tries to load /swagger-ui-bundle.js, that's mapped to /swagger-ui/swagger-ui-bundle.js which does exist.

Rob Spoor
  • 6,186
  • 1
  • 19
  • 20
  • I am a Java developer, I asked system administrators at https://serverfault.com/q/1111473/243199 I appreciated your idea. – Vy Do Sep 24 '22 at 14:14