我对以下设置感到困惑:
- 本地 gitlab 实例 (http) 位于可访问的反向代理后面
gitlab.mydomain.com
- plantuml 实例(http)位于同一代理后面,我想在其下访问
gitlab.mydomain.com/plantuml
(也在 gitlab 中配置为这样)
所以我目前已设置nginx
(这里作为“聚合”伪配置):
http {
...
server {
listen 5443 ...;
# general webserver (with error pages etc.)
}
# reverse proxy for gitlab:
server {
listen 5443 ssl;
listen [::]:5443 ssl;
server_name gitlab.*;
include /etc/nginx/ssl.conf; # certificates etc.
# already tried ^~, but now according to
# https://stackoverflow.com/a/28478928/12771809
# (though this doesn't appear to be the real problem)
location ~ ^/plantuml/(.*)$ {
include /etc/nginx/proxy.conf;
resolver myrouter valid=30s;
set $upstream_app myserver;
set $upstream_port 7080;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
rewrite /plantuml(.*) $1 break;
}
location / {
include /etc/nginx/proxy.conf; # standard proxy headers
resolver myrouter valid=30s;
set $upstream_app myserver;
set $upstream_port 6080;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}
反向代理运行良好(我可以正常使用所有 gitlab 功能),同一域上不同 vhost 后面的其他服务也运行良好。
但是 plantuml 实例不起作用,如果我连接到,gitlab.mydomain.com/plantuml/png/U9oLLS6Ec...
我得到:
Bad Message 400
reason: Bad Request
调试日志显示:
2020/11/18 16:30:43 [debug] 102#102: *11 name was resolved to 192.168.1.60
2020/11/18 16:30:43 [debug] 102#102: resolve name done: 0
2020/11/18 16:30:43 [debug] 102#102: resolver expire
2020/11/18 16:30:43 [debug] 102#102: *11 get rr peer, try: 1
2020/11/18 16:30:43 [debug] 102#102: *11 stream socket 44
2020/11/18 16:30:43 [debug] 102#102: *11 epoll add connection: fd:44 ev:80002005
2020/11/18 16:30:43 [debug] 102#102: *11 connect to 192.168.1.60:7080, fd:44 #93
2020/11/18 16:30:43 [debug] 102#102: *11 http upstream connect: -2
2020/11/18 16:30:43 [debug] 102#102: *11 posix_memalign: 0000560AAA19E860:128 @16
2020/11/18 16:30:43 [debug] 102#102: *11 event timer add: 44: 240000:752739282
2020/11/18 16:30:43 [debug] 102#102: *11 http finalize request: -4, "/png/U9oLLS6Ec......"
最后一行显示重写也有效,如果我将其粘贴到局域网浏览器中,http://192.168.1.60:7080/png/U9oLLS6Ec...
我就可以看到图表。
调试日志进一步显示:
2020/11/18 16:30:43 [debug] 102#102: *11 http upstream process header
2020/11/18 16:30:43 [debug] 102#102: *11 malloc: 0000560AAA1A82E0:4096
2020/11/18 16:30:43 [debug] 102#102: *11 recv: eof:0, avail:-1
2020/11/18 16:30:43 [debug] 102#102: *11 recv: fd:44 198 of 4096
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy status 400 "400 Bad Request"
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy header: "Content-Type: text/html;charset=iso-8859-1"
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy header: "Content-Length: 54"
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy header: "Connection: close"
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy header: "Server: Jetty(9.4.33.v20201020)"
2020/11/18 16:30:43 [debug] 102#102: *11 http proxy header done
2020/11/18 16:30:43 [debug] 102#102: *11 http2 header filter
2020/11/18 16:30:43 [debug] 102#102: *11 http2 push resources
2020/11/18 16:30:43 [debug] 102#102: *11 http2 output header: ":status: 400"
2020/11/18 16:30:43 [debug] 102#102: *11 http2 output header: "server: nginx"
2020/11/18 16:30:43 [debug] 102#102: *11 http2 output header: "date: Wed, 18 Nov 2020 15:30:43 GMT"
2020/11/18 16:30:43 [debug] 102#102: *11 http2 output header: "content-type: text/html;charset=iso-8859-1"
2020/11/18 16:30:43 [debug] 102#102: *11 http2 output header: "content-length: 54"
2020/11/18 16:30:43 [debug] 102#102: *11 http2:131 create HEADERS frame 0000560AAA1A8188: len:57 fin:0
我不太明白那部分,但它似乎出现在 plantuml 中?(因为它显示Jetty
)
编辑:
我成功地jetty
直接执行plantuml
并调试如下:
java -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -Dorg.eclipse.jetty.LEVEL=DEBUG -Djetty.contextpath=/ -jar jetty-runner-9.4.34.v20201102.jar plantuml-v1.2020.19.war
并且我更改了代理以转发到此实例。(如果我直接处理它,它就可以正常工作)。
该错误完全可重现。有很多日志输出,但这部分让我感到很奇怪:
2020-11-18 20:28:48.814:DBUG:oejs.HttpChannel:qtp1663166483-40: REQUEST for //gitlab.mydomain.com/ on HttpChannelOverHttp@30ef9a4a{s=HttpChannelState@5e5175f8{s=IDLE rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=1,c=false/false,a=IDLE,uri=//gitlab.mydomain.com/,age=1}
GET //gitlab.mydomain.com/ HTTP/1.1
Host: gitlab.mydomain.com
Upgrade: close
Connection: close
X-Forwarded-For: xxx.xxx.xxx.xxx
X-Forwarded-Host: gitlab.mydomain.com
X-Forwarded-Proto: https
X-Forwarded-Ssl: on
X-Real-IP: xxx.xxx.xxx.xxx
该部分难道不应该GET
是这样的/png/blabla...
吗?
编辑2:
稍微改变该location
部分现在uri
也包括了该部分GET
,至少在日志中是uri
这样,尽管它报告了null
(我认为这是问题的一部分)。
2020-11-18 21:22:33.606:DBUG:oejh.HttpParser:qtp1663166483-22: Parse exception: HttpParser{s=CONTENT,0 of -1} for HttpChannelOverHttp@7dd961cb{s=HttpChannelState@79e6eaa8{s=IDLE rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=0,c=false/false,a=IDLE,uri=null,age=0}
org.eclipse.jetty.http.BadMessageException: 400: null
at org.eclipse.jetty.server.HttpChannelOverHttp.upgrade(HttpChannelOverHttp.java:432)
at org.eclipse.jetty.server.HttpChannelOverHttp.headerComplete(HttpChannelOverHttp.java:357)
at org.eclipse.jetty.http.HttpParser.parseFields(HttpParser.java:1225)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1508)
at org.eclipse.jetty.server.HttpConnection.parseRequestBuffer(HttpConnection.java:364)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:261)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905)
at java.base/java.lang.Thread.run(Thread.java:832)
2020-11-18 21:22:33.607:DBUG:oejh.HttpParser:qtp1663166483-22: CONTENT --> CLOSE
2020-11-18 21:22:33.607:DBUG:oejs.HttpChannel:qtp1663166483-22: REQUEST for //gitlab.mydomain.com/png/XxXxXxXx on HttpChannelOverHttp@7dd961cb{s=HttpChannelState@79e6eaa8{s=IDLE rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=1,c=false/false,a=IDLE,uri=//gitlab.mydomain.com/png/XxXxXxXx,age=0}
GET //gitlab.mydomain.com/png/XxXxXxXx HTTP/1.1
Host: gitlab.mydomain.com
答案1
解决方案:
这个问题很“愚蠢”,因为它很隐蔽(所以我们要吸取的教训是:永远不要“仅仅”包括样板)。
所包含的标准proxy.conf
(它是我尝试过的容器之一的一部分nginx
)包含以下内容(很多并且可能包含不需要的东西?):
## Version 2020/10/04 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/proxy.conf
# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# Proxy Connection Settings
proxy_buffers 32 4k;
proxy_connect_timeout 240;
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 1024;
proxy_http_version 1.1;
proxy_read_timeout 240;
# proxy_redirect http:// $scheme://;
proxy_redirect off;
proxy_send_timeout 240;
# Proxy Cache and Cookie Settings
proxy_cache_bypass $cookie_session;
#proxy_cookie_path / "/; Secure"; # enable at your own risk, may break certain apps
proxy_no_cache $cookie_session;
# Proxy Header Settings
proxy_set_header Early-Data $ssl_early_data;
proxy_set_header Host $host;
proxy_set_header Proxy "";
proxy_set_header Upgrade $connection_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $remote_addr;
只需删除include
此文件并结合一条干净的location /plantuml/ { ... }
线路即可解决问题。
罪魁祸首是那条线:
proxy_set_header Upgrade $connection_upgrade;
没有它,一切都正常。
答案2
location /plantuml/ {
include /etc/nginx/proxy.conf;
resolver myrouter valid=30s;
set $upstream_app myserver;
set $upstream_port 7080;
set $upstream_proto http;
proxy_http_version 1.1;
proxy_pass $upstream_proto://$upstream_app:$upstream_port/;
}