gateway Failed to bind on [0.0.0.0:443]

发布时间 2023-12-28 14:53:56作者: 搬砖党路过

1. 问题背景

  项目在做非docker容器部署,直接在宿主机上部署,gateway出现端口绑定失败的问题

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)
                at reactor.core.publisher.Mono.block(Mono.java:1709)
                at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:133)
                at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:116)
                at org.springframework.boot.web.embedded.netty.NettyWebServer.startHttpServer(NettyWebServer.java:145)
                at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:99)
                at org.springframework.boot.web.reactive.context.WebServerManager.start(WebServerManager.java:54)
                at org.springframework.boot.web.reactive.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:40)
                at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
                at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
                at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
                at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
                at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
                at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:895)
                at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554)
                at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:62)
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755)
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
                at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:402)
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1247)
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1236)
                at com.msxf.cc.gateway.GatewayApplication.main(GatewayApplication.java:30)
Caused by: io.netty.channel.unix.Errors$NativeIoException: bind(..) failed: 权限不够

  问题很明显:当前用户没有权限使用443端口

  在linux系统中普通用户使用的端口限制以该net.ipv4.ip_local_port_range参数为准,且端口下线不能小于默认值1024,这也是上述报错的原因

解决方式一:

  通过sudo命令普通用户提权来执行java -jar命令,此方式又延时出另一个问题

sudo: java:找不到命令

  sudo提权之后找不到java命令,登录root用户和当前普通用户分别执行java -version命令都是成功的,那么sudo之后为什么不行了呢

  查看sudo配置文件cat /etc/sudoers,可以看到sudo提权后的执行目录为:

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin/

  那么我们只需要把java命令软链接到此目录下就行了

sudo ln -s /opt/jdk1.8.0_231/bin/java /usr/bin/
sudo ln -s /opt/jdk1.8.0_231/bin/javac /usr/bin/

  此时执行java -version,可以找到java命令

[finance@ecs-hostname-20230731037001 bin]$ sudo java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

  执行完上述操作之后,再次启动java服务。可以看到443端口绑定成功

 

解决方式二:

  配置路由转发,前提是服务要启用iptables,禁用firewalld

  并且保证net.ipv4.ip_forward = 1开启

  配置转发规则,这里我们使用 Iptables 来配置的转发规则,以实现端口转发到程序所在的端口。

  把443端口的请求转发到本机的10001端口

  iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:10001

解决方式三:

  使用authbind工具来实现普通用户绑定特权端口

  安装authbind: 

sudo apt-get update
sudo apt-get install authbind

  配置authbind允许普通用户绑定443端口

sudo touch /etc/authbind/byport/443
sudo chmod 500 /etc/authbind/byport/443
#test 为用户名
sudo chown test /etc/authbind/byport/443

  使用 authbind 运行指定程序

authbind --deep "java -jar xxx"

解决方式四:

  使用nginx代理,把443端口的请求转发到对应ip的8443端口

upstream gateway{
    server x.x.x.x:8443;
}

server {
    listen 443 ssl;
    server_name jstest2.cc.xinmzc.com;
    access_log  /var/log/nginx/index.access.log  main;
    error_log /var/log/nginx/index.error.log;
    ssl_certificate /etc/nginx/cert/ivr.pem;
    ssl_certificate_key /etc/nginx/cert/ivr.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ## send request back to apache ##
        
    location / {
        proxy_pass  https://gateway;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'Upgrade';
    }
}

推荐解决方式四,如果没有nginx,推荐使用方式一;不推荐使用方式二、三