I am using Spring Boot 2.2.2.RELEASE and tries to bind my embbed netty server to port 443 with a non root user. The application fails to start with message:

2020/01/20 09:29:09.465 [] [main] [DEBUG] report(LoggingFailureAnalysisReporter.java:37) - Application failed to start due to an exception
org.springframework.boot.web.server.PortInUseException: Port 443 is already in use
        at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:85)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext$ServerManager.start(ReactiveWebServerApplicationContext.java:259)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.startReactiveWebServer(ReactiveWebServerApplicationContext.java:138)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.finishRefresh(ReactiveWebServerApplicationContext.java:130)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
        at com.huaweicloud.rms.RmsApplication.main(RmsApplication.java:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)

Spend some time trying to find the process using port 443 but there is no. The real cause is that with no more system config it's not allowed for a non root user to use port under 1024. I think the PortInUseException is misleading here and a PermissionException is more suitable.

Comment From: snicoll

Good catch @zhangyangyu, here is the underlying exception

Caused by: reactor.netty.ChannelBindException: Failed to bind on [0.0.0.0:443]
    Suppressed: java.lang.Exception: #block terminated with an error
        at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:139) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
        at reactor.core.publisher.Mono.block(Mono.java:1687) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
        at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:129) ~[reactor-netty-0.9.4.RELEASE.jar:0.9.4.RELEASE]
        at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:112) ~[reactor-netty-0.9.4.RELEASE.jar:0.9.4.RELEASE]
        at org.springframework.boot.web.embedded.netty.NettyWebServer.startHttpServer(NettyWebServer.java:107) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:80) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext$ServerManager.start(ReactiveWebServerApplicationContext.java:246) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.startReactiveWebServer(ReactiveWebServerApplicationContext.java:125) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.finishRefresh(ReactiveWebServerApplicationContext.java:117) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) ~[spring-context-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
        at com.example.testnetty.TestNettyApplication.main(TestNettyApplication.java:10) ~[classes/:na]
Caused by: io.netty.channel.unix.Errors$NativeIoException: bind(..) failed: Permission denied

Comment From: RicardoRFaria

Hi team, I'm willing to fix this issue, but I found some problems. Netty doesn't expose the "permission denied" info through an Exception, it just throw the NativeIoException

if (socketAddress instanceof InetSocketAddress) {
            InetSocketAddress addr = (InetSocketAddress) socketAddress;
            NativeInetAddress address = NativeInetAddress.newInstance(addr.getAddress());
            int res = bind(fd, address.address, address.scopeId, addr.getPort());
            if (res < 0) {
                throw newIOException("bind", res);
            }
...

Code from line 253. (https://github.com/netty/netty/blob/f17bfd0f64189d91302fbdd15103788bf9eabaa2/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java)

And even the native error code (-13), is converted to just a String in the message. As linked by @snicoll.

Do you think that a solution based on message "Permission Denied", is a good solution for now? Or maybe a PR for Netty first, instead of making a validation based on a message.

Comment From: philwebb

@RicardoRFaria Which bit of the Netty code are you looking at? The exception @snicoll included is Errors$NativeIoException were as your snipped seems to throw a ConnectException.

Comment From: RicardoRFaria

@philwebb The code that I linked before wasn't part of the problem. Sorry about that. I edited the comment with the right code and more information, in the end, Netty doesn't expose the information of permission denied through an Exception or Error code, just the message.

Comment From: philwebb

@RicardoRFaria Thanks for offer to help but I wanted to push something before we release 2.3.0.RC so I've made an attempt myself. In the end I decided the safest way was to look at the error code inside the Netty exception.

Comment From: RicardoRFaria

@philwebb No problem. It was nice to see your solution.

Comment From: twhitmorenz

Found this issue when trying to bind to an AWS machine's public IP - which doesn't actually exist as an interface on the machine, and thus failed with a fairly confusing "Port already in use" message.

Great to see the message is being clarified.