diff --git a/CHANGELOG.md b/CHANGELOG.md index c6bfa67e..df3f7cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.1] - 2026-04-XX + +This version includes **multiple breaking changes**. If you are upgrading from v0.15.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_16.md) for more information on how to upgrade from previous versions. + +## Added +- New `STALWART_BASE_URL` to override the base URL used in HTTP responses, including port if necessary. + +## Changed + +## Fixed + ## [0.16.0] - 2026-04-20 This version includes **multiple breaking changes**. If you are upgrading from v0.15.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_16.md) for more information on how to upgrade from previous versions. diff --git a/UPGRADING/v0_16.md b/UPGRADING/v0_16.md index 6b7ba297..ad2a050c 100644 --- a/UPGRADING/v0_16.md +++ b/UPGRADING/v0_16.md @@ -55,7 +55,7 @@ Because so much has changed, `v0.16` will feel like a different product at first It is **strongly recommended** that operators first install a fresh `v0.16` instance in a Docker container or a throwaway virtual machine, log into the new WebUI, and spend time becoming familiar with how configuration works in the new release. This avoids the situation where a critical production upgrade is the first time an operator sees the new interface. -A second, equally important benefit: any settings created in the test deployment (directory integrations, SMTP listeners, spam rules, rate limits, TLS providers, etc.) can be exported using the [`snapshot`](https://stalw.art/docs/management/cli/snapshot) command. The resulting JSON file is an `apply` plan that can be fed directly into the production instance after the migration completes. Time spent on a test deployment is not thrown away. +A second, equally important benefit: any settings created in the test deployment (directory integrations, SMTP listeners, spam rules, rate limits, TLS providers, etc.) can be exported using the [`snapshot`](https://stalw.art/docs/management/cli/overview/snapshot) command. The resulting JSON file is an `apply` plan that can be fed directly into the production instance after the migration completes. Time spent on a test deployment is not thrown away. ## How the migration works @@ -267,7 +267,7 @@ $ sudo -u stalwart env \ The migration output will scroll past. When it finishes, the process stays in the foreground, listening on port `8080`. Leave this terminal open. -**6. Apply the exported snapshot.** From a **second terminal** (on the same host or any machine that can reach the server on port `8080`), install the new CLI: instructions at https://stalw.art/docs/management/cli: and run: +**6. Apply the exported snapshot.** From a **second terminal** (on the same host or any machine that can reach the server on port `8080`), install the new CLI: instructions at https://stalw.art/docs/management/cli/overview: and run: ```bash $ export STALWART_URL=http://127.0.0.1:8080 diff --git a/crates/common/src/config/network.rs b/crates/common/src/config/network.rs index 4e175fee..9250496c 100644 --- a/crates/common/src/config/network.rs +++ b/crates/common/src/config/network.rs @@ -428,12 +428,12 @@ impl Http { Http { url_https: if !bp.registry.is_bootstrap_mode() { - format!("https://{server_name}") + format!("https://{}", bp.registry.base_url().unwrap_or(server_name)) } else { String::new() }, url_http: if !bp.registry.is_bootstrap_mode() { - format!("http://{server_name}") + format!("http://{}", bp.registry.base_url().unwrap_or(server_name)) } else { String::new() }, diff --git a/crates/http-proto/src/context.rs b/crates/http-proto/src/context.rs index 8134c215..a2ac2d46 100644 --- a/crates/http-proto/src/context.rs +++ b/crates/http-proto/src/context.rs @@ -33,14 +33,7 @@ impl<'x> HttpContext<'x> { } else { #[cfg(not(any(feature = "dev_mode", feature = "test_mode")))] { - if !server.registry().is_bootstrap_mode() { - format!( - "{}:{}", - server.core.network.http.url_http, self.session.local_port - ) - } else { - server.core.network.http.url_http.clone() - } + server.core.network.http.url_http.clone() } #[cfg(any(feature = "dev_mode", feature = "test_mode"))] diff --git a/crates/store/src/build/registry.rs b/crates/store/src/build/registry.rs index 1efdab35..16b86689 100644 --- a/crates/store/src/build/registry.rs +++ b/crates/store/src/build/registry.rs @@ -275,6 +275,11 @@ impl RegistryStore { &self.0.env_hostname } + #[inline(always)] + pub fn base_url(&self) -> Option<&str> { + self.0.env_base_url.as_deref() + } + #[inline(always)] pub fn is_recovery_mode(&self) -> bool { self.0.env_recovery_mode @@ -318,6 +323,7 @@ impl RegistryStore { env_cluster_role: cluster_role, env_push_shard_id: push_shard_id, env_hostname: hostname, + env_base_url: None, id_generator: utils::snowflake::SnowflakeIdGenerator::new(), }) .await diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 9c3829f9..d3f3835e 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -217,6 +217,7 @@ pub struct RegistryStoreInner { pub(crate) env_cluster_role: Option, pub(crate) env_push_shard_id: u32, pub(crate) env_hostname: String, + pub(crate) env_base_url: Option, pub(crate) id_generator: SnowflakeIdGenerator, } diff --git a/crates/store/src/registry/local.rs b/crates/store/src/registry/local.rs index e3394f1f..92f5c963 100644 --- a/crates/store/src/registry/local.rs +++ b/crates/store/src/registry/local.rs @@ -47,12 +47,14 @@ impl RegistryStoreInner { let host = gethostname::gethostname(); let host = host.to_string_lossy(); if host.parse::().is_err() { - host.into_owned() + host.to_lowercase() } else { "localhost".to_string() } - }) - .to_lowercase(), + }), + env_base_url: std::env::var("STALWART_BASE_URL") + .ok() + .filter(|u| !u.is_empty()), } } diff --git a/install.sh b/install.sh index 535bb732..56a49f84 100644 --- a/install.sh +++ b/install.sh @@ -207,6 +207,9 @@ write_env_file() { # Override the hostname used in HTTP responses #STALWART_HOSTNAME=mail.example.com +# Override the base URL used in HTTP responses, including port if necessary. +#STALWART_BASE_URL=mail.example.com:8080 + # Enable bootstrap / recovery mode on startup. Accepted: 1, true. Default: false. #STALWART_RECOVERY_MODE=true