feat(bundled-binary): release-binaries.yml + install docs + binstall metadata
Adds the tag-triggered workflow that builds 4 musl-linux + macOS tarballs and attaches them to the tag's GitHub Release. Ships a matching install guide (docs/install/binary.md) with SHA256SUMS verify, systemd unit, upgrade flow, and hardware notes. Adds [package.metadata.binstall] so 'cargo binstall oxicloud' works automatically once the first release lands. Also re-enables incremental compilation in the dev profile — the 'modest single-crate savings' rationale from when the crate was small has been outgrown; full rebuild ~10 min is now the dev-loop bottleneck.
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
name: "Release Binaries (musl-linux + macOS)"
|
||||
|
||||
# Per-run title shown in the Actions tab — makes it obvious at a
|
||||
# glance which tag is being packaged and whether a manual run is a
|
||||
# dry-run (build tarballs into workflow artifacts, DON'T attach to
|
||||
# any GitHub Release).
|
||||
run-name: >-
|
||||
Release Binaries
|
||||
${{ github.event_name == 'workflow_dispatch' && inputs.dry_run && '[DRY-RUN]' || '' }}
|
||||
— ${{ github.event.inputs.version || github.ref_name }}
|
||||
|
||||
# TRIGGERS — deliberately narrow. This workflow builds 4 platform
|
||||
# binaries (~15-25 min wall-clock, matrix of native runners) and
|
||||
# attaches them to a GitHub Release. Running on every push to main
|
||||
# would be gratuitous CI cost + noise — the point is to package
|
||||
# releases, not to sanity-check the tip. The bundled-binary
|
||||
# integration test in ci.yml already covers "does the embed still
|
||||
# work" on every PR.
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Existing tag to package (e.g. v0.9.0). Must exist on origin.'
|
||||
required: true
|
||||
dry_run:
|
||||
description: 'Dry run — build + upload tarballs as workflow artifacts, skip attaching to a Release. Use to smoke-test workflow edits without publishing.'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Concurrency key includes the tag ref so different tags don't cancel
|
||||
# each other; `cancel-in-progress: false` because tag builds are
|
||||
# unique + immutable — a superseded release build has nothing to cancel.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
# ── Stage 1: Build the SPA once, share across all platforms ─────────
|
||||
#
|
||||
# The SvelteKit build is arch-independent so a single ubuntu runner
|
||||
# produces static-dist/ for every downstream binary-build matrix
|
||||
# entry — saves ~2 min × 4 = 8 min vs building it per platform.
|
||||
frontend-build:
|
||||
name: Build SPA (Vite → static-dist/)
|
||||
# Publish gate — same fork-friendly pattern as docker-publish.yml.
|
||||
# Canonical repo always builds; forks stay quiet unless the fork
|
||||
# owner opts in via `vars.ENABLE_BINARY_RELEASE=true` under Settings
|
||||
# → Secrets and variables → Actions → Variables.
|
||||
if: |
|
||||
github.repository == 'AtalayaLabs/OxiCloud' ||
|
||||
vars.ENABLE_BINARY_RELEASE == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Build the exact tag being packaged. `github.ref` is
|
||||
# refs/tags/vX.Y.Z on push, refs/heads/... on dispatch (we
|
||||
# override via `inputs.version` in that case).
|
||||
ref: ${{ github.event.inputs.version || github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 26.3.0
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Build SPA
|
||||
working-directory: frontend
|
||||
run: npm ci && npm run build
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: static-dist
|
||||
# Repo-root output (SvelteKit adapter-static's `pages:
|
||||
# '../static-dist'`). Downstream jobs restore it to the same
|
||||
# location so rust-embed's `#[folder = "static-dist/"]`
|
||||
# resolves without any path juggling.
|
||||
path: static-dist/
|
||||
retention-days: 1
|
||||
|
||||
# ── Stage 2: Build one binary per target ────────────────────────────
|
||||
#
|
||||
# 4-way matrix — 2 musl-linux (native amd64 + arm64) + 2 macOS
|
||||
# (Apple Silicon + last Intel runner tier). Windows is deferred.
|
||||
#
|
||||
# Linux builds run inside the `rust:1.96-alpine3.24` container the
|
||||
# Dockerfile already uses — guarantees byte-for-byte parity with the
|
||||
# published Docker image; zero new toolchain to maintain. macOS builds
|
||||
# run natively (no cross-compile). See docs/plan/bundled-binary.md § 3
|
||||
# for the target-matrix rationale.
|
||||
binary-build:
|
||||
name: Build ${{ matrix.triple }}
|
||||
needs: frontend-build
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
# `fail-fast: false` — one platform's compile failure shouldn't
|
||||
# cancel the other three. Partial releases are better than none.
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- triple: x86_64-unknown-linux-musl
|
||||
runner: ubuntu-22.04
|
||||
container: rust:1.96-alpine3.24
|
||||
rustflags: "-C target-cpu=x86-64-v2"
|
||||
- triple: aarch64-unknown-linux-musl
|
||||
runner: ubuntu-22.04-arm
|
||||
container: rust:1.96-alpine3.24
|
||||
# ARMv8-A baseline — covers Pi 4/5, Graviton, every 64-bit
|
||||
# ARM Linux server. `generic` is rustc's neutral baseline.
|
||||
rustflags: "-C target-cpu=generic"
|
||||
- triple: aarch64-apple-darwin
|
||||
runner: macos-latest
|
||||
container: ""
|
||||
rustflags: "-C target-cpu=apple-m1"
|
||||
- triple: x86_64-apple-darwin
|
||||
runner: macos-13
|
||||
container: ""
|
||||
rustflags: "-C target-cpu=x86-64-v2"
|
||||
container: ${{ matrix.container || null }}
|
||||
steps:
|
||||
# Alpine container image doesn't ship the deps our build needs
|
||||
# (git for build.rs's GIT_HASH stamping, musl-dev for aws-lc-sys
|
||||
# C parts, plus the toolchain scaffold from the Dockerfile
|
||||
# builder stage). Install once at job start.
|
||||
- name: Install Alpine build deps
|
||||
if: matrix.container != ''
|
||||
run: apk add --no-cache musl-dev pkgconfig gcc perl make bash git curl tar
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version || github.ref }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
# Key by triple so the 4 targets don't share caches
|
||||
# (different feature set + different target triple = different
|
||||
# compiled artefacts).
|
||||
key: ${{ matrix.triple }}
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: static-dist
|
||||
path: static-dist/
|
||||
|
||||
# rustup targets are pre-installed for the runner's own host
|
||||
# triple; other targets need explicit `rustup target add`. macOS
|
||||
# runners already have both apple-* triples; only touch this in
|
||||
# the container path where rustup's default target list is minimal.
|
||||
- name: Add rustup target
|
||||
if: matrix.container == '' && matrix.triple != ''
|
||||
run: rustup target add ${{ matrix.triple }}
|
||||
|
||||
# `--features bundled-assets` bakes static-dist/ into the binary
|
||||
# via rust-embed. `--bin oxicloud` — the single binary the merge
|
||||
# (Deliverable 1b) consolidated everything into.
|
||||
- name: Build binary
|
||||
env:
|
||||
# Per-triple CPU baseline — release binaries target the widest
|
||||
# realistic install base for their arch. See
|
||||
# docs/plan/bundled-binary.md § 3.
|
||||
RUSTFLAGS: ${{ matrix.rustflags }}
|
||||
# Git metadata injection — build.rs reads these env vars to
|
||||
# stamp GIT_HASH / GIT_BRANCH into the binary. Without them
|
||||
# `oxicloud --version` reports "unknown".
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
GITHUB_REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
cargo build --release --features bundled-assets --bin oxicloud --target ${{ matrix.triple }}
|
||||
|
||||
# Assemble the tarball layout documented in
|
||||
# docs/plan/bundled-binary.md § 4: oxicloud + example.env +
|
||||
# LICENSE + README-install.md, rooted under a per-version-per-
|
||||
# triple directory so `tar xzf` lands cleanly.
|
||||
- name: Package tarball
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Version = tag stripped of leading `v` (workflow_dispatch)
|
||||
# or ref_name stripped (push tag). Falls back to ref_name
|
||||
# verbatim if neither strip matches.
|
||||
RAW_REF="${{ github.event.inputs.version || github.ref_name }}"
|
||||
VERSION="${RAW_REF#v}"
|
||||
DIST="oxicloud-${VERSION}-${{ matrix.triple }}"
|
||||
mkdir -p "dist/${DIST}"
|
||||
cp "target/${{ matrix.triple }}/release/oxicloud" "dist/${DIST}/oxicloud"
|
||||
cp example.env "dist/${DIST}/example.env"
|
||||
cp LICENSE "dist/${DIST}/LICENSE"
|
||||
# README-install.md may not exist yet in early releases —
|
||||
# ship a stub that points at the docs site so users have
|
||||
# something in the tarball. Deliverable 6 replaces it with
|
||||
# a proper install guide.
|
||||
if [ -f docs/install/binary.md ]; then
|
||||
cp docs/install/binary.md "dist/${DIST}/README-install.md"
|
||||
else
|
||||
cat > "dist/${DIST}/README-install.md" <<'MD'
|
||||
# OxiCloud — Installation
|
||||
|
||||
Full documentation: https://github.com/AtalayaLabs/OxiCloud/tree/main/docs
|
||||
|
||||
Quickstart:
|
||||
1. Set DATABASE_URL to a PostgreSQL 13+ instance
|
||||
(with pg_trgm + ltree extensions).
|
||||
2. Copy example.env → .env, edit as needed.
|
||||
3. Run ./oxicloud.
|
||||
|
||||
Optional: install ffmpeg for server-side video thumbnails
|
||||
(or set OXICLOUD_ENABLE_VIDEO_THUMBNAILS=false to disable).
|
||||
MD
|
||||
fi
|
||||
# Deterministic tar (owner/group/mtime pinned) so re-running
|
||||
# the build produces byte-identical archives — helps with
|
||||
# reproducible-build audits and cheap hash verification.
|
||||
tar --owner=0 --group=0 -czf "dist/${DIST}.tar.gz" -C dist "${DIST}"
|
||||
ls -la "dist/${DIST}.tar.gz"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tarball-${{ matrix.triple }}
|
||||
path: dist/*.tar.gz
|
||||
retention-days: 1
|
||||
|
||||
# ── Stage 3: Attach all tarballs + SHA256SUMS to the Release ────────
|
||||
#
|
||||
# `dry_run: true` (workflow_dispatch only) skips this job — the
|
||||
# binary tarballs stay as workflow artifacts (accessible from the
|
||||
# run page for 1 day) but nothing lands on any Release.
|
||||
release:
|
||||
name: Attach tarballs to GitHub Release
|
||||
needs: binary-build
|
||||
if: |
|
||||
needs.binary-build.result == 'success' &&
|
||||
(github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: tarball-*
|
||||
path: dist/
|
||||
merge-multiple: true
|
||||
|
||||
- name: Compute SHA256SUMS
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd dist
|
||||
# Sort output for stable ordering across re-runs — the file
|
||||
# doubles as a manifest an operator can `diff` between two
|
||||
# release runs to prove they're identical.
|
||||
sha256sum *.tar.gz | sort > SHA256SUMS
|
||||
cat SHA256SUMS
|
||||
|
||||
# softprops/action-gh-release@v2 semantics:
|
||||
# - If the Release for this tag EXISTS (created by release.yml
|
||||
# which runs in parallel on the same tag push), attaches the
|
||||
# files to it.
|
||||
# - If it doesn't yet exist (race — release.yml still running),
|
||||
# creates a bare Release which release.yml then fills in with
|
||||
# notes when it finishes.
|
||||
# Benign either way; see docs/plan/bundled-binary.md § 5
|
||||
# "Parallel-fire behaviour on tag push".
|
||||
- name: Attach to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
dist/*.tar.gz
|
||||
dist/SHA256SUMS
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+32
-5
@@ -4,6 +4,24 @@ version = "0.8.7"
|
||||
edition = "2024"
|
||||
default-run = "oxicloud"
|
||||
|
||||
# `cargo binstall oxicloud` — fetches the prebuilt release tarball for the
|
||||
# host triple from GitHub Releases (attached by
|
||||
# `.github/workflows/release-binaries.yml`) instead of compiling from
|
||||
# source. Templates match the tarball naming
|
||||
# `oxicloud-<version>-<triple>.tar.gz` produced by that workflow.
|
||||
#
|
||||
# `pkg-fmt = "tgz"` — otherwise binstall guesses from the URL extension;
|
||||
# being explicit lets `cargo binstall oxicloud` succeed on Windows too
|
||||
# (where the URL string parsing differs).
|
||||
#
|
||||
# Once the first tagged release lands on GitHub, this becomes a one-line
|
||||
# install for anyone with the Rust toolchain who prefers not to build
|
||||
# from source and doesn't want Docker either.
|
||||
[package.metadata.binstall]
|
||||
pkg-url = "{ repo }/releases/download/v{ version }/oxicloud-{ version }-{ target }.tar.gz"
|
||||
pkg-fmt = "tgz"
|
||||
bin-dir = "oxicloud-{ version }-{ target }/{ bin }{ binary-ext }"
|
||||
|
||||
|
||||
[dependencies]
|
||||
mimalloc = { version = "0.1.52", default-features = false }
|
||||
@@ -979,11 +997,20 @@ opt-level = 1
|
||||
debug = "line-tables-only"
|
||||
split-debuginfo = "unpacked"
|
||||
# Incremental compilation caches per-function IR fingerprints so a
|
||||
# small edit only recompiles what changed. On a single-crate rebuild
|
||||
# (oxicloud is one crate) the savings are modest — worth < the ~7 GB
|
||||
# incremental/ cache costs on disk. Rust-analyzer uses `cargo check`,
|
||||
# which has its own cache, so LSP responsiveness is unaffected.
|
||||
incremental = false
|
||||
# small edit only recompiles what changed. The `target/incremental/`
|
||||
# cache costs ~7 GB per profile, but at the current codebase size a
|
||||
# full rebuild is ~10 minutes and an incremental single-file edit is
|
||||
# seconds — the disk is worth it and then some. Rust-analyzer's own
|
||||
# `cargo check` cache is separate; LSP responsiveness is unaffected
|
||||
# either way.
|
||||
#
|
||||
# History: this was `= false` early on when the crate was small and
|
||||
# incremental's savings didn't cover the disk cost. Re-enabled
|
||||
# 2026-08-29 as the full-rebuild time crossed the "feels annoying"
|
||||
# threshold on typical dev-loop edits. If disk pressure ever spikes,
|
||||
# `cargo clean -p oxicloud --profile dev` clears the incremental cache
|
||||
# without wiping compiled deps.
|
||||
incremental = true
|
||||
|
||||
[profile.bench]
|
||||
lto = "fat"
|
||||
|
||||
@@ -68,6 +68,16 @@ docker compose up -d
|
||||
|
||||
Open `http://localhost:8086`.
|
||||
|
||||
### Prebuilt binary
|
||||
|
||||
Binary releases (Linux musl amd64/arm64, macOS Intel/Apple Silicon)
|
||||
are attached to every tagged release on GitHub — the whole SPA + all
|
||||
operator subcommands + migrations bake into a single self-contained
|
||||
executable. See [`docs/install/binary.md`](docs/install/binary.md) for
|
||||
the download / verify / systemd walkthrough.
|
||||
|
||||
`cargo binstall oxicloud` works too once a release is out.
|
||||
|
||||
### Run from source
|
||||
|
||||
Requires Rust 1.93+ and PostgreSQL.
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
# Installing OxiCloud from a Binary Release
|
||||
|
||||
OxiCloud ships prebuilt binaries for common Linux and macOS platforms
|
||||
attached to every tagged release on GitHub. This page covers downloading,
|
||||
verifying, and running one.
|
||||
|
||||
If you'd rather run OxiCloud as a container, see the Docker image at
|
||||
`ghcr.io/atalayalabs/oxicloud`. If you're a Rust developer who just
|
||||
wants the binary without hand-fetching a tarball, `cargo binstall
|
||||
oxicloud` picks the right archive for your host automatically.
|
||||
|
||||
## Which tarball do I want?
|
||||
|
||||
Every release attaches four tarballs plus a `SHA256SUMS` manifest. Pick
|
||||
by your host's architecture and OS:
|
||||
|
||||
| Host | Tarball |
|
||||
|---|---|
|
||||
| Linux x86-64 (Intel / AMD servers, most VPS, WSL) | `oxicloud-<version>-x86_64-unknown-linux-musl.tar.gz` |
|
||||
| Linux ARM64 (Raspberry Pi 4/5, Ampere, Graviton, ARM servers) | `oxicloud-<version>-aarch64-unknown-linux-musl.tar.gz` |
|
||||
| macOS Apple Silicon (M-series) | `oxicloud-<version>-aarch64-apple-darwin.tar.gz` |
|
||||
| macOS Intel | `oxicloud-<version>-x86_64-apple-darwin.tar.gz` |
|
||||
|
||||
The Linux tarballs link against musl, so they run on ANY glibc version
|
||||
— Alpine, Debian, Ubuntu, Fedora, Arch, Rocky, and every version in
|
||||
between. You never need to worry about `GLIBC_x.yy not found`.
|
||||
|
||||
Windows and 32-bit ARM are not currently shipped.
|
||||
|
||||
## Hardware notes
|
||||
|
||||
| Model | Notes |
|
||||
|---|---|
|
||||
| Pi 5 (4 GB / 8 GB) | Good experience |
|
||||
| Pi 4 (4 GB / 8 GB) | Solid |
|
||||
| Pi 4 (2 GB) | Works with face indexing disabled; expect swap under load |
|
||||
| Pi 3 (any variant) | Marginal — only for a very light single-user personal cloud |
|
||||
| Pi 2 / Pi Zero / Pi 1 | Not supported (1 GB RAM is below the practical floor) |
|
||||
| Any ARM64 server | Good — the aarch64 tarball is what you want |
|
||||
| Any x86-64 server from 2010 or newer | Good — Nehalem / Bulldozer + newer, per the release CPU baseline |
|
||||
|
||||
## Verifying the download
|
||||
|
||||
Every release ships a `SHA256SUMS` manifest listing every tarball with
|
||||
its hash. Verify your download before extracting:
|
||||
|
||||
```
|
||||
sha256sum -c SHA256SUMS
|
||||
```
|
||||
|
||||
Only files present in the current directory are checked, so this
|
||||
succeeds when just the tarball you downloaded matches its entry.
|
||||
|
||||
## Extracting
|
||||
|
||||
The archive lands as a per-version-per-triple directory next to it:
|
||||
|
||||
```
|
||||
tar xzf oxicloud-<version>-<triple>.tar.gz
|
||||
cd oxicloud-<version>-<triple>/
|
||||
ls
|
||||
# oxicloud example.env LICENSE README-install.md
|
||||
```
|
||||
|
||||
The four files:
|
||||
|
||||
- `oxicloud` — the single self-contained binary. The server, all
|
||||
operator subcommands (`oxicloud opaque setup`, `oxicloud migrate
|
||||
nfc-filenames`, `oxicloud storage select`), and the SvelteKit web
|
||||
frontend are all baked in.
|
||||
- `example.env` — every OxiCloud environment variable documented with
|
||||
defaults. Copy to `.env` and edit as needed.
|
||||
- `LICENSE` — the project license.
|
||||
- `README-install.md` — a shorter version of this page for offline
|
||||
reference.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Only one moving part is required: a PostgreSQL 13+ instance with the
|
||||
`pg_trgm` and `ltree` extensions available. Anything else you might
|
||||
need is either baked into the binary or optional.
|
||||
|
||||
### Required
|
||||
|
||||
- **PostgreSQL 13+** with `pg_trgm` and `ltree` extensions. Any distro
|
||||
package works (Debian/Ubuntu's `postgresql`, Alpine's `postgresql`,
|
||||
Homebrew's `postgresql@17`, etc.). Cloud databases like Neon,
|
||||
Supabase, and RDS also work provided the two extensions are enabled.
|
||||
|
||||
### System libraries (usually pre-installed)
|
||||
|
||||
- **`ca-certificates`** — for outbound HTTPS (OIDC discovery, S3, magic
|
||||
links). Pre-installed on essentially every distribution.
|
||||
- **`tzdata`** — timezone database. Pre-installed on nearly every
|
||||
distribution; alpine minimal images sometimes need it added.
|
||||
|
||||
### Optional
|
||||
|
||||
- **`ffmpeg`** — only needed if you want the server to extract a
|
||||
thumbnail frame from uploaded videos. When ffmpeg is missing the
|
||||
server logs a warning at boot and videos get a placeholder icon —
|
||||
everything else keeps working. If your client uploads video
|
||||
previews itself (some desktop and mobile clients do), or if you
|
||||
simply don't want thumbnails, set
|
||||
`OXICLOUD_ENABLE_VIDEO_THUMBNAILS=false` in your `.env` to silence
|
||||
the warning.
|
||||
|
||||
Distro install commands for the optional prerequisite:
|
||||
|
||||
| Distro | Command |
|
||||
|---|---|
|
||||
| Alpine | `apk add ffmpeg` |
|
||||
| Debian / Ubuntu | `apt install ffmpeg` |
|
||||
| Fedora / RHEL | `dnf install ffmpeg` (RPM Fusion for the full codec set) |
|
||||
| Arch | `pacman -S ffmpeg` |
|
||||
| macOS | `brew install ffmpeg` |
|
||||
| Any Linux (portable) | grab a static build from https://github.com/BtbN/FFmpeg-Builds/releases and point `OXICLOUD_FFMPEG_PATH` at it |
|
||||
|
||||
## First run
|
||||
|
||||
The absolute minimum to boot the server is `DATABASE_URL`:
|
||||
|
||||
```
|
||||
DATABASE_URL="postgres://oxicloud:secret@localhost:5432/oxicloud" \
|
||||
./oxicloud
|
||||
```
|
||||
|
||||
The binary applies its embedded database migrations on startup, then
|
||||
listens on `127.0.0.1:8086` by default. Open your browser at
|
||||
`http://localhost:8086/` and follow the setup flow to create the first
|
||||
admin account.
|
||||
|
||||
For anything more than a smoke test, copy `example.env` to `.env`,
|
||||
edit it, and run `./oxicloud --config .env` — that pins the config
|
||||
source and makes stray shell environment variables not silently leak
|
||||
in.
|
||||
|
||||
## Running as a systemd service (Linux)
|
||||
|
||||
Move the binary to a system location and create a systemd unit. The
|
||||
example below runs as a dedicated `oxicloud` user, loads config from
|
||||
`/etc/oxicloud/oxicloud.env`, and stores data under `/var/lib/oxicloud`.
|
||||
|
||||
```
|
||||
sudo useradd --system --home /var/lib/oxicloud --create-home --shell /usr/sbin/nologin oxicloud
|
||||
sudo install -m 0755 oxicloud /usr/local/bin/oxicloud
|
||||
sudo mkdir -p /etc/oxicloud
|
||||
sudo cp example.env /etc/oxicloud/oxicloud.env
|
||||
sudo chown -R oxicloud:oxicloud /etc/oxicloud
|
||||
sudo chmod 0640 /etc/oxicloud/oxicloud.env
|
||||
```
|
||||
|
||||
Create `/etc/systemd/system/oxicloud.service`:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=OxiCloud self-hosted cloud storage
|
||||
After=network-online.target postgresql.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=oxicloud
|
||||
Group=oxicloud
|
||||
WorkingDirectory=/var/lib/oxicloud
|
||||
ExecStart=/usr/local/bin/oxicloud --config /etc/oxicloud/oxicloud.env
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Sandbox — plenty of room to tighten further per your policy
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/var/lib/oxicloud
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Enable and start:
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now oxicloud
|
||||
sudo systemctl status oxicloud
|
||||
journalctl -u oxicloud -f
|
||||
```
|
||||
|
||||
Terminate the reverse-proxy (nginx, Caddy, HAProxy, Traefik) in front
|
||||
of it for TLS and public exposure — OxiCloud itself binds plaintext
|
||||
HTTP on `127.0.0.1` by default.
|
||||
|
||||
## Upgrading
|
||||
|
||||
Replace the binary and restart the service:
|
||||
|
||||
```
|
||||
# Download and verify the new tarball
|
||||
sha256sum -c SHA256SUMS
|
||||
tar xzf oxicloud-<new-version>-<triple>.tar.gz
|
||||
cd oxicloud-<new-version>-<triple>/
|
||||
|
||||
sudo systemctl stop oxicloud
|
||||
sudo install -m 0755 oxicloud /usr/local/bin/oxicloud
|
||||
sudo systemctl start oxicloud
|
||||
```
|
||||
|
||||
Database migrations apply automatically on startup. Rollbacks are not
|
||||
supported by sqlx's migration model; if you need to roll back, stop
|
||||
the server, roll back your Postgres data directory to a snapshot, and
|
||||
install the previous binary.
|
||||
|
||||
## Installing via `cargo binstall`
|
||||
|
||||
If you already have the Rust toolchain and just want the binary
|
||||
without hand-picking a tarball:
|
||||
|
||||
```
|
||||
cargo binstall oxicloud
|
||||
```
|
||||
|
||||
`cargo-binstall` reads the URL template baked into the release
|
||||
metadata, downloads the tarball for your host triple, verifies its
|
||||
signature (when present), and installs `oxicloud` into
|
||||
`~/.cargo/bin`. This resolves to the same tarball you'd download by
|
||||
hand.
|
||||
|
||||
## Where to go from here
|
||||
|
||||
- Environment reference — see [`docs/config/env.md`](../config/env.md)
|
||||
for every `OXICLOUD_*` variable and its default.
|
||||
- Authentication setup (OPAQUE, OIDC, magic links) — see
|
||||
[`docs/config/authentication.md`](../config/authentication.md).
|
||||
- Storage backends (local disk, S3, Azure Blob, encryption) — see
|
||||
[`docs/config/storage.md`](../config/storage.md) if present, or the
|
||||
entries under `OXICLOUD_STORAGE_*` in the environment reference.
|
||||
- File a bug or a feature request — GitHub issues at
|
||||
https://github.com/AtalayaLabs/OxiCloud.
|
||||
Reference in New Issue
Block a user