docs: migrate legacy docs to official site

This commit is contained in:
Diocrafts
2026-04-22 07:50:41 +02:00
parent e10a908f07
commit c0cb86c273
63 changed files with 1646 additions and 10136 deletions
+12 -59
View File
@@ -28,65 +28,6 @@ export default defineConfig({
label: "English",
lang: "en",
},
es: {
label: "Español",
lang: "es",
link: "/es/",
title: "OxiCloud",
description: "Almacenamiento en la nube autoalojado, calendario y contactos — increíblemente rápido",
themeConfig: {
nav: [
{ text: "Inicio", link: "/es/" },
{ text: "Guía", link: "/es/guide/" },
{ text: "Configuración", link: "/es/config/" },
{ text: "FAQ", link: "/es/faq" },
],
editLink: {
pattern: "https://github.com/DioCrafts/OxiCloud/tree/main/docs/:path",
text: "Editar esta página en GitHub",
},
sidebar: {
"/es/": [
{
text: "Introducción",
items: [
{ text: "¿Qué es OxiCloud?", link: "/es/guide/" },
{ text: "Inicio Rápido", link: "/es/guide/installation" },
],
},
{
text: "Configuración",
items: [
{ text: "Despliegue & Docker", link: "/es/config/deployment" },
{ text: "Variables de Entorno", link: "/es/config/env" },
{ text: "OIDC / SSO", link: "/es/config/oidc" },
{ text: "WOPI (Office)", link: "/es/config/wopi" },
],
},
{
text: "Características",
items: [
{ text: "WebDAV", link: "/es/guide/webdav" },
{ text: "CalDAV & CardDAV", link: "/es/guide/caldav-carddav" },
{ text: "Subida Chunked", link: "/es/guide/chunked-uploads" },
{ text: "Deduplicación", link: "/es/guide/deduplication" },
{ text: "Búsqueda", link: "/es/guide/search" },
{ text: "Papelera", link: "/es/guide/trash" },
],
},
{
text: "Arquitectura",
items: [
{ text: "Arquitectura Interna", link: "/es/architecture/" },
{ text: "Caché", link: "/es/architecture/caching" },
{ text: "Cuotas de Almacenamiento", link: "/es/architecture/storage-quotas" },
],
},
{ text: "FAQ", link: "/es/faq" },
],
},
},
},
},
head: [
@@ -126,7 +67,10 @@ export default defineConfig({
items: [
{ text: "Deployment & Docker", link: "/config/deployment" },
{ text: "Environment Variables", link: "/config/env" },
{ text: "Authentication", link: "/config/authentication" },
{ text: "OIDC / SSO", link: "/config/oidc" },
{ text: "OIDC Config Examples", link: "/config/oidc-config-examples" },
{ text: "Admin Settings", link: "/config/admin-settings" },
{ text: "WOPI (Office Editing)", link: "/config/wopi" },
],
},
@@ -135,10 +79,16 @@ export default defineConfig({
items: [
{ text: "WebDAV", link: "/guide/webdav" },
{ text: "CalDAV & CardDAV", link: "/guide/caldav-carddav" },
{ text: "DAV Client Setup", link: "/guide/dav-client-setup" },
{ text: "Chunked Uploads", link: "/guide/chunked-uploads" },
{ text: "Batch Operations", link: "/guide/batch-operations" },
{ text: "Deduplication", link: "/guide/deduplication" },
{ text: "Favorites & Recent", link: "/guide/favorites-and-recent" },
{ text: "Search", link: "/guide/search" },
{ text: "Thumbnails & Transcoding", link: "/guide/thumbnails-and-transcoding" },
{ text: "Trash & Recycle Bin", link: "/guide/trash" },
{ text: "ZIP & Compression", link: "/guide/zip-and-compression" },
{ text: "Internationalization", link: "/guide/i18n" },
],
},
{
@@ -146,6 +96,9 @@ export default defineConfig({
items: [
{ text: "Internal Architecture", link: "/architecture/" },
{ text: "Caching", link: "/architecture/caching" },
{ text: "Storage Safety", link: "/architecture/file-system-safety" },
{ text: "Database Transactions", link: "/architecture/database-transactions" },
{ text: "Share Integration", link: "/architecture/share-integration" },
{ text: "Storage Quotas", link: "/architecture/storage-quotas" },
],
},
@@ -0,0 +1,74 @@
# Database Transactions
OxiCloud uses explicit PostgreSQL transactions for multi-step operations that must either commit together or fail together.
## ACID Guarantees
- Atomicity: all work succeeds or the entire transaction rolls back
- Consistency: constraints and invariants remain valid before and after commit
- Isolation: concurrent work behaves predictably
- Durability: committed writes survive process and system failures
## Transaction Helper
The PostgreSQL repositories use a helper like `with_transaction` to standardize the transaction lifecycle:
```rust
pub async fn with_transaction<F, T, E>(
pool: &Arc<PgPool>,
operation_name: &str,
operation: F,
) -> Result<T, E>
where
F: for<'c> FnOnce(&'c mut Transaction<'_, Postgres>) -> futures::future::BoxFuture<'c, Result<T, E>>,
E: From<SqlxError> + std::fmt::Display,
{ /* ... */ }
```
That wrapper handles begin, commit, rollback, and lifecycle logging so repository code can focus on the actual domain operation.
## Common Use Cases
### User management
Transactions keep related user changes together, such as creating a user and attaching the dependent records required for a valid account.
### Session management
Session creation and session revocation can update multiple tables in a single logical step, which avoids stale or mismatched security state.
### File and folder workflows
Moves, renames, trash operations, and other multi-step metadata changes rely on transactions so the tree stays consistent.
## Isolation Levels
OxiCloud can use different isolation levels depending on the operation.
| Level | Use case |
| --- | --- |
| `Read Committed` | Default application work |
| `Repeatable Read` | Stable reads during a longer unit of work |
| `Serializable` | Highest safety for conflict-prone critical operations |
Higher isolation can introduce retries or contention, so it should be reserved for the few flows that need it.
## Best Practices
- Keep transactions short
- Avoid heavy I/O inside a transaction when possible
- Group only operations that must commit together
- Choose the lowest isolation level that preserves correctness
- Log and surface rollback causes clearly
## Why It Matters
- Prevents partial metadata updates
- Keeps concurrent user activity predictable
- Reduces race conditions in critical operations
- Makes failures recoverable and easier to reason about
## Related Pages
- [Storage Safety](/architecture/file-system-safety)
- [Internal Architecture](/architecture/)
+77
View File
@@ -0,0 +1,77 @@
# Storage Safety
OxiCloud protects file integrity with two layers working together:
- PostgreSQL transactions for metadata
- Atomic blob writes for content
The result is a simple guarantee: operations either complete fully or fail cleanly enough to recover without corrupting user data.
## Storage Model
- Metadata such as names, folders, MIME types, quotas, and trash state lives in PostgreSQL
- File content is stored as content-addressed blobs under the storage backend
- Deduplication metadata is tracked separately so multiple files can reference the same content safely
## Metadata Safety
PostgreSQL protects metadata with ACID transactions.
- Single-row writes are atomic by default
- Multi-step operations use explicit transactions
- Foreign keys prevent orphaned references
- Unique constraints prevent illegal duplicates in the same scope
- Trash uses soft-delete semantics until permanent deletion is requested
## Content Safety
Blob writes rely on an atomic write pattern:
1. Write new content to a temporary file
2. `fsync` the file to push data and metadata to durable storage
3. Rename the temp file into its final content-addressed path
4. Sync parent directory metadata when needed
This prevents partially written blobs from appearing as valid stored content.
## Deduplication Notes
OxiCloud's deduplication pipeline uses BLAKE3 hashing and chunk manifest tracking. The storage layer can therefore reuse identical content while still keeping metadata changes transactional.
If content is stored successfully but the later metadata transaction fails, the content may remain as an unreferenced blob. That is a space leak, not a consistency leak, and can be cleaned up later.
## Upload Flow
```text
1. Receive content and spool it safely to storage
2. Finalize the content-addressed blob write
3. Begin metadata transaction
4. Insert or update file metadata in PostgreSQL
5. Commit
```
If step 1 or 2 fails, no metadata is committed. If step 4 or 5 fails, metadata rolls back and the storage layer can clean up unreferenced content later.
## Delete Flow
```text
1. Begin metadata transaction
2. Remove or soft-delete the metadata row
3. Commit
4. Decrement blob references and remove physical content when the refcount reaches zero
```
If the metadata transaction fails, the physical file is not considered deleted. If the refcount cleanup fails, the system may keep extra content on disk, but user-visible metadata remains correct.
## Why This Matters
- Crash resilience during uploads and deletes
- Safe recovery after power loss or host restarts
- Clean separation between metadata correctness and background storage cleanup
- Predictable behavior for trash, deduplication, and shared storage backends
## Related Pages
- [Internal Architecture](/architecture/)
- [Database Transactions](/architecture/database-transactions)
- [Storage Quotas](/architecture/storage-quotas)
+11
View File
@@ -37,6 +37,17 @@ All cross-layer dependencies point **inward** via trait-based ports. The DI cont
8. **ZIP service** (last, depends on file & folder services)
9. **Assemble `AppState`**
## AppState Shape
The assembled `AppState` groups the application into a few stable buckets:
- `core` for cross-cutting runtime services such as path resolution, caching, chunked uploads, deduplication, compression, thumbnails, and ZIP handling
- `repositories` for PostgreSQL-backed folder, file, trash, and i18n persistence
- `applications` for the use-case layer exposed to handlers
- optional auth, admin, trash, share, favorites, recent, storage usage, calendar, and contact services when those features are enabled
This lets handlers depend on stable interfaces while the concrete implementation details stay inside the DI container.
## Project Structure
```
+74
View File
@@ -0,0 +1,74 @@
# Share Integration
OxiCloud supports public file and folder sharing through signed share links. A share can be public, password-protected, time-limited, or scoped by permissions.
## What a Share Contains
A share record tracks:
- The shared item ID and whether it is a file or folder
- A public token used in the share URL
- Optional password protection
- Optional expiration timestamp
- Permissions for read, write, and reshare
- The creator and access count
## Public and Private Routes
### Authenticated management routes
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/shares/` | Create a new share |
| `GET` | `/api/shares/` | List current user's shares |
| `GET` | `/api/shares/{id}` | Fetch one share |
| `PUT` | `/api/shares/{id}` | Update permissions, password, or expiration |
| `DELETE` | `/api/shares/{id}` | Delete a share |
### Public access routes
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/s/{token}` | Access a shared item |
| `POST` | `/api/s/{token}/verify` | Verify a password-protected share |
## Service Responsibilities
The share service is responsible for:
- Validating that the underlying file or folder exists
- Generating unique share IDs and public tokens
- Enforcing password checks and expiration rules
- Mapping domain permissions into API DTOs
- Recording access counts
Share metadata is persisted separately from the file content itself. The shared resource still uses the normal storage model for files and folders.
## Example Workflow
### Creating a share link
1. A user selects a file or folder in the UI
2. The frontend submits a request to `/api/shares/`
3. OxiCloud validates the target and requested permissions
4. The backend generates a token and public URL
5. The share metadata is saved and returned to the caller
### Opening a share link
1. A guest opens `/api/s/{token}`
2. OxiCloud verifies the token and checks expiration
3. If the share is password protected, the client verifies the password first
4. Access is counted and the shared resource is returned according to the granted permissions
## Security Notes
- Passwords are stored as hashes, never as plaintext
- Expired shares are rejected before content access
- Permissions are checked per action, not only when the share is created
## Related Pages
- [OIDC / SSO](/config/oidc)
- [Admin Settings](/config/admin-settings)
- [Internal Architecture](/architecture/)
+12
View File
@@ -15,6 +15,10 @@ OXICLOUD_ENABLE_USER_STORAGE_QUOTAS=true
3. If the upload would exceed the quota, it's rejected with a `413 Payload Too Large` error
4. Admins can view and set quotas via the admin panel or API
## Usage Calculation
The storage usage service recalculates logical usage from the user's home folder tree and sums file sizes recursively. Directory entries are skipped and the final value is written back to `auth.users.storage_used`.
## API
| Method | Endpoint | Description |
@@ -26,6 +30,14 @@ OXICLOUD_ENABLE_USER_STORAGE_QUOTAS=true
The admin panel (`/admin.html`) shows each user's current usage vs. quota with a visual progress bar.
The dashboard also exposes aggregate quota stats such as:
- total quota bytes
- total used bytes
- overall storage usage percent
- users above 80% usage
- users over quota
## Deduplication Interaction
Storage usage is calculated based on **logical file size** (what the user uploaded), not physical blob size. This means:
+86
View File
@@ -0,0 +1,86 @@
# Admin Settings
OxiCloud exposes an admin API for runtime configuration, dashboard stats, and user administration. All routes live under `/api/admin` and require an authenticated admin JWT.
## Settings Endpoints
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/admin/settings/oidc` | Read current OIDC settings |
| `PUT` | `/api/admin/settings/oidc` | Save OIDC settings |
| `POST` | `/api/admin/settings/oidc/test` | Test provider connectivity |
| `GET` | `/api/admin/settings/general` | Read general server settings |
The OIDC runtime UI complements the base configuration described in [OIDC / SSO](/config/oidc) and the provider samples in [OIDC Config Examples](/config/oidc-config-examples).
## Dashboard Endpoint
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/admin/dashboard` | Read server statistics and feature state |
Typical dashboard fields include:
- server version
- whether auth and OIDC are enabled
- whether quotas are enabled
- total, active, and admin user counts
- quota usage totals and percentage
## User Management Endpoints
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/admin/users` | List users |
| `GET` | `/api/admin/users/{id}` | Get one user |
| `DELETE` | `/api/admin/users/{id}` | Delete a user |
| `PUT` | `/api/admin/users/{id}/role` | Change role |
| `PUT` | `/api/admin/users/{id}/active` | Activate or deactivate a user |
| `PUT` | `/api/admin/users/{id}/quota` | Update a storage quota |
### Built-in safety guards
- Admins cannot delete their own account
- Admins cannot change their own role
- Admins cannot deactivate themselves
## OIDC Settings Priority
When the same setting exists in multiple places, OxiCloud resolves it in this order:
1. Environment variables such as `OXICLOUD_OIDC_*`
2. Values stored in the admin settings table
3. Built-in defaults
If a value is overridden by environment variables, the admin API can expose that in the response so operators know why a saved value is not taking effect.
## Test Connection Example
```json
{
"issuer_url": "https://keycloak.example.com/realms/main"
}
```
Successful responses include discovered endpoints such as the authorization endpoint, token endpoint, and userinfo endpoint.
## Data Storage
Runtime settings are stored in `auth.admin_settings`.
```sql
CREATE TABLE IF NOT EXISTS auth.admin_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
category TEXT NOT NULL,
is_secret BOOLEAN DEFAULT FALSE,
updated_by VARCHAR(36),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
```
## Related Pages
- [OIDC / SSO](/config/oidc)
- [OIDC Config Examples](/config/oidc-config-examples)
- [Environment Variables](/config/env)
+72
View File
@@ -0,0 +1,72 @@
# Authentication
OxiCloud ships with JWT-based authentication and Argon2id password hashing for local accounts. It also exposes status and OIDC-related auth endpoints under the same `/api/auth` namespace.
## Core Endpoints
| Method | Endpoint | Description |
| --- | --- | --- |
| `POST` | `/api/auth/register` | Create a local user account |
| `POST` | `/api/auth/login` | Exchange username and password for access and refresh tokens |
| `POST` | `/api/auth/refresh` | Refresh the session tokens |
| `GET` | `/api/auth/me` | Return the current authenticated user |
| `PUT` | `/api/auth/change-password` | Change the current user's password |
| `POST` | `/api/auth/logout` | Invalidate the current session |
| `GET` | `/api/auth/status` | Return auth system state, including OIDC availability |
## OIDC Endpoints Under Auth
| Method | Endpoint | Description |
| --- | --- | --- |
| `GET` | `/api/auth/oidc/providers` | List configured OIDC provider info |
| `GET` | `/api/auth/oidc/authorize` | Build the authorization redirect URL |
| `GET` | `/api/auth/oidc/callback` | Handle provider redirect callback |
| `POST` | `/api/auth/oidc/exchange` | Exchange the auth code for OxiCloud session tokens |
## Example Flows
### Register
```json
{
"username": "testuser",
"email": "test@example.com",
"password": "SecurePassword123"
}
```
### Login
```json
{
"username": "testuser",
"password": "SecurePassword123"
}
```
Typical successful login response:
```json
{
"accessToken": "...",
"refreshToken": "...",
"expiresIn": 3600
}
```
### Current User
`GET /api/auth/me` returns the authenticated user's identity, role, and storage information.
## Security Model
- local passwords are hashed with Argon2id
- access control is role-based (`admin` and `user`)
- refresh tokens support session renewal without forcing frequent re-login
- OIDC can coexist with local auth or disable password login entirely
## Related Pages
- [OIDC / SSO](/config/oidc)
- [Admin Settings](/config/admin-settings)
- [Environment Variables](/config/env)
+21 -5
View File
@@ -16,14 +16,18 @@ The final image runs as non-root user `oxicloud` (UID/GID 1001). Exposed port: *
```yaml
services:
postgres:
image: postgres:17.4-alpine
image: postgres:18.2-alpine3.23
restart: always
environment:
POSTGRES_DB: oxicloud
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres # change in production!
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
networks:
- oxicloud
volumes:
- pg_data:/var/lib/postgresql/data
- ./db/schema.sql:/docker-entrypoint-initdb.d/schema.sql
- pg_data:/var/lib/postgresql/
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
@@ -31,9 +35,15 @@ services:
retries: 5
oxicloud:
image: ghcr.io/diocrafts/oxicloud:latest
image: diocrafts/oxicloud:latest
restart: always
build:
context: .
dockerfile: Dockerfile
ports:
- "8086:8086"
networks:
- oxicloud
env_file:
- .env
volumes:
@@ -42,11 +52,17 @@ services:
postgres:
condition: service_healthy
networks:
oxicloud:
driver: bridge
volumes:
pg_data:
storage_data:
```
This example mirrors the repository's current `docker-compose.yml`. If you deploy from a registry-only setup, you can keep the `image:` line and remove the `build:` stanza.
## Kubernetes (Helm)
### Prerequisites
+18 -1
View File
@@ -1,6 +1,6 @@
# Environment Variables
All variables use the `OXICLOUD_` prefix.
Most runtime variables use the `OXICLOUD_` prefix. A few build-time or allocator variables do not.
## Server
@@ -19,6 +19,14 @@ All variables use the `OXICLOUD_` prefix.
| `OXICLOUD_DB_CONNECTION_STRING` | `postgres://postgres:postgres@localhost:5432/oxicloud` | PostgreSQL connection string |
| `OXICLOUD_DB_MAX_CONNECTIONS` | `20` | Max pool connections |
| `OXICLOUD_DB_MIN_CONNECTIONS` | `5` | Min pool connections |
| `OXICLOUD_DB_MAINTENANCE_MAX_CONNECTIONS` | `5` | Max connections in the isolated maintenance pool |
| `OXICLOUD_DB_MAINTENANCE_MIN_CONNECTIONS` | `1` | Min connections in the isolated maintenance pool |
## Build-Time SQLx
| Variable | Default | Description |
|---|---|---|
| `DATABASE_URL` | — | Build-time database URL for SQLx compile-time checks |
## Authentication
@@ -68,6 +76,15 @@ See the [WOPI configuration guide](/config/wopi) for details.
| `OXICLOUD_WOPI_TOKEN_TTL_SECS` | `86400` | Token lifetime |
| `OXICLOUD_WOPI_LOCK_TTL_SECS` | `1800` | Lock expiration |
## Allocator Tuning
These variables are read directly by **mimalloc**, not by OxiCloud's config parser.
| Variable | Default | Description |
|---|---|---|
| `MIMALLOC_PURGE_DELAY` | `0` | Delay in ms before freed memory is returned to the OS |
| `MIMALLOC_ALLOW_LARGE_OS_PAGES` | `0` | Enable or disable large OS pages for allocations |
## Internal Defaults (not configurable via env)
| Parameter | Default |
+1
View File
@@ -6,6 +6,7 @@ OxiCloud is configured entirely via **environment variables** (no config files n
- [Deployment & Docker](/config/deployment) — Docker Compose, Kubernetes Helm chart, image details
- [Environment Variables](/config/env) — complete reference of all `OXICLOUD_*` variables
- [Authentication](/config/authentication) — JWT auth, login, refresh, password changes, and auth status
- [OIDC / SSO](/config/oidc) — single sign-on with Keycloak, Authentik, Authelia, Google, Azure AD
- [WOPI (Office Editing)](/config/wopi) — Collabora Online / OnlyOffice integration
+107
View File
@@ -0,0 +1,107 @@
# OIDC Config Examples
This page collects provider-specific OpenID Connect examples for OxiCloud. Use it together with the base reference in [OIDC / SSO](/config/oidc).
## Base Environment Variables
```bash
OXICLOUD_OIDC_ENABLED=true
OXICLOUD_OIDC_PROVIDER_NAME="Display Name"
OXICLOUD_OIDC_ISSUER_URL="https://provider.example.com/realms/your-realm"
OXICLOUD_OIDC_CLIENT_ID="your-client-id"
OXICLOUD_OIDC_CLIENT_SECRET="your-client-secret"
OXICLOUD_OIDC_REDIRECT_URI="https://your-oxicloud.example.com/api/auth/oidc/callback"
OXICLOUD_OIDC_SCOPES="openid profile email"
OXICLOUD_OIDC_FRONTEND_URL="https://your-oxicloud.example.com"
OXICLOUD_OIDC_AUTO_PROVISION="true"
OXICLOUD_OIDC_ADMIN_GROUPS="admin-group"
OXICLOUD_OIDC_DISABLE_PASSWORD_LOGIN="false"
```
## Authentik
1. Create an OAuth2 or OpenID Connect application for OxiCloud
2. Register `https://your-oxicloud.example.com/api/auth/oidc/callback` as the callback URL
3. Copy the generated client ID and client secret
```yaml
services:
oxicloud:
image: diocrafts/oxicloud:latest
environment:
OXICLOUD_OIDC_ENABLED: "true"
OXICLOUD_OIDC_PROVIDER_NAME: "Authentik"
OXICLOUD_OIDC_ISSUER_URL: "https://authentik.example.com/application/o/oxicloud"
OXICLOUD_OIDC_CLIENT_ID: "your-authentik-client-id"
OXICLOUD_OIDC_CLIENT_SECRET: "your-authentik-client-secret"
OXICLOUD_OIDC_REDIRECT_URI: "https://oxicloud.example.com/api/auth/oidc/callback"
OXICLOUD_OIDC_SCOPES: "openid profile email"
OXICLOUD_OIDC_FRONTEND_URL: "https://oxicloud.example.com"
```
## Authelia
Configure an OIDC client in Authelia and allow OxiCloud's redirect URI.
```yaml
identity_providers:
oidc:
clients:
- id: oxicloud
description: OxiCloud
public: false
redirect_uris:
- https://oxicloud.example.com/api/auth/oidc/callback
scopes: [openid, profile, email, groups]
```
```yaml
services:
oxicloud:
image: diocrafts/oxicloud:latest
environment:
OXICLOUD_OIDC_PROVIDER_NAME: "Authelia"
OXICLOUD_OIDC_ISSUER_URL: "https://authelia.example.com"
OXICLOUD_OIDC_CLIENT_ID: "oxicloud"
OXICLOUD_OIDC_CLIENT_SECRET: "your-client-secret"
```
## Keycloak
1. Create a confidential client named `oxicloud`
2. Set the valid redirect URI to `https://oxicloud.example.com/api/auth/oidc/callback`
3. Copy the generated client secret
```yaml
services:
oxicloud:
image: diocrafts/oxicloud:latest
environment:
OXICLOUD_OIDC_PROVIDER_NAME: "Keycloak"
OXICLOUD_OIDC_ISSUER_URL: "https://keycloak.example.com/realms/your-realm"
OXICLOUD_OIDC_CLIENT_ID: "oxicloud"
OXICLOUD_OIDC_CLIENT_SECRET: "your-keycloak-client-secret"
OXICLOUD_OIDC_ADMIN_GROUPS: "oxicloud-admins"
```
## Troubleshooting
### Failed to discover the provider
- Verify the issuer URL exactly matches the provider's discovery URL base
- Check DNS, TLS, and network reachability from the OxiCloud container or host
### Invalid redirect URI
- Make the configured callback match exactly on scheme, host, port, and path
- Check for `http` versus `https` mismatches
### Auto-provisioning problems
- Enable `OXICLOUD_OIDC_AUTO_PROVISION=true` if first-login account creation is expected
- Make sure `openid` is included in the configured scopes
## Related Pages
- [OIDC / SSO](/config/oidc)
- [Admin Settings](/config/admin-settings)
+19
View File
@@ -10,6 +10,16 @@ OxiCloud supports OpenID Connect for single sign-on with providers like **Keyclo
4. IdP redirects back to OxiCloud with an auth code
5. OxiCloud exchanges the code for user info and issues its own JWT tokens
## Architecture
OIDC follows the Authorization Code Flow and keeps a clear split between provider communication and local session handling.
- `OidcService` discovers provider metadata, builds authorization URLs, exchanges authorization codes, and validates the token response
- `AuthApplicationService` coordinates user lookup or auto-provisioning and then issues OxiCloud's own access and refresh tokens
- the auth handler exposes the public OIDC endpoints under `/api/auth/oidc/*`
After the browser returns from the IdP, OxiCloud does not reuse the provider token for app requests. It converts the identity into its own JWT session model.
## Configuration
```bash
@@ -54,6 +64,15 @@ If `OXICLOUD_OIDC_ENABLED=true` but `issuer_url`, `client_id`, or `client_secret
| GET | `/api/auth/oidc/callback` | Callback from IdP with auth code |
| POST | `/api/auth/oidc/exchange` | Exchange auth code for JWT tokens |
## Identity Mapping
OIDC users are matched by the pair:
- `oidc_provider`
- `oidc_subject`
This allows one external identity to map to one local user record and supports just-in-time provisioning when `OXICLOUD_OIDC_AUTO_PROVISION=true`.
## Provider Examples
### Keycloak
+28 -1
View File
@@ -9,6 +9,15 @@ OxiCloud integrates with **Collabora Online** and **OnlyOffice** via the WOPI pr
3. The editor fetches the file from OxiCloud via WOPI endpoints
4. Edits are saved back via `PutFile`
## Host / Client Flow
OxiCloud acts as the **WOPI host** and Collabora or OnlyOffice acts as the **WOPI client**.
1. OxiCloud loads the discovery document from the configured WOPI client
2. The frontend opens a host page that embeds the editor in an iframe
3. The iframe URL includes `WOPISrc`, which points back to OxiCloud's `/wopi/files/*` endpoints
4. The editor calls back into OxiCloud with the WOPI access token to read, lock, and save the file
## Configuration
```bash
@@ -68,7 +77,25 @@ services:
| GET | `/wopi/files/{id}` | CheckFileInfo — file metadata |
| GET | `/wopi/files/{id}/contents` | GetFile — download file content |
| POST | `/wopi/files/{id}/contents` | PutFile — save edited content |
| POST | `/wopi/files/{id}` | Lock / Unlock / RefreshLock |
| POST | `/wopi/files/{id}` | Lock / Unlock / RefreshLock / Rename / Delete / Save As |
### Common `X-WOPI-Override` operations
| Override | Purpose |
| --- | --- |
| `LOCK` | Acquire or refresh an editor lock |
| `UNLOCK` | Release a lock |
| `REFRESH_LOCK` | Extend the current lock |
| `PUT_RELATIVE` | Save as a related file |
| `RENAME_FILE` | Rename from inside the editor |
| `DELETE` | Delete from the editor when supported |
## Notes
- `CheckFileInfo` is required for every WOPI action
- `PutFile` uploads the full file content back to OxiCloud
- lock conflicts return `409 Conflict` with the current lock value
- OxiCloud uses query parameter `?access_token=` authentication for WOPI callbacks instead of the standard JWT middleware
## Supported Formats
+120
View File
@@ -0,0 +1,120 @@
# Batch Operations
OxiCloud exposes batch endpoints for bulk file and folder operations under `/api/batch`. Batch requests reduce round-trips, run concurrently behind a semaphore, and return per-item success and failure details instead of aborting on the first error.
## What You Can Do
### File operations
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/files/move` | Move multiple files into a target folder |
| `POST` | `/api/batch/files/copy` | Copy multiple files into a target folder |
| `POST` | `/api/batch/files/delete` | Delete multiple files |
| `POST` | `/api/batch/files/get` | Fetch metadata for multiple files |
### Folder operations
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/folders/delete` | Delete multiple folders |
| `POST` | `/api/batch/folders/create` | Create multiple folders |
| `POST` | `/api/batch/folders/get` | Fetch metadata for multiple folders |
| `POST` | `/api/batch/folders/move` | Move multiple folders |
### Additional batch endpoints
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/trash` | Trash multiple items in one request |
| `POST` | `/api/batch/download` | Build a batch download |
## Request Shapes
### File move or copy
```json
{
"file_ids": ["id-1", "id-2", "id-3"],
"target_folder_id": "folder-abc"
}
```
### Folder delete
```json
{
"folder_ids": ["folder-1", "folder-2"],
"recursive": true
}
```
### Folder create
```json
{
"folders": [
{ "name": "Documents", "parent_id": null },
{ "name": "Photos", "parent_id": "folder-abc" }
]
}
```
## Response Format
All batch endpoints return the same envelope:
```json
{
"successful": [
{ "id": "id-1" }
],
"failed": [
{ "id": "bad-id", "error": "File not found" }
],
"stats": {
"total": 5,
"successful": 4,
"failed": 1,
"execution_time_ms": 245
}
}
```
### Status codes
| Code | Meaning |
| --- | --- |
| `200 OK` or `201 Created` | Every operation succeeded |
| `206 Partial Content` | Some operations succeeded and some failed |
| `400 Bad Request` | Every operation failed |
## Concurrency Model
Batch work is coordinated by `BatchOperationService` and a `tokio::sync::Semaphore`. By default, OxiCloud caps concurrent work with `max_concurrent_files = 10` so large batches do not starve the rest of the application.
Individual failures are collected in the `failed` array. One bad item does not cancel the whole request unless the batch cannot start at all.
## Example
```bash
# Move three files into a folder
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"file_ids":["id-1","id-2","id-3"],"target_folder_id":"folder-abc"}' \
"https://oxicloud.example.com/api/batch/files/move"
# Delete multiple folders recursively
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"folder_ids":["old-1","old-2"],"recursive":true}' \
"https://oxicloud.example.com/api/batch/folders/delete"
```
## Related Pages
- [Search](/guide/search)
- [Trash & Recycle Bin](/guide/trash)
- [ZIP and Compression](/guide/zip-and-compression)
+56
View File
@@ -16,6 +16,33 @@ https://your-server:8086/caldav/
- RFC 5545 (iCalendar format)
- DAV capabilities: `1, 2, calendar-access`
### Route Structure
CalDAV is mounted at the top level, not under `/api`:
- `/caldav`
- `/caldav/`
- `/caldav/{*path}`
OxiCloud also exposes `/.well-known/caldav` and redirects it to `/caldav/`.
Typical resource shapes:
- `/caldav/` for the calendar home
- `/caldav/{calendar_id}/` for one calendar
- `/caldav/{calendar_id}/{ical_uid}.ics` for one event
### Supported Methods
- `OPTIONS`
- `PROPFIND`
- `REPORT`
- `MKCALENDAR`
- `PUT`
- `GET`
- `DELETE`
- `PROPPATCH`
### Client Setup
| Client | URL |
@@ -48,6 +75,31 @@ https://your-server:8086/carddav/
- RFC 6352 (CardDAV)
- RFC 6350 (vCard 4.0)
### Route Structure
CardDAV is also mounted at the top level:
- `/carddav`
- `/carddav/`
- `/carddav/{*path}`
Typical resource shapes:
- `/carddav/` for the address book home
- `/carddav/{addressBookId}/` for one address book
- `/carddav/{addressBookId}/{contactId}.vcf` for one contact
### Supported Methods
- `OPTIONS`
- `PROPFIND`
- `REPORT`
- `MKCOL`
- `PUT`
- `GET`
- `DELETE`
- `PROPPATCH`
### Client Setup
| Client | URL |
@@ -68,3 +120,7 @@ https://your-server:8086/carddav/
::: info
DAVx⁵ file sync works. CalDAV/CardDAV support on DAVx⁵ is still being refined.
:::
## Client Setup
For platform-specific instructions, see [DAV Client Setup](/guide/dav-client-setup).
+82 -38
View File
@@ -1,63 +1,107 @@
# Chunked Uploads
OxiCloud supports TUS-like chunked uploads for large files. Uploads are parallel, resumable, and have MD5 integrity checks.
OxiCloud exposes resumable chunked uploads under `/api/uploads`. The protocol is TUS-like in spirit, but the concrete API is OxiCloud-specific: create a session, stream chunks with `PATCH`, inspect progress with `HEAD`, then finalize the assembled file.
## How It Works
## Upload Flow
1. Client sends `POST /api/files/upload/init` with file metadata → receives an `upload_id`
2. Client splits the file into chunks and uploads them in parallel via `POST /api/files/upload/chunk`
3. Each chunk includes its index, MD5 hash, and the `upload_id`
4. When all chunks are uploaded, client calls `POST /api/files/upload/complete`
5. Server reassembles the file, verifies integrity, and runs deduplication
1. Create an upload session with `POST /api/uploads`
2. Upload each chunk with `PATCH /api/uploads/{upload_id}?chunk_index=N`
3. Optionally inspect progress with `HEAD /api/uploads/{upload_id}`
4. Finalize with `POST /api/uploads/{upload_id}/complete`
5. Cancel an in-flight upload with `DELETE /api/uploads/{upload_id}` if needed
## API Endpoints
### Initialize Upload
### Create upload session
```http
POST /api/files/upload/init
POST /api/uploads
Content-Type: application/json
{
"file_name": "large-video.mp4",
"filename": "large-video.mp4",
"folder_id": "folder-uuid",
"content_type": "video/mp4",
"total_size": 524288000,
"chunk_size": 8388608,
"total_chunks": 63
"chunk_size": 8388608
}
```
### Upload Chunk
```http
POST /api/files/upload/chunk
Content-Type: multipart/form-data
upload_id: "uuid"
chunk_index: 0
chunk_hash: "md5-hex"
file: <binary>
```
### Complete Upload
```http
POST /api/files/upload/complete
Content-Type: application/json
Typical response:
```json
{
"upload_id": "uuid"
"upload_id": "uuid",
"chunk_size": 8388608,
"total_chunks": 63,
"expires_at": 86400
}
```
## Configuration
### Upload a chunk
| Parameter | Default | Description |
|---|---|---|
| Max parallel chunks | 8 | Concurrent chunk uploads |
| Min size for chunking | 200 MB | Below this, single-shot upload is used |
| Chunk size | 8 MB | Default chunk size |
Chunks are sent as raw bytes, not multipart form uploads.
## Frontend Behaviour
```http
PATCH /api/uploads/{upload_id}?chunk_index=0&checksum=md5-hex
Content-Type: application/octet-stream
Content-MD5: md5-hex
The OxiCloud web UI automatically selects chunked upload for large files. A progress bar shows overall completion and current chunk status.
<binary chunk bytes>
```
Notes:
- `chunk_index` is required and zero-based
- `checksum` is optional and can also be supplied with the `Content-MD5` header
- Successful responses include progress headers such as `Upload-Offset`, `Upload-Progress`, and `Upload-Complete`
### Inspect upload status
```http
HEAD /api/uploads/{upload_id}
```
The response includes upload metadata in headers such as:
- `Upload-Offset`
- `Upload-Length`
- `Upload-Progress`
- `Upload-Chunks-Total`
- `Upload-Chunks-Complete`
### Finalize upload
```http
POST /api/uploads/{upload_id}/complete
```
Successful responses return the created file metadata:
```json
{
"file_id": "uuid",
"filename": "large-video.mp4",
"size": 524288000,
"path": "/Videos/large-video.mp4"
}
```
### Cancel upload
```http
DELETE /api/uploads/{upload_id}
```
This removes the in-progress session and temporary chunk data.
## Validation Rules
- `filename` is required
- `total_size` must be greater than zero
- `chunk_size` must be at least 1 MB when provided
- Storage quota checks can reject the session before upload starts
## Frontend Behavior
The OxiCloud web UI can switch to chunked uploads for larger files, track aggregate progress, and retry individual chunks without restarting the full transfer.
+101
View File
@@ -0,0 +1,101 @@
# DAV Client Setup
This page collects platform-specific connection steps for OxiCloud's WebDAV, CalDAV, and CardDAV endpoints.
## Connection Summary
| Use case | URL |
| --- | --- |
| WebDAV file access | `https://your-oxicloud-server/webdav/` |
| CalDAV calendar sync | `https://your-oxicloud-server/caldav` |
| CardDAV contact sync | `https://your-oxicloud-server/carddav` |
## WebDAV
### Windows Explorer
1. Open File Explorer
2. Right-click This PC and choose Add a network location or Map network drive
3. Enter `https://your-oxicloud-server/webdav/`
4. Provide your OxiCloud username and password
If Windows refuses the connection, check the `WebClient` service and verify these registry values under `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters`:
- `BasicAuthLevel = 2` when Basic auth is required
- `FileSizeLimitInBytes` if you need to allow larger transfers
### macOS Finder
1. Open Finder
2. Choose Go -> Connect to Server or press Cmd+K
3. Enter `https://your-oxicloud-server/webdav/`
4. Sign in with your OxiCloud credentials
### Linux
- GNOME Files: use `davs://your-oxicloud-server/webdav/`
- KDE Dolphin: use `webdavs://your-oxicloud-server/webdav/`
- `davfs2`: mount `https://your-oxicloud-server/webdav/` to a local directory
## CalDAV
### Apple Calendar
Use an advanced CalDAV account and point it at `https://your-oxicloud-server/caldav`.
### Thunderbird
Create a network calendar and use a CalDAV location such as:
```text
https://your-oxicloud-server/caldav/calendars/your-calendar-id
```
### Android with DAVx5
Use Login with URL and username, then point the base URL at `https://your-oxicloud-server/caldav`.
### Outlook on Windows
Use a CalDAV plugin such as CalDAV Synchronizer and register the calendar endpoint explicitly.
## CardDAV
### Apple Contacts
Create a CardDAV account using `https://your-oxicloud-server/carddav`.
### Thunderbird
Use a remote address book with a URL such as:
```text
https://your-oxicloud-server/carddav/address-books/your-address-book-id
```
### Android with DAVx5
Use the CardDAV base URL `https://your-oxicloud-server/carddav`.
### Outlook on Windows
Use a CardDAV-capable synchronizer and configure the remote address book endpoint explicitly.
## Troubleshooting
### WebDAV
- Make sure the URL includes `/webdav/`
- Use HTTPS in production
- Recheck credentials and the WebClient service on Windows
### CalDAV and CardDAV
- Use the full `/caldav` or `/carddav` base path
- Verify the calendar or address book identifier when the client asks for one
- If sync works on one client and not another, compare the exact URLs being used
## Related Pages
- [WebDAV](/guide/webdav)
- [CalDAV & CardDAV](/guide/caldav-carddav)
+50 -31
View File
@@ -1,46 +1,65 @@
# File Deduplication
OxiCloud uses **SHA-256 content-addressable storage** to avoid storing duplicate files. If two users upload the same file, only one copy is stored on disk.
OxiCloud uses **content-defined chunking (CDC)** with **FastCDC** and **BLAKE3** to deduplicate files at the sub-file level. Instead of storing only whole-file blobs, OxiCloud can split a file into variable-size chunks, reuse unchanged chunks across versions, and track the ordered chunk list in PostgreSQL.
## How It Works
1. When a file is uploaded, its SHA-256 hash is computed
2. The hash is checked against the blob store (`.blobs/{prefix}/{hash}.blob`)
3. If a blob with that hash already exists, the file metadata points to the existing blob (no extra disk usage)
4. If not, the content is saved as a new blob
5. A reference counter tracks how many files point to each blob
1. OxiCloud analyzes the uploaded file with FastCDC
2. The file is split into variable-size chunks from **64 KB** to **1 MB**, targeting an average of **256 KB**
3. Each chunk is hashed with **BLAKE3** and checked against the blob index
4. Only new chunks are written to the blob backend
5. A manifest in PostgreSQL maps the whole-file hash to the ordered chunk hash list
6. Reference counts are updated so identical chunks are stored once even across multiple files or edited versions
## Automatic Cleanup
## Storage Model
```text
storage.files -> metadata rows that reference content
chunk_manifests -> file_hash -> [chunk_hashes] + chunk_sizes + ref_count
storage.blobs -> per-chunk blob metadata and reference counts
blob backend -> actual chunk bytes on disk or remote storage
```
The manifest table is created in `migrations/20260414000000_chunk_manifests.sql` and keeps:
- `file_hash`
- ordered `chunk_hashes`
- `chunk_sizes`
- `total_size`
- `chunk_count`
- `ref_count`
## Why CDC Matters
Whole-file dedup only helps when two files are byte-for-byte identical. CDC helps when files are similar but not identical, for example:
- edited office documents
- versioned project archives
- large media files with partial changes
In those cases, unchanged chunks can be reused and only the modified portions need new storage.
## Backward Compatibility
Older uploads stored before CDC are still readable. When OxiCloud does not find a matching manifest row, it falls back to legacy whole-file blob reads.
## Cleanup Behavior
When a file is permanently deleted:
1. The blob's reference count is decremented
2. If the reference count reaches zero, the blob is removed from disk
1. OxiCloud decrements the manifest reference count
2. If the last manifest reference disappears, chunk refcounts are decremented
3. Chunks with `ref_count = 0` are removed from the blob index and then deleted from the backend
This means disk space is only freed when the **last** reference to a blob is removed.
## Storage Layout
```
storage/
├── .blobs/
│ ├── a1/
│ │ └── a1b2c3d4...sha256.blob
│ ├── f8/
│ │ └── f8e7d6c5...sha256.blob
│ └── ...
```
The first two hex characters of the hash are used as a directory prefix to avoid having millions of files in a single directory.
This keeps storage correct even when multiple files share the same chunk set.
## Benefits
- **Disk savings** — identical files across users consume storage only once
- **Instant uploads** — if the blob already exists, the upload completes immediately
- **Integrity** — SHA-256 ensures bit-for-bit correctness
- Better storage savings for edited and versioned files
- Faster repeat uploads when many chunks already exist
- BLAKE3 hashing for fast content verification
- PostgreSQL-backed manifests for durable indexing and cleanup
## Limitations
## Related Endpoints
- Deduplication is based on exact content match (byte-identical files)
- Near-duplicate files (e.g., a JPEG re-saved at slightly different quality) are stored separately
- Encryption at rest would require per-user keys, which breaks deduplication (planned as opt-in)
The dedup subsystem is also exposed through helper endpoints under `/api/dedup` for hash checks, deduplicated uploads, statistics, and maintenance operations.
+100
View File
@@ -0,0 +1,100 @@
# Favorites and Recent Items
OxiCloud includes two per-user tracking features backed by PostgreSQL:
- Favorites for pinning files and folders you want to reach quickly
- Recent items for tracking the files and folders you accessed most recently
Both features are enabled when the instance has a database connection.
## Favorites
### API
All routes live under `/api/favorites` and require authentication.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/favorites/` | List all favorites for the current user |
| `POST` | `/api/favorites/{item_type}/{item_id}` | Add a file or folder to favorites |
| `DELETE` | `/api/favorites/{item_type}/{item_id}` | Remove a favorite |
`item_type` must be either `file` or `folder`.
### Behavior
- Adding the same item twice is idempotent
- Results are ordered by `created_at DESC`
- User identity comes from the JWT, not the request body
### Storage model
Favorites are stored in `auth.user_favorites` with a uniqueness constraint on `(user_id, item_id, item_type)`.
```sql
CREATE TABLE IF NOT EXISTS auth.user_favorites (
id SERIAL PRIMARY KEY,
user_id VARCHAR(36) NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
item_id TEXT NOT NULL,
item_type TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, item_id, item_type)
);
```
## Recent Items
### API
All routes live under `/api/recent` and require authentication.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/recent/` | List recent items, optionally with `?limit=N` |
| `POST` | `/api/recent/{item_type}/{item_id}` | Record an access |
| `DELETE` | `/api/recent/{item_type}/{item_id}` | Remove one item from history |
| `DELETE` | `/api/recent/clear` | Clear all recent items |
### Behavior
- Default maximum per user: 50 items
- Re-accessing an item updates its `accessed_at` timestamp
- Old items are automatically pruned after inserts
- Results are ordered by `accessed_at DESC`
### Storage model
Recent items are stored in `auth.user_recent_files`.
```sql
CREATE TABLE IF NOT EXISTS auth.user_recent_files (
id SERIAL PRIMARY KEY,
user_id VARCHAR(36) NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
item_id TEXT NOT NULL,
item_type TEXT NOT NULL,
accessed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, item_id, item_type)
);
```
## Example
```bash
# Add a file to favorites
curl -X POST -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/favorites/file/abc-123"
# List recent items
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/recent/?limit=10"
# Clear recent history
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/recent/clear"
```
## Related Pages
- [Search](/guide/search)
- [Trash & Recycle Bin](/guide/trash)
- [Batch Operations](/guide/batch-operations)
+65
View File
@@ -0,0 +1,65 @@
# Internationalization
OxiCloud exposes a public translation API backed by JSON locale files on disk. Locales are loaded lazily, cached in memory, and served without authentication.
## Public API
All routes live under `/api/i18n`.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/i18n/locales` | List available locales |
| `GET` | `/api/i18n/translate?key=...&locale=...` | Resolve a single key |
| `GET` | `/api/i18n/locales/{locale_code}` | Fetch all translations for one locale |
## Locale Files
Translations are stored as nested JSON files under `static/locales/`.
Example shape:
```json
{
"app": {
"title": "OxiCloud"
},
"nav": {
"files": "Files",
"trash": "Trash"
}
}
```
Keys are resolved with dot notation, so `nav.files` maps to `Files`.
## Fallback Rules
- If a key is missing in the requested locale, OxiCloud falls back to English
- If the key is missing there as well, the API returns a not-found error for that key
## Caching Model
Translations are cached in memory with an `RwLock<HashMap<Locale, serde_json::Value>>` and loaded on first use for each locale.
## Frontend Usage
Typical frontend flow:
1. Detect the preferred locale
2. Request `/api/i18n/locales/{code}`
3. Apply translated strings to UI elements
## Example
```bash
# List locales
curl "https://oxicloud.example.com/api/i18n/locales"
# Fetch one translation
curl "https://oxicloud.example.com/api/i18n/translate?key=app.title&locale=es"
```
## Related Pages
- [Internal Architecture](/architecture/)
- [Environment Variables](/config/env)
+27 -16
View File
@@ -3,8 +3,8 @@
## Docker (recommended)
```bash
git clone https://github.com/DioCrafts/oxicloud.git
cd oxicloud
git clone https://github.com/DioCrafts/OxiCloud.git
cd OxiCloud
cp example.env .env
docker compose up -d
```
@@ -16,14 +16,15 @@ Open **http://localhost:8086**. That's it.
```yaml
services:
postgres:
image: postgres:17.4-alpine
image: postgres:18.2-alpine3.23
environment:
POSTGRES_DB: oxicloud
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
- ./db/schema.sql:/docker-entrypoint-initdb.d/schema.sql
- pg_data:/var/lib/postgresql/
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
@@ -32,6 +33,9 @@ services:
oxicloud:
image: diocrafts/oxicloud:latest
build:
context: .
dockerfile: Dockerfile
ports:
- "8086:8086"
env_file:
@@ -52,13 +56,19 @@ volumes:
Requires **Rust 1.93+** and **PostgreSQL 13+**.
```bash
git clone https://github.com/DioCrafts/oxicloud.git
cd oxicloud
echo "DATABASE_URL=postgres://user:pass@localhost/oxicloud" > .env
git clone https://github.com/DioCrafts/OxiCloud.git
cd OxiCloud
cp example.env .env
# Edit .env and set OXICLOUD_DB_CONNECTION_STRING for runtime
export DATABASE_URL=postgres://user:pass@localhost:5432/oxicloud
cargo build --release
cargo run --release
```
`OXICLOUD_DB_CONNECTION_STRING` is the runtime setting read by OxiCloud. `DATABASE_URL` is only needed for SQLx build-time checks.
## Kubernetes (Helm)
```bash
@@ -77,14 +87,14 @@ kubectl logs statefulset/oxicloud -n oxicloud
| Client | Protocol | URL |
|--------|----------|-----|
| Windows Explorer | WebDAV | `http://host:8086/webdav/` |
| macOS Finder | WebDAV | `http://host:8086/webdav/` |
| Nautilus / Dolphin | WebDAV | `dav://host:8086/webdav/` |
| Thunderbird (calendar) | CalDAV | `http://host:8086/caldav/` |
| Thunderbird (contacts) | CardDAV | `http://host:8086/carddav/` |
| DAVx⁵ (Android) | CalDAV + CardDAV | `http://host:8086/` |
| GNOME Calendar | CalDAV | `http://host:8086/caldav/` |
| GNOME Contacts | CardDAV | `http://host:8086/carddav/` |
| Windows Explorer | WebDAV | `https://host/webdav/` |
| macOS Finder | WebDAV | `https://host/webdav/` |
| Nautilus / Dolphin | WebDAV | `davs://host/webdav/` |
| Thunderbird (calendar) | CalDAV | `https://host/caldav/` |
| Thunderbird (contacts) | CardDAV | `https://host/carddav/` |
| DAVx⁵ (Android) | CalDAV + CardDAV | `https://host/` |
| GNOME Calendar | CalDAV | `https://host/caldav/` |
| GNOME Contacts | CardDAV | `https://host/carddav/` |
| Collabora / OnlyOffice | WOPI | See [WOPI configuration](/config/wopi) |
## What's Next?
@@ -92,3 +102,4 @@ kubectl logs statefulset/oxicloud -n oxicloud
- [Environment Variables →](/config/env)
- [OIDC / SSO Setup →](/config/oidc)
- [WebDAV Guide →](/guide/webdav)
- [DAV Client Setup →](/guide/dav-client-setup)
+50 -27
View File
@@ -1,43 +1,66 @@
# Search
OxiCloud provides full-text search across your files with multiple filter options.
OxiCloud provides authenticated file and folder search with simple query parameters, advanced JSON criteria, pagination, recursive traversal, and in-memory result caching.
## Endpoint
## Endpoints
```http
GET /api/search?q=report&type_filter=pdf,docx&recursive=true
```
| Method | Endpoint | Description |
| --- | --- | --- |
| `GET` | `/api/search/` | Simple search using query parameters |
| `POST` | `/api/search/advanced` | Advanced search with a JSON body |
| `GET` | `/api/search/suggest` | Lightweight autocomplete suggestions |
| `DELETE` | `/api/search/cache` | Clear the search results cache |
## Query Parameters
All search endpoints require authentication.
## Simple Search Parameters
| Parameter | Description |
|---|---|
| `q` | Search query (matches file name) |
| `type_filter` | Comma-separated file extensions to filter by |
| `folder_id` | Restrict search to a specific folder |
| `recursive` | `true` to search subfolders |
| `date_from` / `date_to` | Filter by modification date |
| `size_min` / `size_max` | Filter by file size (bytes) |
| `limit` | Maximum results to return |
| --- | --- |
| `query` | Text to search in file and folder names |
| `type` | Comma-separated file extensions |
| `created_after` / `created_before` | Filter by creation time |
| `modified_after` / `modified_before` | Filter by modification time |
| `min_size` / `max_size` | Filter by file size in bytes |
| `folder_id` | Restrict search scope to one folder |
| `recursive` | Search subfolders, defaults to `true` |
| `limit` | Maximum results, defaults to `100` |
| `offset` | Pagination offset |
| `sort_by` | `relevance`, `name`, `name_desc`, `date`, `date_desc`, `size`, or `size_desc` |
## How It Works
### Example
OxiCloud stores file metadata in PostgreSQL with an `ltree` path column, enabling efficient recursive subtree queries:
```sql
SELECT * FROM storage.files
WHERE path <@ 'root.folder_id'
AND LOWER(name) LIKE '%query%'
AND LOWER(extension) = ANY('{pdf,docx}')
ORDER BY updated_at DESC
LIMIT 50;
```bash
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/search/?query=report&type=pdf,docx&recursive=true&limit=20"
```
## Frontend
## Advanced Search
The web UI includes a search bar in the toolbar. Results appear instantly with file name, path, size, and type. Clicking a result navigates to the file's location.
```json
{
"name_contains": "report",
"file_types": ["pdf", "docx"],
"min_size": 1024,
"folder_id": "folder-uuid",
"recursive": true,
"limit": 50,
"offset": 0
}
```
## Suggestions
Use `/api/search/suggest?query=rep&limit=10` for quick autocomplete-style results. Suggestions can also be scoped to a folder with `folder_id`.
## Result Caching
Search results are cached in memory using the search criteria and user ID as the cache key.
- Cache TTL: 5 minutes
- Max entries: 1000
- Manual invalidation: `DELETE /api/search/cache`
## Feature Flag
Search can be disabled via `OXICLOUD_ENABLE_SEARCH=false`.
Search can be disabled with `OXICLOUD_ENABLE_SEARCH=false`.
+96
View File
@@ -0,0 +1,96 @@
# Thumbnails and Transcoding
OxiCloud optimizes image delivery with two complementary features:
- WebP thumbnail generation in three sizes
- On-the-fly image transcoding for browsers that advertise WebP support
Both features use a memory cache plus a persistent disk cache and are designed to stay off the request hot path whenever possible.
## Thumbnails
### Supported sizes
| Size | Dimensions | Directory |
| --- | --- | --- |
| `icon` | 150 x 150 | `.thumbnails/icon/` |
| `preview` | 400 x 400 | `.thumbnails/preview/` |
| `large` | 800 x 800 | `.thumbnails/large/` |
### Supported inputs
`image/jpeg`, `image/jpg`, `image/png`, `image/gif`, and `image/webp`
All thumbnail outputs are stored as WebP.
### API
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/files/{id}/thumbnail/{size}` | Fetch a thumbnail |
| `POST` | `/api/files/upload` | Upload a file and pre-generate thumbnails for supported images |
Thumbnail responses include:
- `Content-Type: image/webp`
- `Cache-Control: public, max-age=31536000, immutable`
- `ETag: "thumb-{id}-{size}"`
### Generation flow
1. Upload succeeds through the file API
2. If the MIME type is supported, OxiCloud starts thumbnail generation in a background task
3. If a thumbnail is requested before pre-generation completes, the request can generate it lazily
4. Future requests are served from memory or disk cache
## Image Transcoding
OxiCloud can serve a smaller WebP version of uploaded JPEG, PNG, or GIF files when the client advertises WebP support in the `Accept` header.
### Rules
- Files over 5 MB skip transcoding
- Existing WebP files are not transcoded again
- SVG and BMP are not transcoded
- If the WebP output is larger than the original, OxiCloud serves the original file instead
### Storage layout
```text
<storage_path>/
.transcoded/
webp/
<file_id>.webp
```
### Statistics tracked by the service
- Cache hits
- Disk hits
- Successful transcodes
- Bytes saved
- Transcode errors
## Caching
Both thumbnail and transcode services use:
- An in-memory LRU cache for hot assets
- A disk cache for persistent reuse across restarts
- Fire-and-forget background writes for cache warmup
For the broader cache model across metadata and listings, see [Caching Architecture](/architecture/caching).
## Example
```text
Client: GET /api/files/abc-123/download
Accept: image/webp, image/png, */*
Server: checks cache -> transcodes if needed -> returns the smaller asset
```
## Related Pages
- [Caching Architecture](/architecture/caching)
- [ZIP and Compression](/guide/zip-and-compression)
+12 -1
View File
@@ -9,12 +9,21 @@ OxiCloud provides a trash system that soft-deletes files and folders, allowing u
3. Users can browse the trash, restore items, or permanently delete them
4. Items older than the retention period (default: **30 days**) are automatically purged
## Storage Model
- files and folders keep their original rows in PostgreSQL
- deletion into trash only flips soft-delete state and records the original parent location for restore
- blob content is not moved when an item enters the trash
- the unified `storage.trash_items` view is used to list trashed files and folders together
## API Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/trash` | List trashed items |
| POST | `/api/trash/restore/{id}` | Restore a trashed item |
| DELETE | `/api/trash/files/{id}` | Move a file to the trash |
| DELETE | `/api/trash/folders/{id}` | Move a folder to the trash |
| POST | `/api/trash/{id}/restore` | Restore a trashed item |
| DELETE | `/api/trash/{id}` | Permanently delete |
| DELETE | `/api/trash/empty` | Empty the entire trash |
@@ -25,3 +34,5 @@ Permanent deletion decrements the blob reference count. If no other file points
## Feature Flag
Trash can be disabled via `OXICLOUD_ENABLE_TRASH=false`. When disabled, deletions are permanent.
Retention is controlled by `OXICLOUD_TRASH_RETENTION_DAYS`.
+72
View File
@@ -33,6 +33,65 @@ Always use HTTPS in production — Basic auth sends credentials in every request
| `DELETE` | Delete a file/folder |
| `LOCK` / `UNLOCK` | File locking |
## Common Operations
### List a directory
Use `PROPFIND` with a `Depth` header:
```http
PROPFIND /webdav/projects/ HTTP/1.1
Depth: 1
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
```
Successful directory listings return `207 Multi-Status`.
### Download a file
```http
GET /webdav/projects/document.pdf HTTP/1.1
Authorization: Basic base64(username:password)
```
### Upload or replace a file
```http
PUT /webdav/projects/document.pdf HTTP/1.1
Content-Type: application/pdf
<file bytes>
```
### Create a folder
```http
MKCOL /webdav/projects/new-folder HTTP/1.1
```
### Move or copy
```http
MOVE /webdav/old-location.pdf HTTP/1.1
Destination: https://your-server/webdav/new-location.pdf
```
```http
COPY /webdav/original.pdf HTTP/1.1
Destination: https://your-server/webdav/copy.pdf
```
### Delete a resource
```http
DELETE /webdav/projects/document.pdf HTTP/1.1
```
## Client Setup
### Windows Explorer
@@ -78,3 +137,16 @@ curl -u user:pass -X MKCOL https://your-server:8086/webdav/new-folder/
## Streaming PROPFIND
OxiCloud streams PROPFIND responses, so listing directories with thousands of files doesn't consume excessive memory.
## Integration Notes
- the WebDAV handler is only an HTTP adapter; file and folder operations still go through the same application services used by the REST API
- HTTP Basic Authentication is supported for DAV clients, while authorization rules remain the same as the rest of OxiCloud
- delete operations integrate with trash when the trash feature is enabled
## Troubleshooting
- Always use the `/webdav/` base path
- Prefer HTTPS because WebDAV uses Basic Authentication
- On Windows, make sure the `WebClient` service is enabled
- OxiCloud rejects path traversal segments such as `.` and `..` at the HTTP boundary
+67
View File
@@ -0,0 +1,67 @@
# ZIP and Compression
OxiCloud ships two compression-related features:
- ZIP download for folders
- Gzip compression for suitable file responses
## ZIP Download
### Endpoint
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/folders/{id}/download` | Download a folder as a ZIP archive |
### How it works
- The ZIP archive is built in memory
- Folder traversal uses an iterative queue rather than recursive async calls
- Cycle detection prevents loops while walking nested folders
- Entries are written with UNIX mode `0o755`
- Compression uses the `Deflated` method from the `zip` crate
### Example
```bash
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/folders/abc-123/download" \
-o my-folder.zip
```
## Gzip Compression
OxiCloud can compress responses when it is worth doing so.
### Compression threshold
Files below 50 KB are skipped.
### Compression levels
| Level | Value |
| --- | --- |
| `None` | `0` |
| `Fast` | `1` |
| `Default` | `6` |
| `Best` | `9` |
### Skip list
These types are not gzipped because they are already compressed or because compression provides poor returns:
- `image/*` except SVG and BMP
- `audio/*`
- `video/*`
- archive formats such as ZIP, gzip, 7z, RAR, bzip2, and XZ
### Runtime behavior
- Compression and decompression run in `spawn_blocking`
- The implementation uses `flate2`
- Optional buffer pooling reduces allocation churn under load
## Related Pages
- [Batch Operations](/guide/batch-operations)
- [Thumbnails and Transcoding](/guide/thumbnails-and-transcoding)