Skip to main content Skip to navigation Skip to footer

Rules of Rediacc

Essential rules and conventions for building applications on the Rediacc platform. Covers Rediaccfile, compose, networking, storage, CRIU, and deployment.

Rules of Rediacc

Every Rediacc repository runs inside an isolated environment with its own Docker daemon, encrypted LUKS volume, and dedicated IP range. These rules ensure your application works correctly within this architecture.

Rediaccfile

  • Every repository needs a Rediaccfile — a bash script with lifecycle functions.
  • Lifecycle functions: up(), down(). Optional: info().
  • up() starts your services. down() stops them.
  • info() provides status information (container state, recent logs, health).
  • Rediaccfile is sourced by renet — it has access to shell variables, not just env vars.

Available environment variables in Rediaccfile

VariableExampleDescription
REDIACC_WORKING_DIR/mnt/rediacc/mounts/abc123/Root path of the mounted repo
REDIACC_NETWORK_ID6336Network isolation identifier
REDIACC_REPOSITORYabc123-...Repository GUID
{SVCNAME}_IPHEARTBEAT_IP=127.0.24.195Per-service loopback IP (uppercase service name)

Minimal Rediaccfile

#!/bin/bash

_compose() {
  renet compose -- "$@"
}

up() {
  _compose up -d
}

down() {
  _compose down
}

Compose

  • Use renet compose, never docker compose — renet injects network isolation, host networking, loopback IPs, and service labels.
  • Do NOT set network_mode in your compose file — renet forces network_mode: host on all services. Any value you set is overwritten.
  • Do NOT set rediacc.* labels — renet auto-injects rediacc.network_id, rediacc.service_ip, and rediacc.service_name.
  • ports: mappings are ignored in host networking mode. Add rediacc.service_port label for HTTP routing (services without this label don’t get HTTP routes). Use rediacc.tcp_ports/rediacc.udp_ports labels for TCP/UDP forwarding.
  • Restart policies (restart: always, on-failure, etc.) are safe to use — renet auto-strips them for CRIU compatibility. The router watchdog auto-recovers stopped containers based on the original policy saved in .rediacc.json.
  • Dangerous settings are blocked by defaultprivileged: true, pid: host, ipc: host, and host bind mounts to system paths are rejected. Use renet compose --unsafe to override at your own risk.

Environment variables inside containers

Renet auto-injects these into every container:

VariableDescription
SERVICE_IPThis container’s dedicated loopback IP
REDIACC_NETWORK_IDNetwork isolation ID

Service naming and routing

  • The compose service name becomes the auto-route URL prefix.
  • Grand repos: https://{service}.{repo}.{machine}.{baseDomain} (e.g., https://myapp.marketing.server-1.example.com).
  • Fork repos: https://{service}-{tag}.{machine}.{baseDomain} — uses the machine wildcard cert to avoid Let’s Encrypt rate limits.
  • For custom domains, use Traefik labels (but note: custom domains are NOT fork-friendly — the domain belongs to the grand repo).

Networking

  • Each repository gets its own Docker daemon at /var/run/rediacc/docker-<networkId>.sock.
  • Each service gets a unique loopback IP within a /26 subnet (e.g., 127.0.24.192/26).
  • Bind to SERVICE_IP — each service gets a unique loopback IP.
  • Health checks must use ${SERVICE_IP}, not localhost. Example: healthcheck: test: ["CMD", "curl", "-f", "http://${SERVICE_IP}:8080/health"]
  • Inter-service communication: Use loopback IPs or SERVICE_IP env var. Docker DNS names do NOT work in host mode.
  • Port conflicts are impossible between repositories — each has its own Docker daemon and IP range.
  • TCP/UDP port forwarding: Add labels to expose non-HTTP ports:
    labels:
      - "rediacc.tcp_ports=5432,3306"
      - "rediacc.udp_ports=53"

Storage

  • All Docker data is stored inside the encrypted repo — Docker’s data-root is at {mount}/.rediacc/docker/data inside the LUKS volume. Named volumes, images, and container layers are all encrypted, backed up, and forked automatically.
  • Bind mounts to ${REDIACC_WORKING_DIR}/... are recommended for clarity, but named volumes also work safely.
    volumes:
      - ${REDIACC_WORKING_DIR}/data:/data        # bind mount (recommended)
      - pgdata:/var/lib/postgresql/data      # named volume (also safe)
  • The LUKS volume is mounted at /mnt/rediacc/mounts/<guid>/.
  • BTRFS snapshots capture the entire LUKS backing file, including all bind-mounted data.
  • The datastore is a fixed-size BTRFS pool file on the system disk. Use rdc machine query <name> --system to see effective free space. Expand with rdc datastore resize.

CRIU (Live Migration)

  • Opt-in via label: Add rediacc.checkpoint=true to containers you want to checkpoint. Containers without it (databases, caches) start fresh and recover via their own mechanisms (WAL, LDF, AOF).
  • backup push --checkpoint captures running process memory + disk state for labeled containers.
  • repo fork --checkpoint captures process state before forking — the fork auto-restores on repo up.
  • repo down --checkpoint saves process state before stopping — next repo up auto-restores.
  • repo up auto-detects checkpoint data and restores if found. Use --skip-checkpoint to force fresh start.
  • Dependency-aware restore: Uses compose depends_on to start databases first (wait for healthy), then CRIU-restore app containers.
  • TCP connections become stale after restore — apps must handle ECONNRESET and reconnect.
  • Docker experimental mode is enabled automatically on per-repo daemons.
  • CRIU is installed during rdc config machine setup.
  • /etc/criu/runc.conf is configured with tcp-established for TCP connection preservation.
  • Container security settings are auto-injected for labeled containersrenet compose adds the following to containers with rediacc.checkpoint=true:
    • cap_add: CHECKPOINT_RESTORE, SYS_PTRACE, NET_ADMIN (minimal set for CRIU on kernel 5.9+)
    • security_opt: apparmor=unconfined (CRIU’s AppArmor support is not yet stable upstream)
    • userns_mode: host (CRIU requires init namespace access for /proc/pid/map_files)
  • Containers without the label run with a cleaner security posture (no extra capabilities).
  • Docker’s default seccomp profile is preserved — CRIU uses PTRACE_O_SUSPEND_SECCOMP (kernel 4.3+) to temporarily suspend filters during checkpoint/restore.
  • Do NOT set CRIU capabilities manually in your compose file — renet handles it based on the label.
  • See the heartbeat template for a CRIU-compatible reference implementation.

CRIU-compatible application patterns

  • Handle ECONNRESET on all persistent connections (database pools, websockets, message queues).
  • Use connection pool libraries that support automatic reconnection.
  • Add process.on("uncaughtException") safety net for stale socket errors from internal library objects.
  • Restart policies are auto-managed by renet (stripped for CRIU, watchdog handles recovery).
  • Avoid relying on Docker DNS — use loopback IPs for inter-service communication.

Security

  • LUKS encryption is mandatory for standard repositories. Each repo has its own encryption key.
  • Credentials are stored in the CLI config (~/.config/rediacc/rediacc.json). Losing the config means losing access to encrypted volumes.
  • Never commit credentials to version control. Use env_file and generate secrets in up().
  • Repository isolation: Each repo’s Docker daemon, network, and storage are fully isolated from other repos on the same machine.
  • Agent isolation: AI agents operate in fork-only mode by default. Each repo has its own SSH key with server-side sandbox enforcement (sandbox-gateway ForceCommand). All connections are sandboxed with Landlock LSM, OverlayFS home overlay, and per-repo TMPDIR. Cross-repo filesystem access is blocked by the kernel.

Deployment

  • rdc repo up runs up() in all Rediaccfiles.
  • rdc repo up --mount opens the LUKS volume first, then runs lifecycle. Required after backup push to a new machine.
  • rdc repo down runs down() and stops the Docker daemon.
  • rdc repo down --unmount also closes the LUKS volume (locks the encrypted storage).
  • Forks (rdc repo fork) create a CoW (copy-on-write) clone with a new GUID and networkId. The fork shares the parent’s encryption key.
  • Takeover (rdc repo takeover <fork> -m <machine>) replaces the grand repo’s data with a fork’s data. The grand keeps its identity (GUID, networkId, domains, autostart, backup chain). Old production data is preserved as a backup fork. Use for: test upgrade on fork, verify, then takeover to production. Revert with rdc repo takeover <backup-fork> -m <machine>.
  • Proxy routes take ~3 seconds to become active after deploy. The “Proxy is not running” warning during repo up is informational in ops/dev environments.

Common mistakes

  • Using docker compose instead of renet compose — containers won’t get network isolation.
  • Restart policies are safe — renet auto-strips them and the watchdog handles recovery.
  • Using privileged: true — not needed, renet injects specific CRIU capabilities instead.
  • Not binding to SERVICE_IP — causes port conflicts between repos.
  • Hardcoding IPs — use SERVICE_IP env var; IPs are allocated dynamically per networkId.
  • Forgetting --mount on first deploy after backup push — LUKS volume needs explicit opening.
  • Using rdc term -c as a workaround for failed commands — report bugs instead.
  • repo delete performs full cleanup including loopback IPs and systemd units. Run rdc machine prune <name> to clean leftovers from legacy deletions.