This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

bobbin: introduce hostname config

Signed-off-by: Seongmin Lee <git@boltless.me>

author
Seongmin Lee
date (Aug 1, 2026, 8:39 PM +0900) commit 09a96912 parent 58def2e4 change-id sttsqqko
+63 -4
+52 -4
bobbin/crates/bobbin/src/config.rs
··· 1 1 use std::collections::HashSet; 2 + use std::fmt; 2 3 use std::net::SocketAddr; 3 4 use std::path::{Path, PathBuf}; 4 5 use std::str::FromStr; ··· 15 16 "server.binds", 16 17 "server.shutdown_grace_secs", 17 18 "server.debug_bind", 19 + "server.hostname", 18 20 "server.trusted_proxies", 19 21 "hydrant.url", 20 22 "hydrant.start_cursor", ··· 38 40 "BOBBIN_BIND", 39 41 "BOBBIN_SHUTDOWN_GRACE_SECS", 40 42 "BOBBIN_DEBUG_BIND", 43 + "BOBBIN_HOSTNAME", 41 44 "BOBBIN_TRUSTED_PROXIES", 42 45 "BOBBIN_HYDRANT_URL", 43 46 "BOBBIN_START_CURSOR", ··· 106 109 /// never reachable on the public listener. Bind to loopback only. 107 110 #[config(env = "BOBBIN_DEBUG_BIND", default = "")] 108 111 pub debug_bind: String, 112 + 113 + /// Required. Public hostname clients reach this instance on, for example 114 + /// `bobbin.example.com` or `localhost:8090`. Its `did:web` is the audience service-auth 115 + /// tokens must be addressed to, so it has to match the host callers actually use. 116 + #[config(env = "BOBBIN_HOSTNAME", default = "")] 117 + pub hostname: String, 109 118 110 119 /// Reverse proxies in front of bobbin, 111 120 /// each a bare IP address without a port or a CIDR block such as `173.245.48.0/20`. ··· 287 296 } 288 297 } 289 298 299 + impl BobbinConfig { 300 + pub fn validate(&self) -> Result<(), ConfigError> { 301 + let errors: Vec<String> = [ 302 + check( 303 + !self.server.hostname.is_empty(), 304 + "server.hostname mustn't be empty", 305 + ), 306 + self.server.trusted_proxies() 307 + .context("server.trusted_proxies takes a bare IP address or a CIDR block") 308 + .err() 309 + .map(|error| error.to_string()), 310 + ] 311 + .into_iter() 312 + .flatten() 313 + .collect(); 314 + 315 + if errors.is_empty() { 316 + Ok(()) 317 + } else { 318 + Err(ConfigError { errors }) 319 + } 320 + } 321 + } 322 + 323 + fn check(ok: bool, message: &str) -> Option<String> { 324 + (!ok).then(|| message.to_string()) 325 + } 326 + 327 + #[derive(Debug, thiserror::Error)] 328 + pub struct ConfigError { 329 + pub errors: Vec<String>, 330 + } 331 + 332 + impl fmt::Display for ConfigError { 333 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 334 + writeln!(f, "{} configuration problem(s):", self.errors.len())?; 335 + self.errors 336 + .iter() 337 + .try_for_each(|error| writeln!(f, " - {error}")) 338 + } 339 + } 340 + 290 341 pub fn load(path: Option<&PathBuf>) -> anyhow::Result<BobbinConfig> { 291 342 check_envs(std::env::vars().map(|(k, _)| k))?; 292 343 if let Some(p) = path { ··· 301 352 .file(SYSTEM_CONFIG_PATH) 302 353 .load() 303 354 .context("load configuration")?; 304 - config 305 - .server 306 - .trusted_proxies() 307 - .context("server.trusted_proxies takes a bare IP address or a CIDR block")?; 355 + config.validate()?; 308 356 Ok(config) 309 357 } 310 358
+9
bobbin/example.toml
··· 23 23 # Default value: "" 24 24 #debug_bind = "" 25 25 26 + # Required. Public hostname clients reach this instance on, for example 27 + # `bobbin.example.com` or `localhost:8090`. Its `did:web` is the audience service-auth 28 + # tokens must be addressed to, so it has to match the host callers actually use. 29 + # 30 + # Can also be specified via environment variable `BOBBIN_HOSTNAME`. 31 + # 32 + # Default value: "" 33 + #hostname = "" 34 + 26 35 # Reverse proxies in front of bobbin, 27 36 # each a bare IP address without a port or a CIDR block such as `173.245.48.0/20`. 28 37 # Bobbin will read the client address out of `x-forwarded-for`
+2
docker-compose.yml
··· 423 423 restart: unless-stopped 424 424 environment: 425 425 BOBBIN_BIND: 0.0.0.0:8090 426 + # must match the host in the web service's BOBBIN_URL, or every token's aud check fails 427 + BOBBIN_HOSTNAME: bobbin.tngl.boltless.dev 426 428 BOBBIN_HYDRANT_URL: http://hydrant:3000 427 429 BOBBIN_SLINGSHOT_URL: http://hydrant:3000 428 430 BOBBIN_KNOT_ALLOW_PRIVATE: "true"