Outsider Stage 0.5
Replay and verify a real, sealed Outsider Stage 0.5 intervention chain.
Translation pending
Automatic protection against ransomware, human error and hardware failure. Your bucket, your keys. US$5 per server per month.
SecurityGo · ShellGitHub @arkame-appOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Open source backup agent for Linux, macOS and Windows servers. Sends files straight to your own S3-compatible bucket (AWS S3, Backblaze B2, Wasabi…) with keys that never leave the server; the Arkame panel only gets the file index. Point-in-time restore, signed releases. Apache-2.0.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The open source backup agent behind Arkame:
it backs up a server's folders straight to your own S3-compatible bucket,
with keys that never leave the server, and restores any version back.
It runs on Linux, macOS and Windows (amd64 and arm64). The Arkame panel
schedules the backups and indexes them; the files themselves go from your server
to your bucket and nowhere else.Read the full README ↗The open source backup agent behind Arkame: it backs up a server's folders straight to your own S3-compatible bucket, with keys that never leave the server, and restores any version back.
It runs on Linux, macOS and Windows (amd64 and arm64). The Arkame panel schedules the backups and indexes them; the files themselves go from your server to your bucket and nowhere else.
I'm the founder. This repository is the part of Arkame that runs on your machine, published so you can read exactly what it does before you run it as root. The agent is not a standalone tool: it needs an Arkame account to get its plans (see Limitations).
Documentation: English · Português · Español
In the Arkame panel,
add your bucket and go to Servers → New server. It opens on the system
of the computer you are using and shows the install for it, with a one-time
install code (atk_…, valid for 24 hours).
On the server:
curl -fsSL https://get.arkame.app/install.sh | sudo sh -s -- --token=atk_...);The installer asks for your bucket's access key and secret, tests them against the bucket, registers the server and waits for you to approve it.
Approve the server in the panel and create a backup plan.
See Native install for the options.
The native install is the default. In Docker the plan's pre/post commands, and so the database and Zimbra recipes, do not run (the Containers recipe does: it needs no shell); use it when a container is what you want. The panel shows this command under Docker:
sudo docker run --pull always --rm -it --user 0 --security-opt label=disable --hostname "$(hostname)" -v /etc/arkame:/etc/arkame \
ghcr.io/arkame-app/arkame-agent:latest install --token=atk_... --panel-url=https://save.arkame.app --install-service=false \
&& { sudo docker stop -t 150 arkame-agent >/dev/null 2>&1; sudo docker rm arkame-agent >/dev/null 2>&1; \
sudo docker run -d --name arkame-agent --restart always --stop-timeout 150 --user 0 --security-opt label=disable --hostname "$(hostname)" \
-v /:/host -v /etc/arkame:/etc/arkame ghcr.io/arkame-app/arkame-agent:latest; }
The first container asks for your bucket's access key and secret, tests them against the bucket, registers the server and waits for you to approve it in the panel. Only if that succeeds is the old container (if any) replaced and the service started.
Why the flags:
--pull always: re-running this command is how you update the image;
without the flag Docker reuses the :latest image already on the host. (The
agent program also updates itself between image pulls; see "Automatic
updates" below.)--stop-timeout 150 / stop -t 150: a stopping agent may need up to 150 s
to finish the upload in progress and send the backup's index to the panel.
Docker's default 10 s (or docker rm -f) kills it first and that restore
point is lost.-v /:/host (read-write): the agent reads the folders you back up, and
restores write back to the server, including to the original location.--security-opt label=disable: on SELinux hosts (RHEL, Rocky, Fedora) the
container otherwise cannot read the host or write /etc/arkame. Elsewhere it
does nothing.A plan can use the Containers recipe (agent 0.6.0+). The agent talks to the Docker (or Podman) API over its Unix socket, finds the compose projects and standalone containers on the server, and for each project you pick it saves:
.env files (or the Unraid template), as they are on
disk, Portainer and TrueNAS paths included;docker inspect of each container and the exact image digest;manifest.json.The work folder (/var/lib/arkame/conteineres/<plan>) is private to the agent
and is deleted after each backup. A failed dump or a missing project makes the
backup partial with the reason; it is never reported as complete with an
empty dump.
In Docker, the socket is already reachable through -v /:/host
(/host/run/docker.sock), so the install command does not change. The
agent never uses QNAP's system-docker.sock.
What the panel can and cannot ask:
internal/conteineres/receitas.go), passwords are passed by environment
variable or a temporary file inside the container, never on a command line.internal/conteineres/cliente.go): read-only calls plus exec. The
agent cannot create, stop, delete or pull anything.Access to the Docker socket is equivalent to root on the server: anyone who can use it can run anything. The agent's allow-list limits what the agent does with it, not what the socket allows.
flowchart LR
subgraph server["Your server"]
agent["arkame-agent<br/>(daemon)"]
keys[("/etc/arkame/agent.env<br/>bucket keys, 0600")]
keys --- agent
end
bucket[("Your S3-compatible bucket<br/>AWS S3, Backblaze B2, Wasabi,<br/>Oracle Cloud, MinIO…")]
panel["Arkame panel<br/>save.arkame.app"]
agent -- "file contents (HTTPS, your keys)" --> bucket
agent -- "heartbeat, file index, bucket checks (HTTPS)" --> panel
panel -- "plans, schedules, restore and retention requests" --> agent
┌──────────── your server ────────────┐
│ arkame-agent │ file contents ┌───────────────────┐
│ • walks the folders in the plan │ ───────────────► │ your bucket │
│ • SHA-256 per file, skips unchanged│ your keys │ (versioned) │
│ • uploads (multipart for big files)│ └───────────────────┘
│ • restores with atomic writes │
│ │ index + status ┌───────────────────┐
│ keys stay in /etc/arkame (0600) │ ◄──────────────► │ Arkame panel │
└──────────────────────────────────────┘ plans, restores └───────────────────┘
install generates an Ed25519 key pair on the server and
registers it with the one-time code. Nothing runs until you approve that
server in the panel; the agent then gets a bearer token (renewed by the panel
before it expires) for its calls.HeadObject) to skip
unchanged content, uploads the rest straight to your bucket, and then sends
the session's file index to the panel.The panel never receives your bucket keys and never receives file contents.
This is what the agent does send to the panel (internal/api/types.go and
internal/daemon/daemon.go have the exact payloads):
| Sent to the panel | When |
|---|---|
| Server name (hostname), OS and architecture, agent version, install method (Docker or binary), Ed25519 public key | Enrollment |
| Agent version, OS, service name and scope, path of the agent program | Heartbeat (every 60 s) |
| Your server's IP address | Implicitly, on every request |
| Bucket check results: versioning, Object Lock and lifecycle settings, total bytes and object count in the bucket, access errors | Hourly, and when you click "Test connection" |
| Per-backup file index: object key (the file's path), size, modification time, SHA-256 and the bucket's version ID; plus counters (files, bytes) | End of each backup |
| Up to 8 KB of output from a plan's pre/post-backup command | When that command fails |
| Error messages from failed backups, files and restores | When something fails |
| Names of folders and files, and file sizes, in a folder you open | When you browse folders while creating a plan |
| Containers recipe (Linux): engine version, platform, compose project and service names, images and digests, container state, mount names and paths | At startup, then when it changes (at most every 15 min) |
| Restore progress, and the keys/version IDs deleted by retention | During restores and retention runs |
Never sent: the bucket access key and secret, file contents, the agent's private key.
The panel is the control plane, so be clear about what it can ask the agent to do:
pg_dump), as the user the agent runs as (root or SYSTEM for a system
service). These do not run in the Docker install.If you want a hard limit on what a compromised panel account could reach, run
the agent with less privilege: the native installer without sudo installs a
user service that reads only what that user can read, and bucket credentials
limited to a single bucket keep it away from the rest of your account. Object
Lock in compliance mode keeps versions from being deleted before their retention
date by anyone, the agent included.
The privacy policy (section 3) describes the same data from the legal side.
Every release is built by GitHub Actions from a tag in this repository, after
the test suite passes. checksums.txt covers every archive and binary, and is
signed keyless with Sigstore cosign through the
workflow's GitHub OIDC identity, so there is no long-lived signing key.
VERSION=v0.4.31 # pick a release
gh release download "$VERSION" -R arkame-app/arkame-agent \
-p 'checksums.txt*' -p 'arkame-agent_linux_amd64.tar.gz'
cosign verify-blob checksums.txt \
--signature checksums.txt.sig \
--certificate checksums.txt.pem \
--certificate-identity-regexp '^https://github\.com/arkame-app/arkame-agent/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --ignore-missing -c checksums.txt
The installers (install.sh, install.ps1 and the Windows setup command)
check the downloaded package against checksums.txt and stop without
installing anything on a mismatch, or if the checksum file cannot be fetched.
They check the SHA-256 only; they do not run cosign.
Each command comes from the panel with your install code. As with Docker, it asks for the bucket key, tests it, registers the server, waits for approval and then installs the service (systemd, launchd or a Windows service).
Linux and macOS
curl -fsSL https://get.arkame.app/install.sh | sudo sh -s -- --token=atk_...
Without sudo, the agent is installed for your user only (a user service)
and reads only what you can read. Useful options: --version=vX.Y.Z,
--service-name and --config (one agent per bucket credential),
--no-service. For the full list:
curl -fsSL https://get.arkame.app/install.sh | sh -s -- --help.
Windows: download get.arkame.app/agente.exe
on the server and double-click it. It asks for administrator rights, then for
the install code and the bucket key, in its own window. Downloading and
running in one command line (curl … && agente.exe) is blocked by Microsoft
Defender as a download-and-execute pattern, so the panel no longer offers it.
From an elevated PowerShell, once the file is downloaded, the panel shows a
command that checks its SHA-256 before running setup --token=atk_....
setup checks its own SHA-256 against the release's checksums.txt, copies
itself to C:\Program Files\Arkame and runs install. On Server 2016 use
install.ps1 from an elevated PowerShell.
Manual download. Archives and plain binaries for every platform are on the
releases page; the
container image is ghcr.io/arkame-app/arkame-agent.
sudo /usr/local/bin/arkame-agent status # identity, key fingerprint, enrollment state
sudo /usr/local/bin/arkame-agent check-storage # test the bucket key in the config file
sudo /usr/local/bin/arkame-agent set-storage-keys --restart # replace the key: asks, tests, saves, restarts
sudo /usr/local/bin/arkame-agent uninstall # removes service, config, identity and program
# Installed as root where /usr/local/bin is not root-only (Homebrew on an
# Intel Mac; the installer says so): the program is in /opt/arkame/bin
sudo /opt/arkame/bin/arkame-agent status
sudo /opt/arkame/bin/arkame-agent check-storage
sudo /opt/arkame/bin/arkame-agent set-storage-keys --restart
sudo /opt/arkame/bin/arkame-agent uninstall
# Installed without root (Linux or macOS): no sudo
~/.local/bin/arkame-agent status
~/.local/bin/arkame-agent check-storage --service-scope user
~/.local/bin/arkame-agent set-storage-keys --restart --service-scope user
~/.local/bin/arkame-agent uninstall --service-scope user
Windows (elevated prompt): arkame-agent status, arkame-agent check-storage,
arkame-agent check-snapshot (creates a volume snapshot, reads a file from it
and releases it, the same thing every backup does before reading).
Docker: sudo docker logs --tail 50 arkame-agent, and always restart or stop
with -t 150. Removing the agent leaves your backups in the bucket.
The panel's Local copy tab (server page) gives the exact commands. In short:
# A local copy on this machine: RustFS (open source, S3 compatible) that the
# agent installs, keeps running and writes to, at disk speed.
sudo arkame-agent local-storage install --storage-id <ID> --bucket <BUCKET> --dir /srv/arkame-local
sudo arkame-agent local-storage move --dir /mnt/new-disk/arkame-local # new disk: moves data and versions
sudo arkame-agent local-storage uninstall # removes it (0.5.10+); the data folder stays
sudo arkame-agent local-storage uninstall --delete-data # also deletes the local backups (asks for the bucket name)
# Let another server on the same network back up to this local copy (0.5.4+).
# Prints the "join" command for that server and its key, once. The key only
# reads and writes that server's own folder in the bucket.
sudo arkame-agent local-storage share --server erp-01 --agent-id <SERVER-ID>
sudo arkame-agent local-storage share --list # client keys
sudo arkame-agent local-storage share --revoke <KEY> # remove a server's access
sudo arkame-agent local-storage share --off # listen on this machine only again
# On the other server: checks the certificate fingerprint, tests the key and
# installs the service that writes there.
sudo arkame-agent local-storage join --storage-id <ID> --bucket <BUCKET> \
--endpoint https://192.168.0.10:9900 --fingerprint <SHA256>
sudo arkame-agent local-storage leave --bucket <BUCKET> # undoes the join (0.5.10+; the backups there stay)
On a local copy shared with the network (share), --delete-data warns
before confirming that the backups of the servers that joined it go too.
arkame-agent uninstall asks whether the network copies (join) go too;
with --yes they stay unless you pass --network-copies remove. The
uninstalls tell the panel the storage is gone, so its plans stop being held
for a process that no longer exists.
Each network server gets its own RustFS user whose policy can list, read and
write only its own folder in that bucket (arkame/data/<server id>/), and
cannot delete objects or versions, change versioning or touch the bucket: a
compromised client can neither erase nor read the backups of the other
servers kept on the storage server. Only the storage server's own process, with the RustFS root
credential, purges by the retention policy. Open the port (9900 by default) to
the internal network only.
On Docker (0.5.4+) the same commands run from a one-off container, and the
local copy is a second container (arkame-agent-local, host network); the
panel shows each command ready to paste. Run local-storage uninstall from a
container with --network host -v /:/host (as the panel shows): without them
it cannot tell whether the local copy is still running, nor see the data
folder, and refuses (--local-store-stopped once the local copy container is
removed; --delete-data needs the host root mounted). local-storage leave
likewise refuses while the network copy container (arkame-agent-rede-<BUCKET>)
still runs; when it cannot see the host processes, pass --network-copy-stopped
once that container is removed.
The agent reads /etc/arkame/agent.env (C:\etc\arkame\agent.env on Windows;
~/.config/arkame/agent.env for a user install), readable by root/Administrators
only. Process environment variables override the file.
| Variable | Purpose |
|---|---|
STORAGE_ACCESS_KEY, STORAGE_SECRET_KEY | Bucket credentials. Used only to talk to the bucket. |
STORAGE_BUCKET, STORAGE_REGION, STORAGE_ENDPOINT | Bucket name, region (default us-east-1), endpoint for non-AWS providers |
STORAGE_ID | Storage ID in the panel |
PANEL_URL | Default https://save.arkame.app |
HOST_ROOT | / natively, /host in Docker |
POLL_INTERVAL_SEC, HEARTBEAT_INTERVAL_SEC | Plan/restore polling and heartbeat intervals (default 60) |
TOKEN_PATH, PRIVATE_KEY_PATH, AGENT_ID_PATH, AGENT_ID | Agent identity files (written at enrollment) |
SIBLING_BUCKETS | Buckets served by other agent processes on the same host (the same agent's agent*.env files in the same folder count too, 0.5.10+) |
ARKAME_STATE_DIR | Folder for the local backup state (what the agent already knows about each file, so unchanged files are not re-read). Default /var/lib/arkame/estado under HOST_ROOT (per-user and per-OS equivalents elsewhere); off disables it. Never backed up; safe to delete. Created for the administrator only (on Windows, Administrators and SYSTEM); a pre-existing folder owned by another user is not used: the state then goes to estado/ next to the config file |
ARKAME_STATE | When the local state is used: auto (default) only when the panel offers the batched index (against an older panel the agent re-reads and checks everything, as v0.4.31 did, and writes nothing to the state folder); always also against an older panel; off never |
ARKAME_REHASH_ALL, ARKAME_VERIFY_DAYS, UPLOAD_CONCURRENCY | Force a full re-read on every backup while set (1; the run --rehash-all flag does it for one backup of each plan only); rotating re-verification cycle in days (default 30); files processed in parallel (default 4) |
HTTPS_PROXY and NO_PROXY are not settings the agent reads from the file:
they only count when they are in the environment of the agent process.
agent.env. The unit loads the file
as its EnvironmentFile, so they reach the process; restart the service
afterwards.-e HTTPS_PROXY=... -e NO_PROXY=... on both docker run
commands (the setup one and the daemon one). The file alone has no effect.agent.env itself for its own settings and does not
export it, and the service definition written by install carries no proxy
variables.install, check-storage, run): the
variables must be set in that shell, and kept through sudo.The complete reference (multiple agents per host, re-enrollment, macOS Full Disk Access, OneDrive, permission checks on the service binary) is in the Portuguese usage guide and on arkame.app/en/docs.
Things you should know before relying on it:
checksums.txt against the keys
built into the running program, checks the SHA-256 against both the signed
checksums and the value sent by the panel, runs the new program's
self-test, swaps the file and lets the service manager restart it. The new
program has 5 minutes to get a heartbeat accepted; otherwise the previous
one is put back (the proof is extended, up to 30 minutes after the swap,
while the panel itself is unreachable). On Docker the new program is stored in the config volume
(/etc/arkame/bin/) and the image's program launches it. Turn it off with
ARKAME_AUTO_UPDATE=off (environment or agent.env), switch your
organization to manual updates in the panel, or hold a single server on its
version. arkame-agent update runs the same verified update on demand.
Agents installed before this feature need one last manual update: re-run
the install command (on Linux it also rewrites the systemd unit so the
service may replace its own program).checksums.txt is..pst) included. It is
a copy-only backup (VSS_BT_COPY), so other backup software's history is
untouched, and the snapshot is released as soon as reading ends; the agent
never deletes shadow copies. If a snapshot can't be created (FAT32/exFAT or
network drive, no shadow storage left, not running as administrator), that
drive is read live and the session is completed with a
warning. A plan can turn it off. Test it with
from an elevated prompt. Linux and
macOS read files as they are (no LVM/btrfs snapshots yet); for databases,
dump to a folder first: the panel's plan form has ready-made recipes for
PostgreSQL, MySQL/MariaDB, MongoDB and SQL Server, and one for Zimbra that
exports account by account (a host cron job with Docker, where pre/post
commands do not run). Restoring a Zimbra account only merges: what is in the
mailbox stays, what was missing comes back, nothing is deleted or replaced
(tested on Zimbra 8.8.15, 9 and 10.1). An account exported on 8.8.15 restores
on 10.1, tags and their colors included; a setting the target version does
not accept is mapped to its equivalent or left out with a warning.make build # bin/arkame-agent for this platform
make build-all # cross-compile: linux, darwin, windows; amd64 and arm64
make test # go test -race with coverage
Go 1.25+. Code layout, architecture notes and the development backlog are in docs/DEVELOPMENT.md (Portuguese).
Issues and pull requests are welcome; see CONTRIBUTING.md. Please report vulnerabilities privately as described in SECURITY.md, not in public issues. This project follows the Contributor Covenant.
| Role | Members |
|---|---|
| Committers and reviewers | hugolf |
| Approvers | hugolf |
HTTPS_PROXY, NO_PROXY | Standard proxy variables, honored for panel calls. Read from the process environment only; see below |
snapshot_unavailablearkame-agent check-snapshot [folder]/etc, /usr or /boot fail because
the systemd unit uses ProtectSystem=full; restore elsewhere and copy. The
Docker install can write there./etc/arkame). Such an item
fails with protected_destination: that folder is writable by the service
so it can update itself, and a restored file there would bypass the release
signature. Restore elsewhere and copy.docker stop and
docker restart, but on a reboot docker.service's own stop timeout wins
(often 90 s). Use the native agent, or raise TimeoutStopSec for
docker.service, if a backup must close cleanly on reboot.