feat: add HTTPS/TLS server support via rustls

Add optional TLS support for the server using axum-server with the
tls-rustls feature. When --server-cert and --server-key are provided
(and tls feature is enabled), the server binds with TLS instead of
plain HTTP.

Changes:
- Add axum-server dependency with optional tls-rustls feature
- New 'tls' feature flag (independent of 'server')
- --server-cert/--server-key CLI args gated behind tls feature
- ServerConfig extended with cert_file/key_file fields
- Conditional TLS/HTTP binding in server mod.rs
- Fix PathBuf::to_str().unwrap() panic risk -> to_string_lossy()
- Update README.md and DESIGN.md with TLS documentation
This commit is contained in:
2026-03-12 22:18:42 -03:00
parent 237a581429
commit bee980605f
8 changed files with 569 additions and 124 deletions

View File

@@ -67,6 +67,14 @@ pub struct ServerConfig {
/// Pre-hashed password (Unix crypt format) for secure authentication. Preferred
/// over plain text password for production use.
pub password_hash: Option<String>,
/// Optional path to TLS certificate file (PEM).
///
/// When both cert_file and key_file are set, the server uses HTTPS.
pub cert_file: Option<PathBuf>,
/// Optional path to TLS private key file (PEM).
///
/// When both cert_file and key_file are set, the server uses HTTPS.
pub key_file: Option<PathBuf>,
}
/// Application state shared across all routes.

View File

@@ -52,6 +52,8 @@ pub fn mode_server(
port: Some(server_port),
password: settings.server_password(),
password_hash: settings.server_password_hash(),
cert_file: settings.server_cert_file(),
key_file: settings.server_key_file(),
};
// Create ItemService once
@@ -138,14 +140,31 @@ async fn run_server(
let addr: SocketAddr = bind_address.parse()?;
// Build the app into a service
let service = app.into_make_service_with_connect_info::<SocketAddr>();
// Use TLS if both cert and key files are provided
#[cfg(feature = "tls")]
if let (Some(cert_file), Some(key_file)) = (&config.cert_file, &config.key_file) {
info!("SERVER: HTTPS server listening on {addr}");
use axum_server::tls_rustls::RustlsConfig;
let tls_config = RustlsConfig::from_pem_file(cert_file, key_file)
.await
.map_err(|e| anyhow::anyhow!("Failed to load TLS config: {e}"))?;
axum_server::bind_rustls(addr, tls_config)
.serve(service)
.await?;
return Ok(());
}
info!("SERVER: HTTP server listening on {addr}");
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await?;
axum::serve(listener, service).await?;
Ok(())
}