Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5b2259e
chore(deps): rebase on Alpine 3.23.4
DavidePrincipi Feb 19, 2026
5338ee2
feat(rclone-gateway): Restic Rest & WebDAV server
DavidePrincipi Feb 12, 2026
614594e
feat(backup): store rclone config in private Redis
DavidePrincipi Feb 13, 2026
307d0d4
feat(backup): event backup-destination-changed
DavidePrincipi Feb 18, 2026
9e41872
feat: migration of node Redis ACLs and backup keys
DavidePrincipi Feb 19, 2026
a307f4b
feat(api-server,agent): obfuscate *key/*pass
DavidePrincipi Apr 3, 2026
56ad90d
feat(backup): add schedule-backup command
DavidePrincipi Apr 10, 2026
fbdffcb
refactor(backup): module-backup output and locking
DavidePrincipi Apr 10, 2026
2c323b6
feat(backup): add run-backup node orchestrator
DavidePrincipi Apr 10, 2026
1aeb3b6
refactor(list-backups): read status from node keys
DavidePrincipi Apr 10, 2026
6acb611
feat(backup): write per-backup prom files
DavidePrincipi Apr 23, 2026
48e35d3
refactor(backup): remove configure-backup action
DavidePrincipi Apr 10, 2026
2bd582d
refactor(backup): simplify cluster backup actions
DavidePrincipi Apr 10, 2026
44a518b
feat(backup): upload cluster backup from run-backup
DavidePrincipi Apr 10, 2026
d056da9
fix(list-backups): repository_path value
DavidePrincipi Apr 14, 2026
87da3ba
chore: fix example of backup repo path
DavidePrincipi Apr 14, 2026
6f9cbd4
feat(backup): persist secrets and UUIDs in dump
DavidePrincipi Apr 14, 2026
9924689
feat: route restic through rclone-gateway REST endpoint
DavidePrincipi Apr 3, 2026
a66aa85
fix(backup): import destinations properly
DavidePrincipi Apr 16, 2026
e5eb815
refactor(backup): use destination_ids list in event
DavidePrincipi Apr 16, 2026
a92b33a
refactor(backup): clean up read-backup-snapshots
DavidePrincipi Apr 16, 2026
345f4ca
fix(rclone-gateway): missing haproxy dir on first setup
DavidePrincipi Apr 17, 2026
4f9a862
feat(backup): add rclone provider, hide secrets
DavidePrincipi Apr 20, 2026
8c191b2
feat(backup): use WebDAV for metadata uploads
DavidePrincipi Apr 21, 2026
1082e2a
fix(restore-module): never remove Traefik
DavidePrincipi May 6, 2026
1e7c66c
feat(read-backup-snapshots): return size and dates
DavidePrincipi May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/agent/htask.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ func obscureTaskInput(jsonStr string) string {
}

func isSensitive(target string) bool {
sensitiveList := []string{"password", "secret", "token"}
sensitiveList := []string{"password", "secret", "token", "key", "pass"}
ltarget := strings.ToLower(target)
for _, sensitive := range sensitiveList {
if strings.HasSuffix(ltarget, sensitive) {
Expand Down
2 changes: 1 addition & 1 deletion core/api-server/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,6 @@ func Init() {
if os.Getenv("SENSITIVE_LIST") != "" {
Config.SensitiveList = strings.Split(os.Getenv("SENSITIVE_LIST"), ",")
} else {
Config.SensitiveList = []string{"password", "secret", "token", "jwt", "admpass", "adminpass"}
Config.SensitiveList = []string{"password", "secret", "token", "jwt", "admpass", "adminpass", "key", "pass"}
}
}
42 changes: 29 additions & 13 deletions core/build-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ printf "CORE_IMAGE=${repobase}/core:%s\n" "${IMAGETAG:-latest}" >> "${core_env_f
printf "REDIS_IMAGE=${repobase}/redis:%s\n" "${IMAGETAG:-latest}" >> "${core_env_file}"
printf "RSYNC_IMAGE=${repobase}/rsync:%s\n" "${IMAGETAG:-latest}" >> "${core_env_file}"
printf "RESTIC_IMAGE=${repobase}/restic:%s\n" "${IMAGETAG:-latest}" >> "${core_env_file}"
printf "RCLONE_IMAGE=${repobase}/rclone:%s\n" "${IMAGETAG:-latest}" >> "${core_env_file}"
printf "SUPPORT_IMAGE=${repobase}/support:%s\n" "${IMAGETAG:-latest}" >> "${core_env_file}"
printf "PROMTAIL_IMAGE=docker.io/grafana/alloy:v1.11.3\n" >> "${core_env_file}"
printf "NODE_EXPORTER_IMAGE=quay.io/prometheus/node-exporter:v1.10.2\n" >> "${core_env_file}"
chmod -c 644 "${core_env_file}"
source "${core_env_file}"
buildah add "${container}" ${core_env_file} /etc/nethserver/core.env
buildah config \
--label="org.nethserver.images=${REDIS_IMAGE} ${RSYNC_IMAGE} ${RESTIC_IMAGE} ${PROMTAIL_IMAGE} ${SUPPORT_IMAGE} ${NODE_EXPORTER_IMAGE}" \
--label="org.nethserver.images=${REDIS_IMAGE} ${RSYNC_IMAGE} ${RESTIC_IMAGE} ${RCLONE_IMAGE} ${PROMTAIL_IMAGE} ${SUPPORT_IMAGE} ${NODE_EXPORTER_IMAGE}" \
--label="org.nethserver.flags=core_module" \
--entrypoint=/ "${container}"
buildah commit "${container}" "${repobase}/${reponame}"
Expand Down Expand Up @@ -124,29 +125,44 @@ buildah commit "${container}" "${repobase}/${reponame}"
buildah rm "${container}"
images+=("${repobase}/${reponame}")

echo "Building the restic/rclone image..."
container=$(buildah from docker.io/library/alpine:3.22.4)
echo "Building the restic image..."
container=$(buildah from docker.io/library/alpine:3.23.4)
reponame="restic"
buildah add "${container}" restic/ /
buildah run ${container} sh <<'EOF'
apk add --no-cache restic rclone
addgroup -S restic
adduser -S -D -H -h /dev/null -s /sbin/nologin -G restic restic
mkdir -v -p -m 0750 /srv/repo
chown -c restic:restic /srv/repo
apk add --no-cache restic
EOF
buildah config \
--cmd='[]' \
--entrypoint='["/usr/bin/restic"]' \
--env='RCLONE_CONFIG=/dev/null' \
--volume=/srv/repo \
${container}
buildah commit "${container}" "${repobase}/${reponame}"
buildah rm "${container}"
images+=("${repobase}/${reponame}")

echo "Building the rclone image..."
container=$(buildah from docker.io/library/alpine:3.23.4)
reponame="rclone"
buildah add "${container}" rclone/ /
buildah run ${container} sh <<'EOF'
addgroup -S rclone -g 101
adduser -u 100 -S -D -h /var/lib/rclone -s /sbin/nologin -G rclone rclone
apk add --no-cache rclone haproxy python3
EOF
buildah config \
--user=rclone:rclone \
--cmd='[]' \
--entrypoint='["/usr/bin/rclone"]' \
--env=RCLONE_CACHE_DIR=/var/cache/rclone \
--env=RCLONE_CONFIG=/etc/rclone/rclone.conf \
--env=RCLONE_UNIX_SOCKET=/var/lib/rclone/rclone.sock \
--env=RCLONE_LOG_SYSTEMD=1 \
${container}
buildah commit "${container}" "${repobase}/${reponame}"
buildah rm "${container}"
images+=("${repobase}/${reponame}")

echo "Building the rsync image..."
container=$(buildah from docker.io/library/alpine:3.22.4)
container=$(buildah from docker.io/library/alpine:3.23.4)
reponame="rsync"
buildah run ${container} -- apk add --no-cache rsync
buildah add "${container}" rsync/entrypoint.sh /entrypoint.sh
Expand All @@ -159,7 +175,7 @@ buildah rm "${container}"
images+=("${repobase}/${reponame}")

echo "Building the support image..."
container=$(buildah from docker.io/library/alpine:3.22.4)
container=$(buildah from docker.io/library/alpine:3.23.4)
reponame="support"
buildah run ${container} -- sh <<'EOF'
apk add --no-cache openvpn gettext-envsubst
Expand Down
11 changes: 11 additions & 0 deletions core/imageroot/etc/systemd/system/backup-timers.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Backup timers (from Redis state)
After=redis.service
Requires=redis.service
ConditionPathExists=/var/lib/nethserver/node/state/rclone

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=runagent -m node schedule-backup start-timers
ExecStop=runagent -m node schedule-backup stop-timers
50 changes: 50 additions & 0 deletions core/imageroot/etc/systemd/system/rclone-gateway.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[Unit]
Description=Rclone Gateway server
After=redis.service
Wants=redis.service backup-timers.service
StartLimitIntervalSec=10s
StartLimitBurst=3
ConditionPathExists=/etc/wireguard/wg0.conf

[Service]
Type=forking
WorkingDirectory=/var/lib/nethserver/node/state
PIDFile=%t/%N.pid
Environment=PODMAN_SYSTEMD_UNIT=%n
Environment=BACKUP_VOLUME=rclone-webdav
EnvironmentFile=/etc/nethserver/core.env
EnvironmentFile=-/var/lib/nethserver/node/state/rclone-webdav.env
Restart=always
TimeoutStopSec=120
TimeoutStartSec=120
SuccessExitStatus=143
ExecStartPre=/bin/rm -f %t/%N.pid %t/%N.cid
ExecStartPre=mkdir -vp rclone haproxy
ExecStartPre=-runagent -m node rclonegwctl write-configuration --rclonedir=rclone --haproxydir=haproxy
ExecStart=/usr/bin/podman run \
--conmon-pidfile=%t/%N.pid \
--cidfile=%t/%N.cid \
--cgroups=no-conmon \
--detach \
--init \
--log-opt=tag=%N \
--replace --name=%N \
--network=host \
--volume=./rclone:/etc/rclone:ro,Z \
--volume=./haproxy:/etc/haproxy:ro,Z \
--volume=${BACKUP_VOLUME}:/srv/repo:z \
--mount=type=tmpfs,tmpfs-size=10M,destination=/var/lib/rclone,chown=true \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this special option really needed?

--volume=/dev/log:/dev/log \
--volume=rclone-cache:/var/cache/rclone:Z \
--entrypoint=rclone-gateway-entrypoint.sh \
--env-file=rclone-webdav.env \
${RCLONE_IMAGE}
ExecStartPost=bash -c '{ while ! exec 3<>/dev/tcp/127.0.0.1/4694; do sleep 5 ; done } &>/dev/null'
ExecReload=runagent -m node rclonegwctl write-configuration --rclonedir=rclone --haproxydir=haproxy
ExecReload=runagent -m node podman exec %N reload-config
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%N.cid -t 115
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%N.cid

[Install]
WantedBy=default.target
Alias=rclone-webdav.service
33 changes: 0 additions & 33 deletions core/imageroot/etc/systemd/system/rclone-webdav.service

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading