mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
chore(deploy): refine systemd and nixos service docs (#3096)
* fix(deploy): simplify systemd service startup * docs(deploy): add nixos systemd service example * docs(deploy): add nixos service guide * chore(deps): update pulsar and pyroscope * docs(deploy): refine nixos service guidance * fix(deploy): use explicit rustfs server entrypoint
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# RustFS NixOS Service Guide
|
||||
|
||||
This guide explains how to use [rustfs.nixos.service.nix](./rustfs.nixos.service.nix) as a starting point for managing RustFS with `systemd` on NixOS.
|
||||
|
||||
## 1. What the example does
|
||||
|
||||
The NixOS example is designed for the current RustFS startup model:
|
||||
|
||||
- `Type = "notify"` so `systemd` waits for RustFS to publish `READY=1`
|
||||
- a dedicated `rustfs` system user instead of running the service as `root`
|
||||
- `WorkingDirectory = "/var/lib/rustfs"` instead of using a log directory as the working directory
|
||||
- `KillMode = "control-group"` and `SendSIGKILL = true` so stuck shutdowns do not leave the unit hanging forever
|
||||
- `StandardOutput = "journal"` and `StandardError = "journal"` so logs stay in `journald`
|
||||
- runtime configuration through `RUSTFS_*` environment variables
|
||||
- secret file wiring through `RUSTFS_ACCESS_KEY_FILE` and `RUSTFS_SECRET_KEY_FILE`
|
||||
|
||||
## 2. Import the example into your NixOS configuration
|
||||
|
||||
You can either copy the contents into your own module, or import it directly and provide `rustfsPkg`.
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = [
|
||||
./deploy/build/rustfs.nixos.service.nix
|
||||
];
|
||||
|
||||
_module.args.rustfsPkg = pkgs.callPackage ./path/to/rustfs/package.nix { };
|
||||
}
|
||||
```
|
||||
|
||||
If you already package RustFS through a flake output or overlay, point `rustfsPkg` at that package instead.
|
||||
|
||||
## 3. Adjust the default paths
|
||||
|
||||
The example uses these defaults:
|
||||
|
||||
- data directory: `/srv/rustfs`
|
||||
- state directory: `/var/lib/rustfs`
|
||||
- log directory: `/var/log/rustfs`
|
||||
|
||||
Before enabling the service, make sure your RustFS volumes and any TLS material match your real deployment layout.
|
||||
|
||||
The example currently sets:
|
||||
|
||||
```nix
|
||||
RUSTFS_VOLUMES = "/srv/rustfs/vol{1...4}";
|
||||
RUSTFS_ADDRESS = "0.0.0.0:9000";
|
||||
RUSTFS_CONSOLE_ENABLE = "true";
|
||||
RUSTFS_CONSOLE_ADDRESS = "0.0.0.0:9001";
|
||||
```
|
||||
|
||||
Update these values to match your storage topology and exposure policy.
|
||||
|
||||
## 4. Wire secrets through runtime files
|
||||
|
||||
Do not put credentials directly into `environment` if they would be stored in the Nix store.
|
||||
|
||||
RustFS supports file-based secrets, so on NixOS the preferred pattern is:
|
||||
|
||||
```nix
|
||||
systemd.services.rustfs.environment = {
|
||||
RUSTFS_ACCESS_KEY_FILE = config.age.secrets.rustfs-access.path;
|
||||
RUSTFS_SECRET_KEY_FILE = config.age.secrets.rustfs-secret.path;
|
||||
};
|
||||
```
|
||||
|
||||
The same shape also works with `sops-nix`, `agenix`, or any other runtime secret manager that exposes files under `/run`.
|
||||
|
||||
## 5. Rebuild and enable the service
|
||||
|
||||
After integrating the unit into your NixOS configuration:
|
||||
|
||||
```bash
|
||||
sudo nixos-rebuild switch
|
||||
sudo systemctl enable --now rustfs
|
||||
```
|
||||
|
||||
## 6. Verify readiness and logs
|
||||
|
||||
Check whether `systemd` sees the service as fully ready:
|
||||
|
||||
```bash
|
||||
systemctl status rustfs
|
||||
systemctl show rustfs -p Type -p ActiveState -p SubState
|
||||
```
|
||||
|
||||
Follow the service logs:
|
||||
|
||||
```bash
|
||||
journalctl -u rustfs -f
|
||||
```
|
||||
|
||||
Look for the point where RustFS reports that startup is complete and `systemd` transitions the unit into the running state.
|
||||
|
||||
## 7. Common NixOS-specific notes
|
||||
|
||||
- If you previously used `SendSIGKILL = false`, expect shutdown behavior to change. The example favors reliable service recovery over indefinite graceful waits.
|
||||
- If your service really needs more startup time, increase `TimeoutStartSec`, but keep it bounded. Very large values can hide broken startup states.
|
||||
- If you must write file logs instead of journald logs, change `StandardOutput` and `StandardError`, then make sure the target path is writable by the `rustfs` user.
|
||||
- If you decide to run as `root`, review the hardening flags again. The example is written for a dedicated unprivileged service user.
|
||||
|
||||
## 8. Validation note
|
||||
|
||||
If your deployment depends on this example directly, validate the final module in your own NixOS environment before rollout. A common check is:
|
||||
|
||||
```bash
|
||||
nix-instantiate --parse /path/to/your/module.nix
|
||||
```
|
||||
|
||||
If you integrate the example into a host configuration or flake, prefer validating it through your normal `nixos-rebuild`, flake check, or CI pipeline as well.
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
rustfsPkg,
|
||||
...
|
||||
}:
|
||||
let
|
||||
dataDir = "/srv/rustfs";
|
||||
stateDir = "/var/lib/rustfs";
|
||||
logDir = "/var/log/rustfs";
|
||||
in
|
||||
{
|
||||
users.groups.rustfs = { };
|
||||
|
||||
users.users.rustfs = {
|
||||
isSystemUser = true;
|
||||
group = "rustfs";
|
||||
home = stateDir;
|
||||
createHome = false;
|
||||
description = "RustFS service user";
|
||||
};
|
||||
|
||||
systemd.services.rustfs = {
|
||||
description = "RustFS Object Storage Server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
# Keep non-secret runtime settings in the unit environment. For secrets,
|
||||
# prefer runtime files so credentials do not land in the Nix store.
|
||||
environment = {
|
||||
RUSTFS_ADDRESS = "0.0.0.0:9000";
|
||||
RUSTFS_CONSOLE_ENABLE = "true";
|
||||
RUSTFS_CONSOLE_ADDRESS = "0.0.0.0:9001";
|
||||
RUSTFS_VOLUMES = "${dataDir}/vol{1...4}";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
NotifyAccess = "main";
|
||||
|
||||
User = "rustfs";
|
||||
Group = "rustfs";
|
||||
|
||||
# Use a state directory instead of a log directory as the cwd so
|
||||
# relative paths do not accidentally resolve under /var/log.
|
||||
WorkingDirectory = stateDir;
|
||||
StateDirectory = "rustfs";
|
||||
LogsDirectory = "rustfs";
|
||||
|
||||
# Explicitly use the server entrypoint instead of relying on legacy
|
||||
# CLI compatibility shims in service management.
|
||||
ExecStart = "${rustfsPkg}/bin/rustfs server";
|
||||
|
||||
LimitNOFILE = 1048576;
|
||||
LimitNPROC = 32768;
|
||||
TasksMax = "infinity";
|
||||
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
StartLimitIntervalSec = "5min";
|
||||
StartLimitBurst = 5;
|
||||
|
||||
# RustFS publishes READY=1 after runtime readiness succeeds. These
|
||||
# values leave room for cold starts without hiding permanently wedged
|
||||
# instances for too long.
|
||||
TimeoutStartSec = "5min";
|
||||
TimeoutStopSec = "45s";
|
||||
KillMode = "control-group";
|
||||
SendSIGKILL = true;
|
||||
|
||||
# Keep the example neutral by default. If your deployment explicitly
|
||||
# wants RustFS to outlive other workloads during OOM, tune this in your
|
||||
# local NixOS configuration.
|
||||
OOMScoreAdjust = 0;
|
||||
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
ProtectHome = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
UMask = "0077";
|
||||
|
||||
ReadWritePaths = [
|
||||
dataDir
|
||||
stateDir
|
||||
logDir
|
||||
];
|
||||
|
||||
StandardOutput = "journal";
|
||||
StandardError = "journal";
|
||||
};
|
||||
};
|
||||
|
||||
# Example secret wiring for sops-nix / agenix style runtime files:
|
||||
#
|
||||
# systemd.services.rustfs.environment = {
|
||||
# RUSTFS_ACCESS_KEY_FILE = config.age.secrets.rustfs-access.path;
|
||||
# RUSTFS_SECRET_KEY_FILE = config.age.secrets.rustfs-secret.path;
|
||||
# };
|
||||
}
|
||||
@@ -16,17 +16,11 @@ Group=rustfs
|
||||
# working directory
|
||||
WorkingDirectory=/opt/rustfs
|
||||
|
||||
# environment variable configuration and main program (Option 1: Directly specify arguments)
|
||||
# Credentials are loaded from /etc/default/rustfs below. Replace the sample values before deployment.
|
||||
ExecStart=/usr/local/bin/rustfs \
|
||||
--address 0.0.0.0:9000 \
|
||||
--volumes /data/rustfs/vol1,/data/rustfs/vol2 \
|
||||
--console-enable
|
||||
|
||||
# environment variable configuration (Option 2: Use environment variables)
|
||||
# rustfs example file see: `../config/rustfs.env`
|
||||
# Environment-driven startup.
|
||||
# rustfs reads address, volumes, console, credentials, and other runtime settings
|
||||
# from RUSTFS_* variables. See `../config/rustfs.env` for an example template.
|
||||
EnvironmentFile=/etc/default/rustfs
|
||||
ExecStart=/usr/local/bin/rustfs $RUSTFS_VOLUMES
|
||||
ExecStart=/usr/local/bin/rustfs server
|
||||
|
||||
# service log configuration
|
||||
LogsDirectory=rustfs
|
||||
@@ -43,8 +37,10 @@ Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
# graceful exit configuration
|
||||
TimeoutStartSec=30s
|
||||
TimeoutStopSec=30s
|
||||
# Type=notify waits for READY=1, so startup timeout must cover RustFS initialization
|
||||
# plus runtime readiness checks on slower disks or cold starts.
|
||||
TimeoutStartSec=120s
|
||||
TimeoutStopSec=45s
|
||||
|
||||
# security settings
|
||||
NoNewPrivileges=true
|
||||
|
||||
Reference in New Issue
Block a user