@@ -12,37 +12,37 @@ import (
1212)
1313
1414const (
15- DefaultAppPort = 4000
16- DefaultLogLevel = "debug"
17- DefaultLogFormat = "json"
18- DefaultPoolMaxConns int32 = 20
19- DefaultPoolMinConns int32 = 5
20- DefaultPoolMaxConnLifetime = 1 * time .Hour
21- DefaultPoolMaxConnIdleTime = 30 * time .Minute
22- DefaultPoolHealthCheck = 1 * time .Minute
23- DefaultJWTAccessTTL = 15 * time .Minute
24- DefaultJWTRefreshTTL = 7 * 24 * time .Hour // 1 week
25- DefaultBillingTrialDays = 7
26- DefaultPluginsDir = "./plugins"
27- DefaultMaxPlugins = 50
28- DefaultPluginHotReload = false
29- DefaultHealthCheckInterval = 10 // seconds
30- DefaultMaxConcurrentChecks = 50
31- DefaultSpeedTestPort = 4203
32- DefaultSubscriptionProxyPort = 4100
33- DefaultCheckoutMaxPerHour = 10
34- DefaultSubscriptionMaxPerDay = 5
35- DefaultLoginMaxPerWindow = 20
36- DefaultLoginWindowMinutes = 15
37- DefaultForgotPwdMaxPerWindow = 3
38- DefaultForgotPwdWindowMinutes = 60
39- DefaultAcceptInvitationMaxPerWindow = 3
40- DefaultAcceptInvitationWindowMinutes = 60
41- DefaultOutboxRelayWorkers = 1
42- DefaultOutboxPartitionLookahead = 2
43- DefaultOutboxRetentionDays = 90
44- DefaultHooksSubscriptionEnabled = false
45- DefaultHooksVPNProviderEnabled = false
15+ DefaultAppPort = 4000
16+ DefaultLogLevel = "debug"
17+ DefaultLogFormat = "json"
18+ DefaultPoolMaxConns int32 = 20
19+ DefaultPoolMinConns int32 = 5
20+ DefaultPoolMaxConnLifetime = 1 * time .Hour
21+ DefaultPoolMaxConnIdleTime = 30 * time .Minute
22+ DefaultPoolHealthCheck = 1 * time .Minute
23+ DefaultJWTAccessTTL = 15 * time .Minute
24+ DefaultJWTRefreshTTL = 7 * 24 * time .Hour // 1 week
25+ DefaultBillingTrialDays = 7
26+ DefaultPluginsDir = "./plugins"
27+ DefaultMaxPlugins = 50
28+ DefaultPluginHotReload = false
29+ DefaultHealthCheckInterval = 10 // seconds
30+ DefaultMaxConcurrentChecks = 50
31+ DefaultSpeedTestPort = 4203
32+ DefaultSubscriptionProxyPort = 4100
33+ DefaultCheckoutMaxPerHour = 10
34+ DefaultSubscriptionMaxPerDay = 5
35+ DefaultLoginMaxPerWindow = 20
36+ DefaultLoginWindowMinutes = 15
37+ DefaultForgotPwdMaxPerWindow = 3
38+ DefaultForgotPwdWindowMinutes = 60
39+ DefaultAcceptInvitationMaxPerWindow = 3
40+ DefaultAcceptInvitationWindowMinutes = 60
41+ DefaultOutboxRelayWorkers = 1
42+ DefaultOutboxPartitionLookahead = 2
43+ DefaultOutboxRetentionDays = 90
44+ DefaultHooksSubscriptionEnabled = false
45+ DefaultHooksVPNProviderEnabled = false
4646
4747 // Smart router default weights — browsing.
4848 DefaultWeightGeo = 0.33
@@ -97,6 +97,12 @@ type JWTConfig struct {
9797 PublicKeyPath string `koanf:"public_key_path"`
9898 AccessTokenTTL time.Duration `koanf:"access_token_ttl"`
9999 RefreshTokenTTL time.Duration `koanf:"refresh_token_ttl"`
100+ // AllowEphemeralKey permits generating a throwaway in-memory signing key when
101+ // the key file is missing. DEV ONLY: an ephemeral key invalidates all tokens
102+ // on restart and makes multi-replica deployments reject each other's tokens,
103+ // so production must ship a real key file. Defaults to false (boot fails if
104+ // the key is absent).
105+ AllowEphemeralKey bool `koanf:"allow_ephemeral_key"`
100106}
101107
102108type RemnawaveConfig struct {
@@ -167,12 +173,12 @@ type TracingConfig struct {
167173
168174// RateLimitConfig holds domain-level rate limit thresholds.
169175type RateLimitConfig struct {
170- CheckoutMaxPerHour int `koanf:"checkout_max_per_hour"`
171- SubscriptionMaxPerDay int `koanf:"subscription_max_per_day"`
172- LoginMaxPerWindow int `koanf:"login_max_per_window"`
173- LoginWindowMinutes int `koanf:"login_window_minutes"`
174- ForgotPwdMaxPerWindow int `koanf:"forgot_pwd_max_per_window"`
175- ForgotPwdWindowMinutes int `koanf:"forgot_pwd_window_minutes"`
176+ CheckoutMaxPerHour int `koanf:"checkout_max_per_hour"`
177+ SubscriptionMaxPerDay int `koanf:"subscription_max_per_day"`
178+ LoginMaxPerWindow int `koanf:"login_max_per_window"`
179+ LoginWindowMinutes int `koanf:"login_window_minutes"`
180+ ForgotPwdMaxPerWindow int `koanf:"forgot_pwd_max_per_window"`
181+ ForgotPwdWindowMinutes int `koanf:"forgot_pwd_window_minutes"`
176182 AcceptInvitationMaxPerWindow int `koanf:"accept_invitation_max_per_window"`
177183 AcceptInvitationWindowMinutes int `koanf:"accept_invitation_window_minutes"`
178184}
@@ -255,38 +261,38 @@ func Load() (*Config, error) {
255261
256262 // Set defaults
257263 defaults := map [string ]any {
258- "app.port" : DefaultAppPort ,
259- "app.version" : DefaultAppVersion ,
260- "app.log_level" : DefaultLogLevel ,
261- "app.log_format" : DefaultLogFormat ,
262- "database.max_conns" : DefaultPoolMaxConns ,
263- "database.min_conns" : DefaultPoolMinConns ,
264- "database.max_conn_lifetime" : DefaultPoolMaxConnLifetime ,
265- "database.max_conn_idle_time" : DefaultPoolMaxConnIdleTime ,
266- "database.health_check_period" : DefaultPoolHealthCheck ,
267- "jwt.access_token_ttl" : DefaultJWTAccessTTL ,
268- "jwt.refresh_token_ttl" : DefaultJWTRefreshTTL ,
269- "billing.trial_days" : DefaultBillingTrialDays ,
270- "plugin.dir" : DefaultPluginsDir ,
271- "plugin.max_plugins" : DefaultMaxPlugins ,
272- "plugin.hot_reload" : DefaultPluginHotReload ,
273- "infra.health_check_interval" : time .Duration (DefaultHealthCheckInterval ) * time .Second ,
274- "infra.max_concurrent_checks" : DefaultMaxConcurrentChecks ,
275- "infra.speed_test_port" : DefaultSpeedTestPort ,
276- "infra.subscription_proxy_port" : DefaultSubscriptionProxyPort ,
277- "ratelimit.checkout_max_per_hour" : DefaultCheckoutMaxPerHour ,
278- "ratelimit.subscription_max_per_day" : DefaultSubscriptionMaxPerDay ,
279- "ratelimit.login_max_per_window" : DefaultLoginMaxPerWindow ,
280- "ratelimit.login_window_minutes" : DefaultLoginWindowMinutes ,
281- "ratelimit.forgot_pwd_max_per_window" : DefaultForgotPwdMaxPerWindow ,
282- "ratelimit.forgot_pwd_window_minutes" : DefaultForgotPwdWindowMinutes ,
283- "ratelimit.accept_invitation_max_per_window" : DefaultAcceptInvitationMaxPerWindow ,
284- "ratelimit.accept_invitation_window_minutes" : DefaultAcceptInvitationWindowMinutes ,
285- "outbox.relay_workers" : DefaultOutboxRelayWorkers ,
286- "outbox.partition_lookahead" : DefaultOutboxPartitionLookahead ,
287- "outbox.retention_days" : DefaultOutboxRetentionDays ,
288- "featureflags.hooks_subscription_enabled" : DefaultHooksSubscriptionEnabled ,
289- "featureflags.hooks_vpn_provider_enabled" : DefaultHooksVPNProviderEnabled ,
264+ "app.port" : DefaultAppPort ,
265+ "app.version" : DefaultAppVersion ,
266+ "app.log_level" : DefaultLogLevel ,
267+ "app.log_format" : DefaultLogFormat ,
268+ "database.max_conns" : DefaultPoolMaxConns ,
269+ "database.min_conns" : DefaultPoolMinConns ,
270+ "database.max_conn_lifetime" : DefaultPoolMaxConnLifetime ,
271+ "database.max_conn_idle_time" : DefaultPoolMaxConnIdleTime ,
272+ "database.health_check_period" : DefaultPoolHealthCheck ,
273+ "jwt.access_token_ttl" : DefaultJWTAccessTTL ,
274+ "jwt.refresh_token_ttl" : DefaultJWTRefreshTTL ,
275+ "billing.trial_days" : DefaultBillingTrialDays ,
276+ "plugin.dir" : DefaultPluginsDir ,
277+ "plugin.max_plugins" : DefaultMaxPlugins ,
278+ "plugin.hot_reload" : DefaultPluginHotReload ,
279+ "infra.health_check_interval" : time .Duration (DefaultHealthCheckInterval ) * time .Second ,
280+ "infra.max_concurrent_checks" : DefaultMaxConcurrentChecks ,
281+ "infra.speed_test_port" : DefaultSpeedTestPort ,
282+ "infra.subscription_proxy_port" : DefaultSubscriptionProxyPort ,
283+ "ratelimit.checkout_max_per_hour" : DefaultCheckoutMaxPerHour ,
284+ "ratelimit.subscription_max_per_day" : DefaultSubscriptionMaxPerDay ,
285+ "ratelimit.login_max_per_window" : DefaultLoginMaxPerWindow ,
286+ "ratelimit.login_window_minutes" : DefaultLoginWindowMinutes ,
287+ "ratelimit.forgot_pwd_max_per_window" : DefaultForgotPwdMaxPerWindow ,
288+ "ratelimit.forgot_pwd_window_minutes" : DefaultForgotPwdWindowMinutes ,
289+ "ratelimit.accept_invitation_max_per_window" : DefaultAcceptInvitationMaxPerWindow ,
290+ "ratelimit.accept_invitation_window_minutes" : DefaultAcceptInvitationWindowMinutes ,
291+ "outbox.relay_workers" : DefaultOutboxRelayWorkers ,
292+ "outbox.partition_lookahead" : DefaultOutboxPartitionLookahead ,
293+ "outbox.retention_days" : DefaultOutboxRetentionDays ,
294+ "featureflags.hooks_subscription_enabled" : DefaultHooksSubscriptionEnabled ,
295+ "featureflags.hooks_vpn_provider_enabled" : DefaultHooksVPNProviderEnabled ,
290296 // Smart router weight defaults.
291297 "smartrouter.weight_geo" : DefaultWeightGeo ,
292298 "smartrouter.weight_latency" : DefaultWeightLatency ,
@@ -298,27 +304,27 @@ func Load() (*Config, error) {
298304 "smartrouter.weight_streaming_latency" : DefaultWeightStreamingLatency ,
299305 "smartrouter.weight_streaming_load" : DefaultWeightStreamingLoad ,
300306 // Speed test defaults.
301- "speedtest.max_concurrent" : DefaultSpeedTestMaxConcurrent ,
307+ "speedtest.max_concurrent" : DefaultSpeedTestMaxConcurrent ,
302308 "speedtest.per_ip_rate_limit" : DefaultSpeedTestPerIPRateLimit ,
303- "speedtest.max_upload_bytes" : DefaultSpeedTestMaxUploadBytes ,
309+ "speedtest.max_upload_bytes" : DefaultSpeedTestMaxUploadBytes ,
304310 // Circuit breaker defaults — Remnawave and VPN provider use DefaultConfig
305311 // (with interval), outbox relay and Valkey use DefaultConfigNoInterval.
306312 "circuitbreaker.remnawave.max_failures" : circuitbreaker .DefaultMaxFailures ,
307- "circuitbreaker.remnawave.timeout" : circuitbreaker .DefaultTimeout ,
308- "circuitbreaker.remnawave.max_requests" : circuitbreaker .DefaultMaxRequests ,
309- "circuitbreaker.remnawave.interval" : circuitbreaker .DefaultInterval ,
310- "circuitbreaker.outbox_nats.max_failures" : circuitbreaker .DefaultMaxFailures ,
311- "circuitbreaker.outbox_nats.timeout" : circuitbreaker .DefaultTimeout ,
312- "circuitbreaker.outbox_nats.max_requests" : uint32 (1 ),
313- "circuitbreaker.outbox_nats.interval" : time .Duration (0 ),
314- "circuitbreaker.valkey.max_failures" : circuitbreaker .DefaultMaxFailures ,
315- "circuitbreaker.valkey.timeout" : circuitbreaker .DefaultTimeout ,
316- "circuitbreaker.valkey.max_requests" : circuitbreaker .DefaultMaxRequests ,
317- "circuitbreaker.valkey.interval" : time .Duration (0 ),
318- "circuitbreaker.vpn_provider.max_failures" : circuitbreaker .DefaultMaxFailures ,
319- "circuitbreaker.vpn_provider.timeout" : circuitbreaker .DefaultTimeout ,
320- "circuitbreaker.vpn_provider.max_requests" : circuitbreaker .DefaultMaxRequests ,
321- "circuitbreaker.vpn_provider.interval" : circuitbreaker .DefaultInterval ,
313+ "circuitbreaker.remnawave.timeout" : circuitbreaker .DefaultTimeout ,
314+ "circuitbreaker.remnawave.max_requests" : circuitbreaker .DefaultMaxRequests ,
315+ "circuitbreaker.remnawave.interval" : circuitbreaker .DefaultInterval ,
316+ "circuitbreaker.outbox_nats.max_failures" : circuitbreaker .DefaultMaxFailures ,
317+ "circuitbreaker.outbox_nats.timeout" : circuitbreaker .DefaultTimeout ,
318+ "circuitbreaker.outbox_nats.max_requests" : uint32 (1 ),
319+ "circuitbreaker.outbox_nats.interval" : time .Duration (0 ),
320+ "circuitbreaker.valkey.max_failures" : circuitbreaker .DefaultMaxFailures ,
321+ "circuitbreaker.valkey.timeout" : circuitbreaker .DefaultTimeout ,
322+ "circuitbreaker.valkey.max_requests" : circuitbreaker .DefaultMaxRequests ,
323+ "circuitbreaker.valkey.interval" : time .Duration (0 ),
324+ "circuitbreaker.vpn_provider.max_failures" : circuitbreaker .DefaultMaxFailures ,
325+ "circuitbreaker.vpn_provider.timeout" : circuitbreaker .DefaultTimeout ,
326+ "circuitbreaker.vpn_provider.max_requests" : circuitbreaker .DefaultMaxRequests ,
327+ "circuitbreaker.vpn_provider.interval" : circuitbreaker .DefaultInterval ,
322328 }
323329 for key , val := range defaults {
324330 k .Set (key , val ) //nolint:errcheck // Set on a fresh koanf instance cannot fail
0 commit comments