# 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; location / { 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_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 ""; add_header Host $3; proxy_buffering off; proxy_request_buffering off; 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://jwtproxy_secscan; } location /secscan/_internal_ping { 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 /cnr { proxy_buffering off; proxy_request_buffering off; proxy_pass http://registry_app_server; proxy_read_timeout 120; proxy_temp_path /tmp 1 2; {% if enable_rate_limits %} limit_req zone=staticauth burst=5 nodelay; {% 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_read_timeout 2000; proxy_temp_path /tmp 1 2; client_max_body_size {{ maximum_layer_size }}; # 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 %} keepalive_timeout 0; # Disables HTTP 1.1 keep-alive and forces round-robin. } # 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 /c1/ { proxy_buffering off; proxy_request_buffering off; proxy_pass http://verbs_app_server; proxy_temp_path /tmp 1 2; {% if enable_rate_limits %} limit_req zone=staticauth burst=5 nodelay; {% endif %} } 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; location ~ ^/b1/controller(/?)(.*) { proxy_pass http://build_manager_controller_server/$2; } location ~ ^/b1/socket(/?)(.*) { proxy_pass http://build_manager_websocket_server/$2; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300; }