diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-03-25 07:19:26 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-03-25 07:19:26 +0000 |
| commit | 28168a7701c897a5b6af13bc472d6f5902e0a96d (patch) | |
| tree | bbb2ad5e238f118a31d4d1b974c0b391c74a12c1 | |
| parent | 05b7edb5f5797100d8e0f59905e16488680928ec (diff) | |
chore: remove arbitrary default max connections limit
When NGIT_MAX_CONNECTIONS is unset the relay imposes no connection cap,
deferring to OS fd limits and infrastructure controls. The option remains
available for operators who want an explicit ceiling.
| -rw-r--r-- | .env.example | 4 | ||||
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | docs/reference/configuration.md | 10 | ||||
| -rw-r--r-- | nix/module.nix | 10 | ||||
| -rw-r--r-- | src/config.rs | 9 | ||||
| -rw-r--r-- | src/nostr/builder.rs | 13 |
6 files changed, 29 insertions, 21 deletions
diff --git a/.env.example b/.env.example index 43f8f6f..24090ef 100644 --- a/.env.example +++ b/.env.example | |||
| @@ -298,7 +298,7 @@ | |||
| 298 | # ============================================================================ | 298 | # ============================================================================ |
| 299 | 299 | ||
| 300 | # Maximum total connections to the relay | 300 | # Maximum total connections to the relay |
| 301 | # Prevents connection exhaustion DoS attacks | 301 | # When unset (default), connections are unlimited (defers to OS fd limits and infrastructure controls) |
| 302 | # CLI: --max-connections <count> | 302 | # CLI: --max-connections <count> |
| 303 | # Default: 4096 | 303 | # Default: unlimited |
| 304 | # NGIT_MAX_CONNECTIONS=4096 \ No newline at end of file | 304 | # NGIT_MAX_CONNECTIONS=4096 \ No newline at end of file |
diff --git a/CHANGELOG.md b/CHANGELOG.md index a1c2f60..217781c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
| @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## [Unreleased] | 8 | ## [Unreleased] |
| 9 | 9 | ||
| 10 | ### Changed | ||
| 11 | |||
| 12 | - Remove arbitrary default max connections limit; when `NGIT_MAX_CONNECTIONS` is unset the relay imposes no connection cap, deferring to OS fd limits and infrastructure controls | ||
| 13 | |||
| 10 | ## [1.0.1] - 2026-02-27 | 14 | ## [1.0.1] - 2026-02-27 |
| 11 | 15 | ||
| 12 | ### Fixed | 16 | ### Fixed |
diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index a05aeee..bce1200 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md | |||
| @@ -997,15 +997,15 @@ Event blacklist does **not** affect NIP-11 metadata: | |||
| 997 | 997 | ||
| 998 | #### `NGIT_MAX_CONNECTIONS` | 998 | #### `NGIT_MAX_CONNECTIONS` |
| 999 | 999 | ||
| 1000 | **Description:** Maximum total connections to the relay. Prevents connection exhaustion DoS attacks. | 1000 | **Description:** Maximum total connections to the relay. When unset, connections are unlimited, deferring to OS fd limits and infrastructure-level controls. |
| 1001 | **Type:** Integer | 1001 | **Type:** Integer |
| 1002 | **Default:** `4096` | 1002 | **Default:** unlimited |
| 1003 | **Required:** No | 1003 | **Required:** No |
| 1004 | 1004 | ||
| 1005 | **Examples:** | 1005 | **Examples:** |
| 1006 | 1006 | ||
| 1007 | ```bash | 1007 | ```bash |
| 1008 | # Default: 4096 connections | 1008 | # Cap connections for a resource-constrained deployment |
| 1009 | NGIT_MAX_CONNECTIONS=4096 | 1009 | NGIT_MAX_CONNECTIONS=4096 |
| 1010 | 1010 | ||
| 1011 | # Higher limit for large public relay | 1011 | # Higher limit for large public relay |
| @@ -1017,8 +1017,8 @@ NGIT_MAX_CONNECTIONS=100 | |||
| 1017 | 1017 | ||
| 1018 | **Notes:** | 1018 | **Notes:** |
| 1019 | 1019 | ||
| 1020 | - Limits total concurrent WebSocket connections to the relay | 1020 | - When unset, the relay imposes no connection limit (`Semaphore::MAX_PERMITS`); OS fd limits and infrastructure controls apply |
| 1021 | - Prevents connection exhaustion attacks | 1021 | - Set this only if you need an explicit cap; otherwise leave unset |
| 1022 | - Works in conjunction with per-connection limits (500 subscriptions, 60 events/min) | 1022 | - Works in conjunction with per-connection limits (500 subscriptions, 60 events/min) |
| 1023 | - When limit is reached, new connections are rejected | 1023 | - When limit is reached, new connections are rejected |
| 1024 | - Existing connections continue to work normally | 1024 | - Existing connections continue to work normally |
diff --git a/nix/module.nix b/nix/module.nix index 7354ab6..9693358 100644 --- a/nix/module.nix +++ b/nix/module.nix | |||
| @@ -268,9 +268,10 @@ let | |||
| 268 | }; | 268 | }; |
| 269 | 269 | ||
| 270 | maxConnections = mkOption { | 270 | maxConnections = mkOption { |
| 271 | type = types.int; | 271 | type = types.nullOr types.int; |
| 272 | default = 4096; | 272 | default = null; |
| 273 | description = "Maximum total connections to the relay"; | 273 | description = |
| 274 | "Maximum total connections to the relay (default: unlimited, defers to OS/infrastructure limits)"; | ||
| 274 | }; | 275 | }; |
| 275 | 276 | ||
| 276 | user = mkOption { | 277 | user = mkOption { |
| @@ -337,8 +338,9 @@ let | |||
| 337 | NGIT_REPOSITORY_WHITELIST = concatStringsSep "," cfg.repositoryWhitelist; | 338 | NGIT_REPOSITORY_WHITELIST = concatStringsSep "," cfg.repositoryWhitelist; |
| 338 | NGIT_REPOSITORY_BLACKLIST = concatStringsSep "," cfg.repositoryBlacklist; | 339 | NGIT_REPOSITORY_BLACKLIST = concatStringsSep "," cfg.repositoryBlacklist; |
| 339 | NGIT_EVENT_BLACKLIST = concatStringsSep "," cfg.eventBlacklist; | 340 | NGIT_EVENT_BLACKLIST = concatStringsSep "," cfg.eventBlacklist; |
| 340 | NGIT_MAX_CONNECTIONS = toString cfg.maxConnections; | ||
| 341 | NGIT_LOG_LEVEL = cfg.logLevel; | 341 | NGIT_LOG_LEVEL = cfg.logLevel; |
| 342 | } // optionalAttrs (cfg.maxConnections != null) { | ||
| 343 | NGIT_MAX_CONNECTIONS = toString cfg.maxConnections; | ||
| 342 | } // optionalAttrs (cfg.relayName != null) { | 344 | } // optionalAttrs (cfg.relayName != null) { |
| 343 | NGIT_RELAY_NAME = cfg.relayName; | 345 | NGIT_RELAY_NAME = cfg.relayName; |
| 344 | } // optionalAttrs (cfg.archiveReadOnly != null) { | 346 | } // optionalAttrs (cfg.archiveReadOnly != null) { |
diff --git a/src/config.rs b/src/config.rs index 5c9303c..30e77ab 100644 --- a/src/config.rs +++ b/src/config.rs | |||
| @@ -466,10 +466,9 @@ pub struct Config { | |||
| 466 | #[arg(long, env = "NGIT_EVENT_BLACKLIST", default_value = "")] | 466 | #[arg(long, env = "NGIT_EVENT_BLACKLIST", default_value = "")] |
| 467 | pub event_blacklist: String, | 467 | pub event_blacklist: String, |
| 468 | 468 | ||
| 469 | /// Maximum total connections to the relay (default: 4096) | 469 | /// Maximum total connections to the relay (default: unlimited, defers to OS/infrastructure limits) |
| 470 | /// Prevents connection exhaustion DoS attacks | 470 | #[arg(long, env = "NGIT_MAX_CONNECTIONS")] |
| 471 | #[arg(long, env = "NGIT_MAX_CONNECTIONS", default_value_t = 4096)] | 471 | pub max_connections: Option<usize>, |
| 472 | pub max_connections: usize, | ||
| 473 | 472 | ||
| 474 | /// Log level for application logging | 473 | /// Log level for application logging |
| 475 | #[arg(long, env = "NGIT_LOG_LEVEL", default_value = "info")] | 474 | #[arg(long, env = "NGIT_LOG_LEVEL", default_value = "info")] |
| @@ -755,7 +754,7 @@ impl Config { | |||
| 755 | repository_whitelist: String::new(), | 754 | repository_whitelist: String::new(), |
| 756 | repository_blacklist: String::new(), | 755 | repository_blacklist: String::new(), |
| 757 | event_blacklist: String::new(), | 756 | event_blacklist: String::new(), |
| 758 | max_connections: 500, | 757 | max_connections: None, |
| 759 | log_level: "debug".to_string(), | 758 | log_level: "debug".to_string(), |
| 760 | } | 759 | } |
| 761 | } | 760 | } |
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs index 03132bf..02ba84b 100644 --- a/src/nostr/builder.rs +++ b/src/nostr/builder.rs | |||
| @@ -736,7 +736,7 @@ pub async fn create_relay( | |||
| 736 | let write_policy = | 736 | let write_policy = |
| 737 | Nip34WritePolicy::new(database.clone(), &git_data_path, purgatory, config.clone()); | 737 | Nip34WritePolicy::new(database.clone(), &git_data_path, purgatory, config.clone()); |
| 738 | 738 | ||
| 739 | let relay = LocalRelayBuilder::default() | 739 | let mut builder = LocalRelayBuilder::default() |
| 740 | .database(database.clone()) | 740 | .database(database.clone()) |
| 741 | .write_policy(write_policy.clone()) | 741 | .write_policy(write_policy.clone()) |
| 742 | // Explicitly set rate limits (make defaults visible in code) | 742 | // Explicitly set rate limits (make defaults visible in code) |
| @@ -744,10 +744,13 @@ pub async fn create_relay( | |||
| 744 | .rate_limit(RateLimit { | 744 | .rate_limit(RateLimit { |
| 745 | max_reqs: 500, // Max concurrent subscriptions per connection | 745 | max_reqs: 500, // Max concurrent subscriptions per connection |
| 746 | notes_per_minute: 60, // Max events per minute per connection | 746 | notes_per_minute: 60, // Max events per minute per connection |
| 747 | }) | 747 | }); |
| 748 | // Total connection limit to prevent DoS attacks | 748 | |
| 749 | .max_connections(config.max_connections) | 749 | if let Some(max) = config.max_connections { |
| 750 | .build(); | 750 | builder = builder.max_connections(max); |
| 751 | } | ||
| 752 | |||
| 753 | let relay = builder.build(); | ||
| 751 | 754 | ||
| 752 | tracing::info!( | 755 | tracing::info!( |
| 753 | "Relay configured with GRASP-01 validation for domain: {}", | 756 | "Relay configured with GRASP-01 validation for domain: {}", |