diff --git a/custom-domain/dstack-ingress/README.md b/custom-domain/dstack-ingress/README.md index 0de4cd0..168670b 100644 --- a/custom-domain/dstack-ingress/README.md +++ b/custom-domain/dstack-ingress/README.md @@ -177,6 +177,9 @@ configs: - `TARGET_ENDPOINT`: The plain HTTP endpoint of your dstack application (for single domain mode) - `SET_CAA`: Set to `true` to enable CAA record setup - `CLIENT_MAX_BODY_SIZE`: Optional value for nginx `client_max_body_size` (numeric with optional `k|m|g` suffix, e.g. `50m`) in single-domain mode +- `PROXY_READ_TIMEOUT`: Optional value for nginx `proxy_read_timeout` (numeric with optional `s|m|h` suffix, e.g. `30s`) in single-domain mode +- `PROXY_SEND_TIMEOUT`: Optional value for nginx `proxy_send_timeout` (numeric with optional `s|m|h` suffix, e.g. `30s`) in single-domain mode +- `PROXY_CONNECT_TIMEOUT`: Optional value for nginx `proxy_connect_timeout` (numeric with optional `s|m|h` suffix, e.g. `10s`) in single-domain mode **Backward Compatibility:** diff --git a/custom-domain/dstack-ingress/scripts/entrypoint.sh b/custom-domain/dstack-ingress/scripts/entrypoint.sh index a150687..b2e1c02 100644 --- a/custom-domain/dstack-ingress/scripts/entrypoint.sh +++ b/custom-domain/dstack-ingress/scripts/entrypoint.sh @@ -19,6 +19,15 @@ fi if ! CLIENT_MAX_BODY_SIZE=$(sanitize_client_max_body_size "$CLIENT_MAX_BODY_SIZE"); then exit 1 fi +if ! PROXY_READ_TIMEOUT=$(sanitize_proxy_timeout "$PROXY_READ_TIMEOUT"); then + exit 1 +fi +if ! PROXY_SEND_TIMEOUT=$(sanitize_proxy_timeout "$PROXY_SEND_TIMEOUT"); then + exit 1 +fi +if ! PROXY_CONNECT_TIMEOUT=$(sanitize_proxy_timeout "$PROXY_CONNECT_TIMEOUT"); then + exit 1 +fi if ! TXT_PREFIX=$(sanitize_dns_label "$TXT_PREFIX"); then exit 1 fi @@ -73,6 +82,21 @@ setup_nginx_conf() { client_max_body_size_conf=" client_max_body_size ${CLIENT_MAX_BODY_SIZE};" fi + local proxy_read_timeout_conf="" + if [ -n "$PROXY_READ_TIMEOUT" ]; then + proxy_read_timeout_conf=" ${PROXY_CMD}_read_timeout ${PROXY_READ_TIMEOUT};" + fi + + local proxy_send_timeout_conf="" + if [ -n "$PROXY_SEND_TIMEOUT" ]; then + proxy_send_timeout_conf=" ${PROXY_CMD}_send_timeout ${PROXY_SEND_TIMEOUT};" + fi + + local proxy_connect_timeout_conf="" + if [ -n "$PROXY_CONNECT_TIMEOUT" ]; then + proxy_connect_timeout_conf=" ${PROXY_CMD}_connect_timeout ${PROXY_CONNECT_TIMEOUT};" + fi + cat </etc/nginx/conf.d/default.conf server { listen ${PORT} ssl; @@ -120,6 +144,9 @@ ${client_max_body_size_conf} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; +${proxy_read_timeout_conf} +${proxy_send_timeout_conf} +${proxy_connect_timeout_conf} } location /evidences/ { diff --git a/custom-domain/dstack-ingress/scripts/functions.sh b/custom-domain/dstack-ingress/scripts/functions.sh index a945b45..868555c 100644 --- a/custom-domain/dstack-ingress/scripts/functions.sh +++ b/custom-domain/dstack-ingress/scripts/functions.sh @@ -68,3 +68,17 @@ sanitize_dns_label() { return 1 fi } + +sanitize_proxy_timeout() { + local candidate="$1" + if [ -z "$candidate" ]; then + echo "" + return 0 + fi + if [[ "$candidate" =~ ^[0-9]+[smh]?$ ]]; then + echo "$candidate" + else + echo "Warning: Ignoring invalid proxy timeout value: $candidate" >&2 + echo "" + fi +} diff --git a/custom-domain/dstack-ingress/scripts/tests/test_sanitizers.sh b/custom-domain/dstack-ingress/scripts/tests/test_sanitizers.sh index be8e66f..8c6d71e 100644 --- a/custom-domain/dstack-ingress/scripts/tests/test_sanitizers.sh +++ b/custom-domain/dstack-ingress/scripts/tests/test_sanitizers.sh @@ -47,6 +47,11 @@ assert_equal "$(sanitize_target_endpoint grpc://svc:50051)" "grpc://svc:50051" " assert_equal "$(sanitize_client_max_body_size 50m)" "50m" "sanitize_client_max_body_size accepts suffix" assert_equal "$(sanitize_dns_label test_label)" "test_label" "sanitize_dns_label accepts lowercase" assert_equal "$(sanitize_dns_label test-label)" "test-label" "sanitize_dns_label accepts hyphen" +assert_equal "$(sanitize_proxy_timeout 30)" "30" "sanitize_proxy_timeout accepts numeric value" +assert_equal "$(sanitize_proxy_timeout 30s)" "30s" "sanitize_proxy_timeout accepts seconds suffix" +assert_equal "$(sanitize_proxy_timeout 5m)" "5m" "sanitize_proxy_timeout accepts minutes suffix" +assert_equal "$(sanitize_proxy_timeout 1h)" "1h" "sanitize_proxy_timeout accepts hours suffix" +assert_equal "$(sanitize_proxy_timeout '')" "" "sanitize_proxy_timeout accepts empty value" # Failing cases assert_fails "sanitize_port rejects non-numeric" sanitize_port abc @@ -60,6 +65,26 @@ else printf '%s\n' "$warning_output" failures=$((failures + 1)) fi + +# Test invalid timeout values +timeout_warning="$(sanitize_proxy_timeout "30ms" 2>&1 || true)" +if [[ "$timeout_warning" == "Warning: Ignoring invalid proxy timeout value: 30ms" ]]; then + echo "PASS: sanitize_proxy_timeout warns on invalid suffix (ms)" +else + echo "FAIL: sanitize_proxy_timeout warning unexpected" + printf '%s\n' "$timeout_warning" + failures=$((failures + 1)) +fi + +timeout_warning="$(sanitize_proxy_timeout "abc" 2>&1 || true)" +if [[ "$timeout_warning" == "Warning: Ignoring invalid proxy timeout value: abc" ]]; then + echo "PASS: sanitize_proxy_timeout warns on non-numeric value" +else + echo "FAIL: sanitize_proxy_timeout warning unexpected" + printf '%s\n' "$timeout_warning" + failures=$((failures + 1)) +fi + assert_fails "sanitize_dns_label rejects invalid characters" sanitize_dns_label "bad*label" if [[ $failures -eq 0 ]]; then