--no-tls-very-insecure silently overrides --ip, making reverse proxy deployments impossible
Summary
When --no-tls-very-insecure is set, the server unconditionally binds to 127.0.0.1 regardless of the value passed to --ip. This makes it impossible to use frostd behind a reverse proxy unless the proxy shares the same network namespace as the server process.
Description
The documentation for --tls-cert explicitly recommends using a reverse proxy for production deployments:
For production deployments, it's recommended to provide HTTPS using a reverse proxy. In that case, set no_tls_very_insecure instead.
However, the ip() method in args.rs ignores the user-supplied --ip argument when no_tls_very_insecure is set:
frostd/src/args.rs
pub fn ip(&self) -> String {
if self.no_tls_very_insecure {
"127.0.0.1".to_string() // --ip flag is silently ignored
} else {
self.ip.clone()
}
}
And in frostd/src/lib.rs, the bind address is derived from args.ip():
let addr: SocketAddr = format!("{}:{}", args.ip(), args.port).parse()?;
if args.no_tls_very_insecure {
tracing::warn!(
"starting an INSECURE HTTP server at {}. This should be done only \
for testing or if you are providing TLS/HTTPS with a separate \
mechanism (e.g. reverse proxy)",
addr,
);
let listener = tokio::net::TcpListener::bind(addr).await?;
The warning message at runtime even mentions the reverse proxy use case, but addr will always be 127.0.0.1:<port> at this point, making the flag effectively unusable for that deployment pattern.
Expected behaviour
When --no-tls-very-insecure is set alongside --ip 0.0.0.0, the server should bind to 0.0.0.0:<port>, allowing a reverse proxy to reach it from outside the local network namespace.
Suggested fix
Keep --no-tls-very-insecure as-is for its current safe default (localhost only). Add a companion flag --allow-public-no-tls that must be explicitly passed alongside it to permit binding to a non-loopback address. This keeps the opt-in nature of the current flag while making the public bind an additional, deliberate choice:
frostd/src/args.rs
/// Disable TLS/HTTPS. Binds to 127.0.0.1 unless --allow-public-no-tls is also set.
#[arg(short, long, default_value_t = false)]
pub no_tls_very_insecure: bool,
/// Allow binding to the address specified by --ip when --no-tls-very-insecure is set.
/// Only use this if TLS is being handled externally (e.g. a reverse proxy).
#[arg(long, default_value_t = false)]
pub allow_public_no_tls: bool,
pub fn ip(&self) -> String {
if self.no_tls_very_insecure && !self.allow_public_no_tls {
"127.0.0.1".to_string()
} else {
self.ip.clone()
}
}
No changes required in lib.rs. The bind address returned by ip() already flows through to the listener correctly.
--no-tls-very-insecuresilently overrides--ip, making reverse proxy deployments impossibleSummary
When
--no-tls-very-insecureis set, the server unconditionally binds to127.0.0.1regardless of the value passed to--ip. This makes it impossible to usefrostdbehind a reverse proxy unless the proxy shares the same network namespace as the server process.Description
The documentation for
--tls-certexplicitly recommends using a reverse proxy for production deployments:However, the
ip()method inargs.rsignores the user-supplied--ipargument whenno_tls_very_insecureis set:frostd/src/args.rsAnd in
frostd/src/lib.rs, the bind address is derived fromargs.ip():The warning message at runtime even mentions the reverse proxy use case, but
addrwill always be127.0.0.1:<port>at this point, making the flag effectively unusable for that deployment pattern.Expected behaviour
When
--no-tls-very-insecureis set alongside--ip 0.0.0.0, the server should bind to0.0.0.0:<port>, allowing a reverse proxy to reach it from outside the local network namespace.Suggested fix
Keep
--no-tls-very-insecureas-is for its current safe default (localhost only). Add a companion flag--allow-public-no-tlsthat must be explicitly passed alongside it to permit binding to a non-loopback address. This keeps the opt-in nature of the current flag while making the public bind an additional, deliberate choice:frostd/src/args.rsNo changes required in
lib.rs. The bind address returned byip()already flows through to the listener correctly.