Packaging: the binary and package are inbuxa, INBUXA_* settings with STALWART_* fallback

- crates/main: package and [[bin]] renamed to inbuxa; homepage inbuxa.org;
  license AGPL-3.0-only (upstream is dual; the fork takes the AGPL).
- types::branding::env_var reads INBUXA_<name>, falling back to
  STALWART_<name> with a warning, for all nine server settings.
  STALWART_APP_ and STALWART_SPAM_* storage keys are unchanged.
- New-install default paths /var/lib/inbuxa and /var/log/inbuxa.
- Dockerfiles, systemd unit, launchd plist and AppArmor profile renamed.
- Upstream's .github moved to .github-upstream so none of it runs.
- install.sh stubbed: upstream's would install Stalwart.
- Two missed brand strings: the SMTP Received header and the utils user agent.
This commit is contained in:
2026-09-18 11:09:22 -07:00
parent 5ce033e10c
commit d3f0b36dd2
35 changed files with 199 additions and 1205 deletions
Generated
+32 -32
View File
@@ -3923,6 +3923,38 @@ dependencies = [
"utils",
]
[[package]]
name = "inbuxa"
version = "0.16.22"
dependencies = [
"common",
"coordinator",
"dav",
"directory",
"email",
"groupware",
"http 0.16.22",
"http_proto",
"imap",
"jmap",
"managesieve",
"migration",
"pop3",
"registry",
"rustls",
"scim",
"services",
"smtp",
"smtp-proto",
"spam-filter",
"store",
"tikv-jemallocator",
"tokio",
"trc",
"types",
"utils",
]
[[package]]
name = "include-flate"
version = "0.3.4"
@@ -8222,38 +8254,6 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "stalwart"
version = "0.16.22"
dependencies = [
"common",
"coordinator",
"dav",
"directory",
"email",
"groupware",
"http 0.16.22",
"http_proto",
"imap",
"jmap",
"managesieve",
"migration",
"pop3",
"registry",
"rustls",
"scim",
"services",
"smtp",
"smtp-proto",
"spam-filter",
"store",
"tikv-jemallocator",
"tokio",
"trc",
"types",
"utils",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
+14 -14
View File
@@ -21,7 +21,7 @@ RUN rustup target add "$(cat /target.txt)"
COPY --from=planner /recipe.json /recipe.json
RUN RUSTFLAGS="$(cat /flags.txt)" cargo chef cook --target "$(cat /target.txt)" --release --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats" --recipe-path /recipe.json
COPY . .
RUN RUSTFLAGS="$(cat /flags.txt)" cargo build --target "$(cat /target.txt)" --release -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats"
RUN RUSTFLAGS="$(cat /flags.txt)" cargo build --target "$(cat /target.txt)" --release -p inbuxa --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats"
RUN mv "/build/target/$(cat /target.txt)/release" "/output"
FROM docker.io/debian:trixie-slim
@@ -29,18 +29,18 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends ca-certificates curl libcap2-bin && \
rm -rf /var/lib/apt/lists/* && \
groupadd -r -g 2000 stalwart && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M stalwart && \
mkdir -p /etc/stalwart /var/lib/stalwart && \
chown stalwart:stalwart /etc/stalwart /var/lib/stalwart
COPY --from=builder --chmod=0755 /output/stalwart /usr/local/bin/stalwart
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/stalwart
USER stalwart
WORKDIR /var/lib/stalwart
VOLUME ["/etc/stalwart", "/var/lib/stalwart"]
groupadd -r -g 2000 inbuxa && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M inbuxa && \
mkdir -p /etc/inbuxa /var/lib/inbuxa && \
chown inbuxa:inbuxa /etc/inbuxa /var/lib/inbuxa
COPY --from=builder --chmod=0755 /output/inbuxa /usr/local/bin/inbuxa
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/inbuxa
USER inbuxa
WORKDIR /var/lib/inbuxa
VOLUME ["/etc/inbuxa", "/var/lib/inbuxa"]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENV STALWART_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
ENV INBUXA_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$STALWART_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/stalwart"]
CMD ["--config", "/etc/stalwart/config.json"]
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$INBUXA_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/inbuxa"]
CMD ["--config", "/etc/inbuxa/config.json"]
+32 -32
View File
@@ -108,7 +108,7 @@ RUN \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
if [ ! -z "${FDB_ARCH}" ]; then \
RUSTFLAGS="-L /usr/lib" cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "foundationdb s3 redis nats"; \
RUSTFLAGS="-L /usr/lib" cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p inbuxa --no-default-features --features "foundationdb s3 redis nats"; \
fi
RUN \
--mount=type=secret,id=ACTIONS_RESULTS_URL,env=ACTIONS_RESULTS_URL \
@@ -116,7 +116,7 @@ RUN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats"
cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p inbuxa --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats"
# Copy the source code
COPY . .
ENV RUSTC_WRAPPER="sccache" \
@@ -129,8 +129,8 @@ RUN \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
if [ ! -z "${FDB_ARCH}" ]; then \
RUSTFLAGS="-L /usr/lib" cargo zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "foundationdb s3 redis nats" && \
mv /app/target/${TARGET}/release/stalwart /app/artifact/stalwart-foundationdb; \
RUSTFLAGS="-L /usr/lib" cargo zigbuild --release --target ${TARGET} -p inbuxa --no-default-features --features "foundationdb s3 redis nats" && \
mv /app/target/${TARGET}/release/inbuxa /app/artifact/inbuxa-foundationdb; \
fi
# Build generic version
RUN \
@@ -139,8 +139,8 @@ RUN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
cargo zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats" && \
mv /app/target/${TARGET}/release/stalwart /app/artifact/stalwart
cargo zigbuild --release --target ${TARGET} -p inbuxa --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats" && \
mv /app/target/${TARGET}/release/inbuxa /app/artifact/inbuxa
# *****************
# Binary stage
@@ -156,21 +156,21 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends ca-certificates curl tzdata libcap2-bin && \
rm -rf /var/lib/apt/lists/* && \
groupadd -r -g 2000 stalwart && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M stalwart && \
mkdir -p /etc/stalwart /var/lib/stalwart && \
chown stalwart:stalwart /etc/stalwart /var/lib/stalwart
COPY --from=builder --chmod=0755 /app/artifact/stalwart /usr/local/bin/stalwart
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/stalwart
USER stalwart
WORKDIR /var/lib/stalwart
VOLUME ["/etc/stalwart", "/var/lib/stalwart"]
groupadd -r -g 2000 inbuxa && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M inbuxa && \
mkdir -p /etc/inbuxa /var/lib/inbuxa && \
chown inbuxa:inbuxa /etc/inbuxa /var/lib/inbuxa
COPY --from=builder --chmod=0755 /app/artifact/inbuxa /usr/local/bin/inbuxa
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/inbuxa
USER inbuxa
WORKDIR /var/lib/inbuxa
VOLUME ["/etc/inbuxa", "/var/lib/inbuxa"]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENV STALWART_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
ENV INBUXA_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$STALWART_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/stalwart"]
CMD ["--config", "/etc/stalwart/config.json"]
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$INBUXA_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/inbuxa"]
CMD ["--config", "/etc/inbuxa/config.json"]
# *****************
# Runtime image for musl targets
@@ -178,18 +178,18 @@ CMD ["--config", "/etc/stalwart/config.json"]
FROM --platform=$TARGETPLATFORM alpine AS musl
RUN apk add --update --no-cache ca-certificates curl tzdata libcap && \
rm -rf /var/cache/apk/* && \
addgroup -S -g 2000 stalwart && \
adduser -S -D -H -u 2000 -G stalwart -s /sbin/nologin stalwart && \
mkdir -p /etc/stalwart /var/lib/stalwart && \
chown stalwart:stalwart /etc/stalwart /var/lib/stalwart
COPY --from=builder --chmod=0755 /app/artifact/stalwart /usr/local/bin/stalwart
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/stalwart
USER stalwart
WORKDIR /var/lib/stalwart
VOLUME ["/etc/stalwart", "/var/lib/stalwart"]
addgroup -S -g 2000 inbuxa && \
adduser -S -D -H -u 2000 -G inbuxa -s /sbin/nologin inbuxa && \
mkdir -p /etc/inbuxa /var/lib/inbuxa && \
chown inbuxa:inbuxa /etc/inbuxa /var/lib/inbuxa
COPY --from=builder --chmod=0755 /app/artifact/inbuxa /usr/local/bin/inbuxa
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/inbuxa
USER inbuxa
WORKDIR /var/lib/inbuxa
VOLUME ["/etc/inbuxa", "/var/lib/inbuxa"]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENV STALWART_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
ENV INBUXA_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$STALWART_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/stalwart"]
CMD ["--config", "/etc/stalwart/config.json"]
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$INBUXA_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/inbuxa"]
CMD ["--config", "/etc/inbuxa/config.json"]
+14 -14
View File
@@ -53,28 +53,28 @@ COPY Cargo.lock .
COPY crates/ crates/
COPY resources/ resources/
COPY tests/ tests/
RUN cargo build -p stalwart --no-default-features --features "foundationdb s3 redis azure nats" --release
RUN cargo build -p inbuxa --no-default-features --features "foundationdb s3 redis azure nats" --release
FROM debian:trixie-slim AS runtime
COPY --from=builder --chmod=0755 /app/target/release/stalwart /usr/local/bin/stalwart
COPY --from=builder --chmod=0755 /app/target/release/inbuxa /usr/local/bin/inbuxa
COPY --from=builder /usr/lib/libfdb_c.so /usr/lib/libfdb_c.so
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends ca-certificates curl libcap2-bin && \
rm -rf /var/lib/apt/lists/* && \
groupadd -r -g 2000 stalwart && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M stalwart && \
mkdir -p /etc/stalwart /var/lib/stalwart && \
chown stalwart:stalwart /etc/stalwart /var/lib/stalwart && \
setcap 'cap_net_bind_service=+ep' /usr/local/bin/stalwart
groupadd -r -g 2000 inbuxa && \
useradd -r -u 2000 -g 2000 -s /usr/sbin/nologin -M inbuxa && \
mkdir -p /etc/inbuxa /var/lib/inbuxa && \
chown inbuxa:inbuxa /etc/inbuxa /var/lib/inbuxa && \
setcap 'cap_net_bind_service=+ep' /usr/local/bin/inbuxa
USER stalwart
WORKDIR /var/lib/stalwart
VOLUME ["/etc/stalwart", "/var/lib/stalwart"]
USER inbuxa
WORKDIR /var/lib/inbuxa
VOLUME ["/etc/inbuxa", "/var/lib/inbuxa"]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENV STALWART_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
ENV INBUXA_HEALTHCHECK_URL=https://127.0.0.1:443/healthz/live
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$STALWART_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/stalwart"]
CMD ["--config", "/etc/stalwart/config.json"]
CMD curl -fsSk -H "X-Forwarded-For: 127.0.0.1" "$INBUXA_HEALTHCHECK_URL" || curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live || exit 1
ENTRYPOINT ["/usr/local/bin/inbuxa"]
CMD ["--config", "/etc/inbuxa/config.json"]
+7 -3
View File
@@ -45,11 +45,15 @@ The report for every import is in `docs/fork/strip-reports/`. See
## Building
```bash
cargo build --release -p stalwart
cargo build --release -p inbuxa # the binary is target/release/inbuxa
docker build -t inbuxa . # or the container image
```
The binary and package are still named `stalwart` while the packaging is
reworked.
Settings are read from `INBUXA_*` environment variables. An existing Stalwart
install's `STALWART_*` variables still work, with a warning to rename them.
New installs keep their data in `/var/lib/inbuxa` and logs in
`/var/log/inbuxa`. Existing installs keep the paths their configuration
already names, so none of their data moves.
## License and credits
+1 -1
View File
@@ -69,7 +69,7 @@ impl Listeners {
bind: Map::new(vec![
SocketAddr::from_str(&format!(
"[::]:{}",
std::env::var("STALWART_RECOVERY_MODE_PORT")
types::branding::env_var("RECOVERY_MODE_PORT")
.ok()
.and_then(|p| p.parse::<u16>().ok())
.unwrap_or(8080)
+1 -1
View File
@@ -503,7 +503,7 @@ impl Tracers {
}
} else {
// Add default tracer if none were found
let level = std::env::var("STALWART_RECOVERY_MODE_LOG_LEVEL")
let level = types::branding::env_var("RECOVERY_MODE_LOG_LEVEL")
.ok()
.and_then(|level| Level::from_str(&level).ok())
.unwrap_or(Level::Info);
+1 -1
View File
@@ -43,7 +43,7 @@ const HELP: &str = concat!(
env!("CARGO_PKG_VERSION"),
r#"
Usage: stalwart [OPTIONS]
Usage: inbuxa [OPTIONS]
Options:
-c, --config <PATH> Start server with the specified configuration file
+1 -1
View File
@@ -529,7 +529,7 @@ async fn insert_safe_defaults(bp: &mut Bootstrap) -> trc::Result<()> {
ansi: false,
prefix: "stalwart.log".into(),
rotate: LogRotateFrequency::Daily,
path: "/var/log/stalwart".into(),
path: "/var/log/inbuxa".into(),
..Default::default()
})
.into(),
@@ -657,7 +657,7 @@ fn map_dns_server(dns_server: &DnsServerBootstrap) -> Option<registry::schema::s
const DEFAULT_DATA_PATH: &str = if cfg!(target_os = "freebsd") {
"/var/db/stalwart/"
} else {
"/var/lib/stalwart/"
"/var/lib/inbuxa/"
};
fn build_default_bootstrap(server: &Server) -> Bootstrap {
@@ -676,7 +676,7 @@ fn build_default_bootstrap(server: &Server) -> Bootstrap {
in_memory_store: InMemoryStore::Default,
directory: DirectoryBootstrap::Internal,
tracer: Tracer::Log(TracerLog {
path: "/var/log/stalwart/".to_string(),
path: "/var/log/inbuxa/".to_string(),
prefix: "stalwart".to_string(),
ansi: true,
enable: true,
+5 -5
View File
@@ -1,17 +1,17 @@
[package]
name = "stalwart"
name = "inbuxa"
description = "INBUXA Mail and Collaboration Server, a fork of Stalwart"
authors = [ "Stalwart Labs LLC <[email protected]>"]
repository = "https://github.com/stalwartlabs/stalwart"
homepage = "https://stalw.art"
homepage = "https://inbuxa.org"
keywords = ["imap", "jmap", "smtp", "email", "mail", "webdav", "server"]
categories = ["email"]
license = "AGPL-3.0-only OR LicenseRef-SEL"
# Upstream offers AGPL-3.0-only OR LicenseRef-SEL; INBUXA takes the AGPL only.
license = "AGPL-3.0-only"
version = "0.16.22"
edition = "2024"
[[bin]]
name = "stalwart"
name = "inbuxa"
path = "src/main.rs"
[dependencies]
+2 -2
View File
@@ -4143,7 +4143,7 @@ impl Default for Bootstrap {
request_tls_certificate: true,
generate_dkim_keys: true,
data_store: DataStore::RocksDb(RocksDbStore {
path: "/var/lib/stalwart/".to_string(),
path: "/var/lib/inbuxa/".to_string(),
..Default::default()
}),
blob_store: BlobStore::Default,
@@ -4151,7 +4151,7 @@ impl Default for Bootstrap {
in_memory_store: InMemoryStore::Default,
directory: DirectoryBootstrap::Internal,
tracer: Tracer::Log(TracerLog {
path: "/var/log/stalwart/".to_string(),
path: "/var/log/inbuxa/".to_string(),
..Default::default()
}),
dns_server: DnsServerBootstrap::Manual,
+1 -1
View File
@@ -1051,7 +1051,7 @@ impl<T: SessionStream> Session<T> {
}
headers.extend_from_slice(b"by ");
headers.extend_from_slice(self.hostname.as_bytes());
headers.extend_from_slice(b" (Stalwart SMTP) with ");
headers.extend_from_slice(concat!(" (", types::brand!(), " SMTP) with ").as_bytes());
headers.extend_from_slice(match (self.stream.is_tls(), !self.is_authenticated()) {
(true, true) => b"ESMTPS",
(true, false) => b"ESMTPSA",
+3 -3
View File
@@ -31,18 +31,18 @@ impl RegistryStore {
.collect::<String>();
eprintln!();
eprintln!("════════════════════════════════════════════════════════════");
eprintln!("🔑 Stalwart bootstrap mode - temporary administrator account");
eprintln!("🔑 INBUXA bootstrap mode - temporary administrator account");
eprintln!();
eprintln!(" username: admin");
eprintln!(" password: {password}");
eprintln!();
eprintln!("Use these credentials to complete the initial setup at the");
eprintln!("/admin web UI. Once setup is done, Stalwart will provision a");
eprintln!("/admin web UI. Once setup is done, the server will provision a");
eprintln!("permanent administrator and this temporary account will no");
eprintln!("longer apply.");
eprintln!();
eprintln!("This password is shown only once. To pin a credential");
eprintln!("instead, set STALWART_RECOVERY_ADMIN=admin:<password> in the");
eprintln!("instead, set INBUXA_RECOVERY_ADMIN=admin:<password> in the");
eprintln!("env file.");
eprintln!("════════════════════════════════════════════════════════════");
eprintln!();
+7 -7
View File
@@ -17,7 +17,7 @@ pub(crate) enum RegistryInit {
impl RegistryStoreInner {
pub(crate) fn new(local_path: PathBuf) -> Self {
let env_hostname = std::env::var("STALWART_HOSTNAME")
let env_hostname = types::branding::env_var("HOSTNAME")
.ok()
.filter(|h| !h.is_empty())
.unwrap_or_else(|| {
@@ -35,30 +35,30 @@ impl RegistryStoreInner {
store: Store::None,
id_generator: SnowflakeIdGenerator::new(),
node_id: 0,
env_recovery_mode: std::env::var("STALWART_RECOVERY_MODE")
env_recovery_mode: types::branding::env_var("RECOVERY_MODE")
.ok()
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false),
env_recovery_admin: std::env::var("STALWART_RECOVERY_ADMIN")
env_recovery_admin: types::branding::env_var("RECOVERY_ADMIN")
.ok()
.and_then(|v| {
v.split_once(':')
.map(|(a, p)| (a.trim().to_string(), p.trim().to_string()))
})
.filter(|(a, p)| !a.is_empty() && !p.is_empty()),
env_cluster_role: std::env::var("STALWART_ROLE")
env_cluster_role: types::branding::env_var("ROLE")
.ok()
.filter(|r| !r.is_empty()),
env_push_shard_id: std::env::var("STALWART_PUSH_SHARD")
env_push_shard_id: types::branding::env_var("PUSH_SHARD")
.ok()
.and_then(|id| id.parse::<u32>().ok().and_then(|v| v.checked_sub(1)))
.unwrap_or(0),
env_public_url: std::env::var("STALWART_PUBLIC_URL")
env_public_url: types::branding::env_var("PUBLIC_URL")
.ok()
.map(|v| v.trim().trim_end_matches('/').to_string())
.filter(|u| !u.is_empty())
.or_else(|| {
std::env::var("STALWART_HTTPS_PORT").ok().and_then(|p| {
types::branding::env_var("HTTPS_PORT").ok().and_then(|p| {
p.parse::<u16>()
.ok()
.map(|port| format!("https://{}:{}", env_hostname, port))
+19
View File
@@ -45,3 +45,22 @@ macro_rules! brand_url {
"https://inbuxa.org"
};
}
/// Reads one of the server's environment variables by its unprefixed name,
/// such as `RECOVERY_ADMIN`.
///
/// `INBUXA_<name>` wins. `STALWART_<name>` is still read when the new name
/// isn't set, so an existing Stalwart install moves over without editing its
/// environment, and a warning says which variable to rename.
pub fn env_var(name: &str) -> Result<String, std::env::VarError> {
match std::env::var(format!("INBUXA_{name}")) {
Err(std::env::VarError::NotPresent) => {
let legacy = std::env::var(format!("STALWART_{name}"));
if legacy.is_ok() {
eprintln!("Warning: STALWART_{name} is deprecated; set INBUXA_{name} instead.");
}
legacy
}
found => found,
}
}
+1 -1
View File
@@ -145,7 +145,7 @@ pub fn build_http_client(
allow_invalid_certs: bool,
) -> Result<Client, String> {
let mut headers = build_http_headers(raw_headers, username, password, token, content_type)?;
headers.insert(USER_AGENT, "Stalwart/1.0.0".parse().unwrap());
headers.insert(USER_AGENT, "INBUXA/1.0.0".parse().unwrap()); // types::brand!(); utils does not depend on types
match http_client_builder(allow_invalid_certs)
.connect_timeout(timeout)
+32 -4
View File
@@ -103,10 +103,12 @@ repository. Instead:
- Each import's full strip report is committed on `main` under
`docs/fork/strip-reports/<ref>.md` (and `.json`), beside the merge that
brought the release in.
- The snapshot includes upstream's `.github/` workflows, release automation
included. They're kept on `upstream` as upstream shipped them, but must be
disabled or replaced on `main` before the repository is ever pushed
anywhere that runs them.
- The snapshot includes upstream's `.github/`: its CI and release workflows,
workflows that auto-close issues and PRs from anyone not on its allowlist,
issue templates and Dependabot. On `main` the whole directory is moved to
`.github-upstream/`, so GitHub never runs it. Upstream changes to it still
merge there on each sync. INBUXA writes its own `.github/` when the
repository is first published.
### 2.2b What the first import proved (v0.16.22, 2026-09-18)
@@ -179,6 +181,32 @@ one edition.
interoperability, not branding, and renaming them breaks every existing
client. Anything the fork adds uses its own namespace (open: which one).
### 2.5 Packaging
Done 2026-09-18:
- The package and binary are `inbuxa` (`cargo build -p inbuxa`). The binary's
help, banner and every protocol greeting say INBUXA (the branding module,
`types::brand!()`).
- Settings come from `INBUXA_*` environment variables. Each still falls back
to its `STALWART_*` name, with a startup warning to rename it
(`types::branding::env_var`). That covers all nine the server reads:
`HOSTNAME`, `RECOVERY_MODE`, `RECOVERY_ADMIN`, `RECOVERY_MODE_PORT`,
`RECOVERY_MODE_LOG_LEVEL`, `ROLE`, `PUSH_SHARD`, `PUBLIC_URL`, `HTTPS_PORT`.
- **Not renamed, on purpose:** `STALWART_APP_` and the two `STALWART_SPAM_...`
names. They look like environment variables, but they're keys inside the
data store, so renaming them would orphan existing installed apps and
spam-classifier models.
- New installs default to `/var/lib/inbuxa` for data and `/var/log/inbuxa` for
logs. Existing installs keep the paths their configuration names, so no data
moves.
- The container image runs as user `inbuxa` (uid 2000, as upstream), with
`/etc/inbuxa` and `/var/lib/inbuxa` as volumes, `INBUXA_HEALTHCHECK_URL`, and
`inbuxa --config /etc/inbuxa/config.json`. The systemd unit
(`inbuxa.service`), launchd plist and AppArmor profile are renamed to match.
- `install.sh` is a stub that says there's no release yet. Upstream's version
would download and install Stalwart itself.
## 3. Clean room
INBUXA runs on a paid Stalwart Enterprise license, so its maintainer is a
+8 -1065
View File
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,6 @@
#include <tunables/global>
profile stalwart flags=(attach_disconnected) {
profile inbuxa flags=(attach_disconnected) {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
@@ -17,8 +17,8 @@ profile stalwart flags=(attach_disconnected) {
owner /proc/*/net/if_inet6 r,
owner /proc/*/net/ipv6_route r,
# Full write access to /opt/stalwart
/opt/stalwart/** rwk,
# Full write access to /opt/inbuxa
/opt/inbuxa/** rwk,
# Allow creating directories under /tmp
/tmp/ r,
@@ -51,9 +51,9 @@ profile stalwart flags=(attach_disconnected) {
network inet6 dgram bind port 7911,
# Basic system access
/usr/bin/stalwart rix,
/etc/stalwart/** r,
/var/log/stalwart/** w,
/usr/bin/inbuxa rix,
/etc/inbuxa/** r,
/var/log/inbuxa/** w,
# Additional permissions might be needed depending on specific requirements
}
@@ -4,12 +4,12 @@
<plist version="1.0">
<dict>
<key>Label</key>
<string>stalwart.mail</string>
<string>inbuxa.mail</string>
<key>ServiceDescription</key>
<string>Stalwart</string>
<string>INBUXA</string>
<key>ProgramArguments</key>
<array>
<string>__PATH__/bin/stalwart</string>
<string>__PATH__/bin/inbuxa</string>
<string>--config=__PATH__/etc/config.json</string>
</array>
<key>RunAtLoad</key>
@@ -1,5 +1,5 @@
[Unit]
Description=Stalwart Server
Description=INBUXA Server
Conflicts=postfix.service sendmail.service exim4.service
ConditionPathExists=__PATH__/etc/config.json
After=network-online.target
@@ -11,10 +11,10 @@ KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=5
ExecStart=__PATH__/bin/stalwart --config=__PATH__/etc/config.json
SyslogIdentifier=stalwart
User=stalwart
Group=stalwart
ExecStart=__PATH__/bin/inbuxa --config=__PATH__/etc/config.json
SyslogIdentifier=inbuxa
User=inbuxa
Group=inbuxa
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]