ReCasaOS is a community continuation fork of IceWhaleTech/CasaOS. Its purpose is to keep the CasaOS ecosystem maintainable by fixing security defects, reliability bugs, dependency drift, unsafe release automation, and deployment gaps while preserving compatibility where that does not weaken the security boundary.
v0.5.2 is released at
EdmundFu-233/ReCasaOS v0.5.2.
All six required components are locked in
release/components.lock.json with immutable
source revisions, artifact digests, licenses, API/schema versions, and passed
compatibility evidence:
| Component | Source |
|---|---|
| Root service | this repository |
| UserService | EdmundFu-233/ReCasaOS-UserService |
| Gateway | EdmundFu-233/ReCasaOS-Gateway |
| Administrative UI | EdmundFu-233/ReCasaOS-UI |
| AppManagement | EdmundFu-233/ReCasaOS-AppManagement |
| Message Bus | EdmundFu-233/ReCasaOS-MessageBus |
| Installer | EdmundFu-233/ReCasaOS-Installer |
The GitHub release carries musl-static Linux binaries (amd64, arm64, arm-7,
riscv64) plus the migration tool, a checksums.txt GPG-signed with the
ReCasaOS release key (fingerprint 65A1BD27 2E10 6BF7 983B 3D13 D3F5 9DC3 10EE 3539; public key in release/recasaos-release.pub),
and a SLSA provenance attestation bound to the release tag and workflow.
Verify before installing:
gpg --import release/recasaos-release.pub
gpg --verify checksums.txt.asc checksums.txt
sha256sum -c checksums.txt
gh attestation verify checksums.txt --repo EdmundFu-233/ReCasaOSInstall only through the offline installer, which verifies every artifact SHA-256 against its bundle manifest before writing anything and never uses the network:
./install.sh --bundle <dir> [--prefix /]Do not use get.casaos.io install or update scripts. Those scripts are
controlled by the upstream CasaOS project and do not install the fixes in
this fork.
v0.5.2 extends the v0.5.0 hardening: root casaos.conf persistence and
Samba configuration publishes now use the descriptor-pinned atomic
replacement, the Samba compare-and-swap publisher resolves every staging,
read, exchange, rollback, quarantine, and cleanup operation against one
pinned config-directory descriptor, and each v2 resumable upload session
holds its staging directory descriptor across chunk writes, assembly, and
the final target commit instead of re-resolving the staging path per call.
The v0.5.1 version was tagged during preparation, but its draft release
was withdrawn before publication: no v0.5.1 release exists.
Post-release hardening on main extends the same boundary: the v1 upload
registry also pins its staging directory and parent per session, and both
registries now prove that the staging name still identifies the pinned
directory inode, quarantine it under an unpredictable name, and refuse to
recursively delete a name that no longer matches.
The full administrative dashboard is still not ready for unrestricted
Internet exposure. Keep it on a private management network or mesh VPN,
even at v0.5.2: post-release hardening continues on main (tracked in
Issues), and an
independent penetration test has not been performed.
The first hardening milestone includes:
- default-off loopback authentication bypass and exact-origin CORS/WebSocket checks;
- access/refresh JWT issuer separation and protected debug routes;
- bounded, traversal-resistant multipart uploads and safer streaming downloads;
- an opt-in, read-only
/public-filesportal confined with Linuxopenat2, served by a separate non-root, systemd-activated process with an isolated network and root filesystem, with share filesystem work delegated to bounded disposable workers, and authenticated by a header-only bearer whose server-side configuration contains only a versioned SHA-256 verifier; - bounded root file/SSH WebSockets, verified local SSH host keys, one-use SSH login tickets, and removal of an SSH infinite retry path;
- capability-bound outbound fetches with exact endpoint allowlists and DNS/redirect/IP revalidation;
- fail-closed cloud OAuth recovery until one-time state and PKCE are available;
- maintained archive/OpenAPI implementations and upgraded vulnerable dependencies;
- secret-safe request/OAuth logging, restrictive file permissions, CodeQL, Dependabot, reachable-vulnerability CI, and a default-branch-controlled exact-SHA promotion path for trusted-only privileged tests;
- reviewed Caddy/Nginx edge examples, a threat model, and explicit component release gates.
See the threat model for the remaining blockers and the component lock policy for the full-stack boundary.
GitHub-hosted runners provide passwordless sudo; the normal fork-PR workflow
is therefore not a sandbox for arbitrary contributor code. ReCasaOS does not
give fork or Dependabot code a write token or repository secrets. Trusted-only
filesystem tests for those PRs must be promoted by a maintainer from the
default branch, using the PR's complete immutable head SHA. The workflow pins
that object to a one-time same-repository ref, proves the commit and tree before
testing, runs with read-only contents permission and no persisted checkout
credential or shared cache, then revalidates the still-current PR head before
publishing ReCasaOS / trusted privileged exact-SHA on that SHA.
See the trusted privileged CI runbook
for the review, dispatch, verification, branch-protection, and rollback gates.
Issue #27 remains open
until the workflow is validated from main, the exact status provider is
required by branch protection, and both stale-head and external-PR behavior are
recorded. A skipped job is not privileged-test evidence.
The full administrative dashboard is not ready for unrestricted Internet
exposure. Keep it on a private management network or mesh VPN. ReCasaOS now
has a separate read-only public file binary. A systemd socket owns the dedicated
literal-loopback listener (default 127.0.0.1:39777) and passes it to a
non-root service whose network and filesystem views are isolated from the
privileged CasaOS daemon. The socket is not automatically enabled. The examples
in the public-access guide proxy only that
listener and positive route allowlist. Gateway's /public-files registration
is an intentional 404 tombstone for stale-route cleanup and is never the portal
upstream.
A particular host is not public-ready until the guide's deployment, restore, scanning, and independent-review gates pass. The standalone coordinator now keeps share open, classification, list, and read syscalls in same-binary disposable workers. It admits at most eight active workers, applies fixed IPC deadlines, kills timed-out children through pidfds, and stops admitting work when killed children cannot be reaped. A non-ESRCH pidfd signaling failure closes all further worker admission and retains that slot until the child is reaped. The packaged service reports readiness only after bootstrap succeeds and the HTTP server enters its accept loop. Issue #25 remains open until exact-head Linux CI and real hung-storage/D-state tests prove those bounds on the supported deployment stack. The declared systemd 247 floor is qualified only for commits whose dedicated Debian 11/systemd 247 PID-1 VM job passes; the Ubuntu 24.04/systemd 255 integration job is not evidence for that floor. That hosted job runs the normal production build for activation, sandbox and API smoke checks. Only its deterministic worker-capacity and coordinator-cleanup phases swap in a non-release, CI-tagged binary whose exact synthetic fixture worker stops itself after one successful read. This proves admission, pidfd cancellation and control-group cleanup mechanics; it is not byte-identical release evidence and does not simulate uninterruptible storage.
The portal's large-file browser stream is still a candidate tracked in
Issue #20. Its client does
not intentionally persist the bearer in browser storage or a URL. During an
authorized request the bearer necessarily passes through page, Worker,
Authorization-header, edge, and server request memory. Stable
Chromium/Firefox/WebKit HTTPS storage, log, crash, download, memory,
transparent retry/resume, cancellation, and filename tests remain release
gates; stable initial-Range behavior is also not yet a release claim.
The repository's browser smoke job is deliberately narrower: it runs the
bundled Playwright Chromium, Firefox, and WebKit engines on Ubuntu 24.04
against the real portal handler over loopback HTTPS, using an ephemeral CA
installed into that disposable runner's trust stores. It does not disable TLS
verification, record traces/HAR/video, receive production credentials, or run
the production systemd service. Passing that job is useful frontend protocol
evidence. It also makes one explicit initial byte-range request per bundled
engine and checks the authenticated upstream counter and 206 response, but
that is not stable Chrome/Firefox/Safari, proxy, target-host, transparent
retry/resume, or Internet-readiness evidence and does not close Issue #20.
Its cancel smoke has a deliberately narrower meaning: all three engines must
report the local download as canceled to Playwright, and exactly one authorized
upstream request must reach a terminal state within the 40-second test-harness
deadline. Chromium and WebKit must classify that request as canceled; Firefox
may classify it as canceled or completed. That Firefox outcome is consistent
with Mozilla's open
Bug 1825388, in which
response-body cancellation is not propagated to a Service Worker, but the
native-download path exercised here is not identical. It proves that the test
fixture does not retain an active slot; it does not prove Firefox cancel
propagation or satisfy Issue #20's release gate.
The same bundled-engine matrix now also requires an already consumed navigation
proof to fail replay without another authorization challenge or upstream
request, and requires forgetting the page token to abort an already handed,
still-active upstream stream. These are repository CI checks, not evidence of
retail-browser, reverse-proxy, token-rotation, or target-host readiness.
The portal also verifies the already-pinned root descriptor's Linux mount ID and filesystem type before it becomes available. Only ext2/3/4, XFS, Btrfs, tmpfs, and F2FS are allowlisted; FUSE, network filesystems, overlayfs, ZFS, and unknown or unverified types fail startup. There is no unrestricted fallback. This keeps unsupported roots out of the isolated service's download-slot boundary; it does not certify the health or locality of an allowlisted filesystem's block device. Issue #22 remains open until the compatibility and blocking-I/O boundary is independently verified. The worker protocol limits coordinator exposure, but SIGKILL cannot complete a kernel syscall already stuck in uninterruptible sleep. Admission quarantine and the service cgroup provide finite containment; hostile-storage evidence remains tracked in Issue #25.
The supported credential candidate is verifier-only. Generate the 47-character
rc1_ bearer from 32 random bytes on an independent administrator workstation,
keep its durable copy only in a password manager, and provision only the strict
versioned SHA-256 verifier as host credential material. Authorized HTTPS
requests still carry the bearer transiently to the edge and portal process. The
standalone service receives the verifier through systemd LoadCredential= and
a strict CLI path; it has no environment-variable configuration fallback.
Every non-empty legacy RECASAOS_PUBLIC_FILE_* setting fails startup so an old
root-daemon drop-in cannot silently influence the new boundary. Verifier
format, bind-alias, rotation, and rollback hardening was completed and reviewed
in Issue #26.
Never expose Samba, SSH, daemon ports, debug/API documentation, setup routes,
privileged v1/v2/v3 APIs, the dedicated portal listener, or root/Gateway
listeners directly. Keep the management Gateway on a firewalled private/VPN
address and non-public port; public 80/443 belong only to the route-allowlisted
TLS edge. Never enable RECASAOS_TRUST_LOOPBACK_AUTH_BYPASS=1 behind a reverse
proxy. The Nginx example includes rate and connection limits; a public stock
Caddy deployment needs a separately reviewed rate-limiting edge/WAF in front.
The private administrative file APIs fail closed outside the roots in
RECASAOS_MANAGEMENT_FILE_ROOTS. The value is a comma-separated list of
canonical absolute directories; when unset it defaults to /DATA,/mnt,/media.
Every configured root must already exist, / is forbidden, and ReCasaOS pins
the roots at startup before it registers file routes. Changing the setting or
replacing a configured mount requires a service restart.
This boundary requires Linux 5.8 or newer for openat2 and mount-ID checks,
plus the unified cgroup v2 hierarchy with effective memory and pids controllers
for the worker task, memory, and no-swap limits. The service and socket fail
their conditions before activation when those cgroup v2 files are unavailable.
Before loading the verifier, the standalone service also proves its exact
system.slice membership and validates three individually bound, read-only
cgroup2 files for the effective 512 MiB memory, zero-swap, and 256-task limits.
Reads and writes may cross operator-configured mounts below /mnt or /media
for CasaOS storage compatibility, but recursive deletion refuses to cross a
mount boundary. Treat the host mount namespace and CAP_SYS_ADMIN as trusted
operator controls. Keep the administrative API private/VPN-only even when its
paths are confined; RECASAOS_MANAGEMENT_FILE_ROOTS is not a public sharing
configuration and is separate from the isolated portal share at
/srv/recasaos-public.
Retained .recasaos-transfer-* directories are recovery evidence, not ordinary
temporary files. The managed transfer inventory guide
documents the authenticated, read-only inspection endpoint and its intentionally
non-destructive operator workflow. It does not provide or authorize cleanup.
ReCasaOS supports the service runtime only on a conventional Linux appliance;
Android is not a supported target. Native Darwin builds are a contributor
validation target, not a supported runtime. The root binary on unsupported
platforms exits immediately instead of starting a partially functional service.
The Go toolchain and generator versions are locked in go.mod; the remote
Message Bus OpenAPI input is locked to an immutable commit.
Run the complete build and test suite on Linux:
go generate ./...
go test ./...
go vet ./...
govulncheck ./...On Darwin, compile all native packages and tests without executing the Linux-oriented test suite, then run native vet:
go test -exec=true ./...
go vet ./...The macOS GitHub Actions job repeats these checks and verifies that the root binary rejects unsupported runtime use with a clear, nonzero exit. To validate the complete Linux package graph from any non-Linux development host, use:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go test -exec=true ./...
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go vet ./...-exec=true verifies compilation but does not execute the test binaries.
GitHub Actions executes the full suite on Ubuntu with the patched Go version
recorded in the workflow.
Use ReCasaOS issues for bugs, compatibility work, and scoped roadmap items. Keep one security or reliability problem per commit where practical and include a regression test.
Report vulnerabilities privately through the repository Security tab as described in SECURITY.md. Do not put exploits, credentials, private host details, or personal data in a public issue.
ReCasaOS preserves the upstream module path and binary/service names for compatibility while the component migration is staged. This does not imply endorsement by or affiliation with IceWhaleTech.
CasaOS was created by IceWhaleTech and its contributors. Their history remains in this Git repository, and upstream fixes should retain commit provenance. ReCasaOS is distributed under the repository's Apache-2.0 license.