mirror of
https://github.com/quay/quay.git
synced 2025-04-18 10:44:06 +03:00
* nginx: Increase the number and size of proxy buffers (PROJQUAY-6950) From [nginx documentation](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering): > When buffering is enabled, nginx receives a response from the proxied server as soon as possible, saving it into the buffers set by the proxy_buffer_size and proxy_buffers directives. > If the whole response does not fit into memory, a part of it can be saved to a temporary file on the disk. > Writing to temporary files is controlled by the proxy_max_temp_file_size and proxy_temp_file_write_size directives. > > When buffering is disabled, the response is passed to a client synchronously, immediately as it is received. nginx will not try to read the whole response from the proxied server. > The maximum size of the data that nginx can receive from the server at a time is set by the proxy_buffer_size directive. By default, the value of `proxy_buffer_size` directive, if not set in the nginx configuration, is equal to one memory page which on most platforms equals 4 KiB of memory. When `FEATURE_PROXY_STORAGE` is turned on and STS driver is used, the size of headers reaches that limit of 4 KiB and, if it surpasses it, nginx will error out and will not process the request. With this PR we set the buffers to an adequate size so that proxy requests are properly processed by nginx. * Add additional nginx directive to make buffers work
353 lines
10 KiB
Nginx Configuration File
353 lines
10 KiB
Nginx Configuration File
# vim: ft=nginx
|
|
|
|
keepalive_timeout 5;
|
|
|
|
if ($host = "www.quay.io") {
|
|
return 301 $proper_scheme://quay.io$request_uri;
|
|
}
|
|
|
|
# Disable the ability to be embedded into iframes
|
|
add_header X-Frame-Options DENY;
|
|
|
|
|
|
# Proxy Headers
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
proxy_redirect off;
|
|
|
|
proxy_set_header Transfer-Encoding $http_transfer_encoding;
|
|
absolute_redirect off;
|
|
|
|
# Temporarily force signin for old and new UI to route to web app
|
|
location /signin {
|
|
proxy_pass http://web_app_server/;
|
|
}
|
|
|
|
# Temporarily force /updateuser for old and new UI to route to web app
|
|
location /updateuser {
|
|
proxy_pass http://web_app_server/;
|
|
}
|
|
|
|
location /angular {
|
|
# Expire cookie and switch to old UI
|
|
add_header Set-Cookie "patternfly=deleted; path=/; Expires=Thu, Jan 01 1970 00:00:00 UTC";
|
|
return 302 /?$args;
|
|
}
|
|
|
|
location /react {
|
|
# Set cookie and witch to new UI
|
|
add_header Set-Cookie "patternfly=true; path=/; SameSite=Lax; HttpOnly;" always;
|
|
return 302 /?$args;
|
|
}
|
|
|
|
location / {
|
|
root {{static_dir}}/patternfly/;
|
|
index index.html;
|
|
|
|
# Show new UI if patternfly cookie is set
|
|
if ($cookie_patternfly) {
|
|
# catch new static paths and direct to /index.html
|
|
rewrite ^(/overview|/organization|/repository|/tag) /index.html break;
|
|
}
|
|
|
|
# Show old UI if patternfly cookie is not set
|
|
if ($cookie_patternfly != "true") {
|
|
proxy_pass http://web_app_server;
|
|
}
|
|
}
|
|
|
|
# Capture traffic that needs to go to web_app, see /web.py
|
|
location ~* ^(/config|/csrf_token|/oauth1|/oauth2|/webhooks|/keys|/.well-known|/customtrigger|/authrepoemail|/confirm|/userfiles/(.*)) {
|
|
proxy_pass http://web_app_server;
|
|
}
|
|
|
|
# Capture old UI paths that aren't present in new UI
|
|
location ~* ^(/user/(.*)|/search) {
|
|
proxy_pass http://web_app_server;
|
|
}
|
|
|
|
location /push {
|
|
proxy_pass http://web_app_server;
|
|
client_max_body_size 5M;
|
|
}
|
|
|
|
location /realtime {
|
|
proxy_pass http://web_app_server;
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
}
|
|
|
|
location ~ ^/_storage_proxy/([^/]+)/([^/]+)/([^/]+)/(.+) {
|
|
include resolver.conf;
|
|
|
|
auth_request /_storage_proxy_auth;
|
|
|
|
proxy_pass $2://$3/$4$is_args$args;
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header Host $3;
|
|
proxy_set_header Authorization "";
|
|
proxy_set_header x-forwarded-host "";
|
|
proxy_ssl_name $3;
|
|
proxy_ssl_server_name on;
|
|
|
|
add_header Host $3;
|
|
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
proxy_buffer_size 32k;
|
|
proxy_buffers 4 32k;
|
|
|
|
proxy_read_timeout 60s;
|
|
}
|
|
|
|
location = /_storage_proxy_auth {
|
|
proxy_pass http://web_app_server;
|
|
proxy_pass_request_body off;
|
|
proxy_set_header Content-Length "";
|
|
|
|
proxy_set_header X-Original-URI $request_uri;
|
|
|
|
proxy_read_timeout 10;
|
|
}
|
|
|
|
location ~ ^/v2/_catalog(.*)$ {
|
|
proxy_pass http://registry_app_server;
|
|
proxy_read_timeout 10;
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=dynamicauth_heavy_http1 burst=1 nodelay;
|
|
limit_req zone=dynamicauth_heavy_http2 burst=5 nodelay;
|
|
{% endif %}
|
|
}
|
|
|
|
location /secscan/ {
|
|
proxy_pass http://secscan_app_server;
|
|
}
|
|
|
|
{% if signing_enabled %}
|
|
location ~ ^/v2/(.+)/_trust/tuf/(.*)$ {
|
|
set $upstream_tuf {{ tuf_server }};
|
|
proxy_pass $upstream_tuf$uri;
|
|
proxy_set_header Host "{{ tuf_host }}";
|
|
}
|
|
{% endif %}
|
|
|
|
location /api/ {
|
|
proxy_pass http://web_app_server;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=dynamicauth_heavy_http1 burst=25 nodelay;
|
|
limit_req zone=dynamicauth_heavy_http2 burst=100 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
location /api/suconfig {
|
|
proxy_pass http://web_app_server;
|
|
|
|
# For suconfig, set our read timeout as super large for both DB migrations
|
|
# and awaiting for secrets to be updated.
|
|
proxy_read_timeout 2000;
|
|
}
|
|
|
|
# This block handles blob requests, and will receive a high volume of traffic, so we set the burst
|
|
# much higher.
|
|
location ~ /v2/([^/]+)(/[^/]+)+/blobs/ {
|
|
# If we're being accessed via v1.quay.io, pretend we don't support v2.
|
|
if ($host = "v1.quay.io") {
|
|
return 404;
|
|
}
|
|
|
|
# NOTE: We disable gzip for HEAD requests because Docker issues them to determine the Content
|
|
# Length of a blob. Unfortunately, nginx, seeing an empty body, overwrites the header with
|
|
# a length of 0, which breaks this functionality.
|
|
if ($request_method = HEAD) {
|
|
gzip off;
|
|
}
|
|
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
proxy_buffer_size 32k;
|
|
proxy_buffers 4 32k;
|
|
proxy_read_timeout 2000;
|
|
proxy_send_timeout 2000;
|
|
proxy_temp_path /tmp 1 2;
|
|
|
|
client_max_body_size {{ maximum_layer_size }};
|
|
http2_chunk_size 32k;
|
|
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
|
|
set $namespace $1;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=namespaced_dynamicauth_light_http1 burst=50 nodelay;
|
|
limit_req zone=namespaced_dynamicauth_light_http2 burst=100 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
# This block handles tags endpoint requests, for which we want to restrict traffic due to how
|
|
# heavy an operation it can be
|
|
location ~ /v2/([^/]+)\/[^/]+/tags/ {
|
|
# If we're being accessed via v1.quay.io, pretend we don't support v2.
|
|
if ($host = "v1.quay.io") {
|
|
return 404;
|
|
}
|
|
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
|
|
set $namespace $1;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=namespaced_dynamicauth_heavy_http1 burst=2 nodelay;
|
|
limit_req zone=namespaced_dynamicauth_heavy_http2 burst=2 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
# This block handles manifests endpoint requests, for which we want to restrict traffic heavier than
|
|
# the generic V2 operations, as it handles pushes and pulls.
|
|
location ~ /v2/([^/]+)\/[^/]+/manifests/ {
|
|
# If we're being accessed via v1.quay.io, pretend we don't support v2.
|
|
if ($host = "v1.quay.io") {
|
|
return 404;
|
|
}
|
|
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
|
|
set $namespace $1;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=namespaced_dynamicauth_light_http1 burst=10 nodelay;
|
|
limit_req zone=namespaced_dynamicauth_light_http2 burst=50 nodelay;
|
|
{% endif %}
|
|
|
|
{% if manifests_endpoint_read_timeout %}
|
|
proxy_read_timeout {{ manifests_endpoint_read_timeout }};
|
|
{% endif %}
|
|
}
|
|
|
|
# This block applies to the beginning of a push or pull
|
|
location = /v2/auth {
|
|
# If we're being accessed via v1.quay.io, pretend we don't support v2.
|
|
if ($host = "v1.quay.io") {
|
|
return 404;
|
|
}
|
|
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=staticauth burst=2 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
# This block handles all other V2 requests, for which we can use a higher rate limit.
|
|
location ~ ^/v2 {
|
|
# If we're being accessed via v1.quay.io, pretend we don't support v2.
|
|
if ($host = "v1.quay.io") {
|
|
return 404;
|
|
}
|
|
|
|
# NOTE: We disable gzip for HEAD requests because Docker issues them to determine the Content
|
|
# Length of a blob. Unfortunately, nginx, seeing an empty body, overwrites the header with
|
|
# a length of 0, which breaks this functionality. Included here for completeness.
|
|
if ($request_method = HEAD) {
|
|
gzip off;
|
|
}
|
|
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=dynamicauth_very_light_http1 burst=20 nodelay;
|
|
limit_req zone=dynamicauth_very_light_http2 burst=80 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
location /v1/ {
|
|
# Setting ANY header clears all inherited proxy_set_header directives
|
|
proxy_set_header X-Forwarded-For $proper_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $proper_scheme;
|
|
proxy_set_header Host $host;
|
|
|
|
proxy_buffering off;
|
|
|
|
proxy_request_buffering off;
|
|
|
|
proxy_http_version 1.1;
|
|
|
|
proxy_pass http://registry_app_server;
|
|
proxy_temp_path /tmp 1 2;
|
|
|
|
client_max_body_size {{ maximum_layer_size }};
|
|
|
|
{% if enable_rate_limits %}
|
|
limit_req zone=dynamicauth_heavy_http1 burst=5 nodelay;
|
|
limit_req zone=dynamicauth_heavy_http2 burst=25 nodelay;
|
|
{% endif %}
|
|
|
|
keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin.
|
|
}
|
|
|
|
location = /v1/_ping {
|
|
add_header Content-Type text/plain;
|
|
add_header X-Docker-Registry-Version 0.6.0;
|
|
add_header X-Docker-Registry-Standalone 0;
|
|
return 200 'true';
|
|
}
|
|
|
|
location /static/ {
|
|
# checks for static file, if not found proxy to app
|
|
alias {{static_dir}}/;
|
|
error_page 404 /404;
|
|
}
|
|
|
|
error_page 502 {{static_dir}}/502.html;
|