У меня есть среда Ubuntu 16.04 с Docker в Digital Ocean, и я загружаю службу с помощью docker-compose:
version: '2'
services:
cis-api:
image: docker.myserver.com/cis-api:latest
ports:
- 8080:5000
environment:
DB_CONN_STRING: 'Server=tcp:...;Initial Catalog=cis-stage;Persist Security Info=False;User ID=...;Password=...;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'
Затем у меня установлен ванильный Nginx с одной конфигурацией внутри /etc/nginx/conf.d
:
upstream cis-api {
server 0.0.0.0:8080;
}
server {
listen 80;
server_name cis-api.myserver.com;
location / {
proxy_pass http://cis-api;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
Когда я пытаюсь запросить URL в обход nginx, все работает:
root@cis-stage:/etc/nginx# curl localhost:8080/businesses -H 'Authorization: Bearer ...'
[{"id":1,...,"email":null}]
Однако, если я попытаюсь выполнить тот же запрос, проходящий через nginx, соединение зависнет, или если я установлю тайм-аут 30 секунд, он истечет:
root@cis-stage:/etc/nginx# curl --max-time 30 --connect-timeout 30 http://cis-api.mysever.com/businesses -H 'Authorization: Bearer ....'
curl: (28) Operation timed out after 30000 milliseconds with 0 bytes received
Приложение написано на ASP.Net Core 1.1, и вот разница в результатах, когда я запускаю его в обход nginx:
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[1]
cis-api_1 | Connection id "0HL3OL7D1CF19" started.
cis-api_1 | info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
cis-api_1 | Request starting HTTP/1.1 GET http://localhost:8080/businesses
cis-api_1 | info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[2]
cis-api_1 | Successfully validated the token.
cis-api_1 | info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[3]
cis-api_1 | HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
cis-api_1 | info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
cis-api_1 | Request finished in 414.6261ms 200 application/json; charset=utf-8
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[6]
cis-api_1 | Connection id "0HL3OL7D1CF19" received FIN.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[9]
cis-api_1 | Connection id "0HL3OL7D1CF19" completed keep alive response.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[10]
cis-api_1 | Connection id "0HL3OL7D1CF19" disconnecting.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[7]
cis-api_1 | Connection id "0HL3OL7D1CF19" sending FIN.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[8]
cis-api_1 | Connection id "0HL3OL7D1CF19" sent FIN with status "0".
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[2]
cis-api_1 | Connection id "0HL3OL7D1CF19" stopped.
Против, когда я использую nginx в качестве прокси:
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[1]
cis-api_1 | Connection id "0HL3OL7D1CF1B" started.
cis-api_1 | info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
cis-api_1 | Request starting HTTP/1.0 GET http://cis-api.myserver.com/businesses
cis-api_1 | info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[2]
cis-api_1 | Successfully validated the token.
cis-api_1 | info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[3]
cis-api_1 | HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
Здесь он висит до истечения времени ожидания запроса, а затем:
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[6]
cis-api_1 | Connection id "0HL3OLAD6F4QN" received FIN.
cis-api_1 | info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
cis-api_1 | Request finished in 4615.4522ms 200 application/json; charset=utf-8
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[10]
cis-api_1 | Connection id "0HL3OLAD6F4QN" disconnecting.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[7]
cis-api_1 | Connection id "0HL3OLAD6F4QN" sending FIN.
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[8]
cis-api_1 | Connection id "0HL3OLAD6F4QN" sent FIN with status "-107".
cis-api_1 | dbug: Microsoft.AspNetCore.Server.Kestrel[2]
cis-api_1 | Connection id "0HL3OLAD6F4QN" stopped.
Любые идеи?
После долгих исследований я нашел здесь ответ:
https://github.com/aspnet/KestrelHttpServer/issues/468#issuecomment-165951249
И проблема была решена путем изменения файла конфигурации nginx, чтобы добавить новый заголовок Proxy:
proxy_set_header Connection keep-alive;
Новый location
блок стал:
location / {
proxy_pass http://cis-api;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection keep-alive;
proxy_read_timeout 900;
}
Теперь все работает как положено