Enterprise file management without the enterprise price tag.
Multi-tenant file management and compliance platform built with Rust and React.
Self-host it. Own your data. Stop paying $25/user/month.
Quick Start • Features • Screenshots • Contributing • Hosted Version
Enterprise file management has become absurdly expensive:
| Provider | Cost | Annual (50 users) |
|---|---|---|
| Box Business | $20/user/month | $12,000 |
| Dropbox Business | $18/user/month | $10,800 |
| SharePoint | $12.50/user/month | $7,500 + Microsoft tax |
| Egnyte | $20/user/month | $12,000 |
| ClovaLink | ~$20/month VPS + S3 storage | ~$300-400 total |
| Component | Monthly Cost | Notes |
|---|---|---|
| VPS (4GB RAM) | ~$20 | DigitalOcean, Linode, Hetzner, etc. |
| Backblaze B2 | ~$3-5 | $0.006/GB storage + $0.01/GB egress |
| OR Wasabi | ~$7 | $6.99/mo minimum, no egress fees |
| PostgreSQL | Included | Self-hosted on VPS |
| Redis | Included | Self-hosted on VPS |
| Total | ~$25-30/mo | ~$300-360/year for 50 users |
Storage costs based on ~500GB usage. Scales with actual usage, not user count.
Most small businesses need 80% of enterprise features at 10% of the cost. ClovaLink delivers exactly that.
| You Should Use ClovaLink If... | You Might Not Need ClovaLink If... |
|---|---|
| You need HIPAA/SOX/GDPR compliance | You just need basic cloud storage |
| You manage multiple clients/tenants | You have 5 or fewer users |
| You want full control over your data | You need native Office 365 integration |
| You're an MSP serving multiple companies | Budget isn't a concern |
| You want to avoid per-user pricing |
Want the features without the infrastructure? ClovaLink.com offers a fully managed hosted version for enterprise teams (10+ users).
|
|
|
|
|
|
|
|
| Mode | Enforcements |
|---|---|
| HIPAA | Mandatory MFA, 15-min timeout, audit logging locked, public sharing blocked, 7-year retention |
| SOX | MFA required, file versioning mandatory, audit trails locked, 7-year retention |
| GDPR | Consent tracking, export logging, deletion request support, 2-year retention |
| Standard | No restrictions — full flexibility |
Real-time monitoring for unusual activity patterns:
| Alert Type | Trigger | Severity |
|---|---|---|
| Failed Login Spike | 5+ failed logins in 5 min | High |
| New IP Login | Login from unknown IP | Medium |
| Permission Escalation | Role upgraded to Admin+ | High |
| Bulk Download | 20+ files in 10 min | High |
| Blocked Extension | Prohibited file upload | Low |
| Account Lockout | Too many failed attempts | Critical |
| Malware Detected | Virus found in upload | Critical |
Email notifications automatically sent for Critical and High severity alerts.
Run this single command to install ClovaLink:
curl -fsSL https://raw.githubusercontent.com/ClovaLink/ClovaLink/main/install.sh | bashThe installer will:
- Check if Docker is installed
- Download the configuration files
- Generate secure secrets automatically
- Start all services
- Show you the login URL
That's it! Follow the prompts and you'll be running in minutes.
curl -fsSL https://raw.githubusercontent.com/ClovaLink/ClovaLink/main/install.sh | bash -s -- --updateThis will back up your config, pull the latest images, and restart services. Migrations run automatically.
Click here for step-by-step manual setup
If you don't have Docker installed yet:
| Operating System | Installation |
|---|---|
| Windows | Download Docker Desktop and run the installer |
| Mac | Download Docker Desktop or run brew install --cask docker |
| Linux (Ubuntu/Debian) | Run: `curl -fsSL https://get.docker.com |
Verify Docker is installed:
docker --version
# Should show: Docker version 24.x or higherOpen a terminal and run these commands one at a time:
# Create a folder for ClovaLink
mkdir clovalink
cd clovalink
# Download the configuration files
curl -LO https://raw.githubusercontent.com/ClovaLink/ClovaLink/main/infra/compose.yml
curl -LO https://raw.githubusercontent.com/ClovaLink/ClovaLink/main/infra/.env.example# Create your config file from the example
mv .env.example .env
# Open it in a text editor
nano .env # Linux/Mac
# Or: notepad .env # WindowsImportant settings to change:
JWT_SECRET- Change this to a random string (at least 32 characters)POSTGRES_PASSWORD- Set a secure database password
Save the file when done (in nano: press Ctrl+X, then Y, then Enter).
docker compose up -dThis will download and start all the services. First run takes 2-5 minutes.
Open your browser and go to:
| Service | URL |
|---|---|
| Web Interface | http://localhost:8080 |
| API | http://localhost:3000 |
| Role | Password | |
|---|---|---|
| SuperAdmin | [email protected] | password123 |
| Admin | [email protected] | password123 |
| Manager | [email protected] | password123 |
| Employee | [email protected] | password123 |
Important: Change these passwords immediately after first login!
# Check if everything is running
docker compose ps
# View logs (if something isn't working)
docker compose logs -f
# Stop ClovaLink
docker compose down
# Restart ClovaLink
docker compose restart
# Update to latest version
docker compose pull
docker compose up -dPort 8080 already in use?
Edit compose.yml and change 8080:80 to another port like 8888:80, then run docker compose up -d again.
Docker command not found?
Make sure Docker Desktop is running (Windows/Mac) or the Docker service is started (Linux: sudo systemctl start docker).
Permission denied errors on Linux?
Add your user to the docker group:
sudo usermod -aG docker $USERThen log out and log back in.
Using Podman instead of Docker?
Use podman compose (built-in plugin) instead of docker compose in all commands. If that doesn't work, install podman-compose separately.
Clone Full Repository (for developers)
git clone https://github.com/ClovaLink/ClovaLink.git
cd ClovaLink/infra
cp .env.example .env
nano .env
docker compose up -dBuild from Source
Requires 8GB+ RAM for Rust compilation:
git clone https://github.com/ClovaLink/ClovaLink.git
cd ClovaLink/infra
cp .env.example .env
docker compose -f compose.yml -f compose.build.yml up -d --buildAlternative Container Registries
Images are available from both GHCR and Docker Hub:
# GitHub Container Registry (default)
image: ghcr.io/clovalink/clovalink-backend:latest
# Docker Hub (alternative)
image: clovalink/clovalink-backend:latest| Service | URL |
|---|---|
| Web Interface | http://localhost:8080 |
| API | http://localhost:3000 |
| PostgreSQL | localhost:5433 |
| Redis | localhost:6379 |
| Role | Password | |
|---|---|---|
| SuperAdmin | [email protected] | password123 |
| Admin | [email protected] | password123 |
| Manager | [email protected] | password123 |
| Employee | [email protected] | password123 |
Change these credentials immediately in production!
flowchart TB
subgraph Clients[" "]
direction LR
Browser[Browser] ~~~ Mobile[Mobile] ~~~ API_Client[API Client]
end
subgraph Frontend[Frontend - Nginx]
direction LR
Static[React SPA] ~~~ Proxy[Reverse Proxy]
end
subgraph Backend[Backend - Rust/Axum]
direction LR
API[REST API] --> Auth[Auth] --> RateLimit[Rate Limiter]
end
subgraph Persistence[" "]
direction LR
subgraph Data[Data Layer]
PG[(PostgreSQL)]
Redis[(Redis)]
end
subgraph Storage[Storage Layer]
S3[S3/Wasabi/B2]
Local[Local FS]
end
end
Clients --> Frontend
Frontend --> Backend
Backend --> Data
Backend --> Storage
Extensions: UI extensions, file processors (webhooks), and scheduled jobs run sandboxed with permission grants.
| Technology | Reason |
|---|---|
| Rust | Memory safety, zero-cost abstractions, single binary deployment |
| Axum | Async-first, tower middleware, type-safe extractors |
| SQLx | Compile-time SQL verification against actual schema |
| PostgreSQL | ACID, JSON columns, row-level security, rock solid |
| Redis | Sub-ms sessions, rate limiting, job queues |
| React | Component ecosystem, TypeScript support, mature tooling |
Create backend/.env from the example:
cp backend/.env.example backend/.envDATABASE_URL=postgres://user:pass@localhost:5432/clovalink
REDIS_URL=redis://localhost:6379
JWT_SECRET=generate-a-64-char-random-string-hereLocal Storage (Development)
STORAGE_TYPE=local
UPLOAD_DIR=./uploadsAWS S3
STORAGE_TYPE=s3
S3_BUCKET=your-bucket-name
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_REGION=us-east-1
USE_PRESIGNED_URLS=trueWasabi (S3-compatible, 80% cheaper)
STORAGE_TYPE=s3
S3_BUCKET=your-bucket-name
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_REGION=us-east-1
S3_ENDPOINT=https://s3.wasabisys.com
USE_PRESIGNED_URLS=trueMinIO (Self-hosted)
STORAGE_TYPE=s3
S3_BUCKET=clovalink
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_REGION=us-east-1
S3_ENDPOINT=http://localhost:9000
S3_PATH_STYLE=trueFor enterprise durability, ClovaLink supports asynchronous replication of uploaded files to a secondary S3 bucket. This provides disaster recovery and geographic redundancy.
Two Modes:
| Mode | Behavior |
|---|---|
| backup | Uploads are replicated; deletions are not (keeps historical data) |
| mirror | Both uploads and deletions are synchronized |
Replication Configuration
REPLICATION_ENABLED=true
REPLICATION_ENDPOINT=https://s3.us-west-2.amazonaws.com
REPLICATION_BUCKET=clovalink-backup
REPLICATION_REGION=us-west-2
REPLICATION_ACCESS_KEY=your-access-key
REPLICATION_SECRET_KEY=your-secret-key
REPLICATION_MODE=backup
REPLICATION_RETRY_SECONDS=60
REPLICATION_WORKERS=4Replication is fully async and non-blocking — uploads complete immediately while replication jobs are queued in the background with automatic retries.
ClamAV integration scans all uploads for malware:
ClamAV Configuration
CLAMAV_ENABLED=true
CLAMAV_HOST=clamav
CLAMAV_PORT=3310See Virus Scanning Documentation for quarantine, auto-suspend, and monitoring details.
SSO is configured per-tenant through the admin UI (Settings → SSO). Both OIDC and SAML 2.0 are supported. The following environment variables are only needed if you plan to use SSO:
SSO Configuration
# Required for SSO
SECRETS_ENCRYPTION_KEY=base64-encoded-32-byte-key # For encrypting IdP client secrets
# OIDC callback and frontend URLs are derived from BASE_URL automatically.
# SAML ACS URL and SP Entity ID are derived from BASE_URL automatically.
# Make sure BASE_URL is set correctly (the installer does this for you).Provider-specific settings (issuer URL, client ID/secret, IdP certificates, email domains) are configured in the admin UI, not in environment variables. SAML SP metadata is available at
/api/auth/saml/metadata/:provider_id.
See Deployment Guide for detailed setup instructions.
clovalink/
├── backend/
│ ├── crates/
│ │ ├── api/ # HTTP handlers, routes, middleware
│ │ ├── auth/ # JWT, passwords, 2FA
│ │ ├── core/ # Models, DB, mailer, cache, security
│ │ ├── extensions/ # Extension runtime
│ │ └── storage/ # S3/local storage abstraction
│ └── migrations/ # SQL schema files
├── frontend/
│ └── src/
│ ├── components/ # Reusable UI components
│ ├── context/ # React contexts (Auth, Tenant, Theme)
│ └── pages/ # Route components
└── infra/
├── compose.yml # Docker Compose config
└── Dockerfile.* # Container builds
| Resource | Minimum | Handles |
|---|---|---|
| CPU | 1 core | ~100 concurrent users |
| RAM | 1 GB | Basic operations |
| Storage | 10 GB | App + OS (files separate) |
| PostgreSQL | 14+ | Required |
| Redis | 6+ | Required |
| Resource | Recommended |
|---|---|
| CPU | 2+ cores |
| RAM | 4 GB |
| PostgreSQL | Managed (RDS, Supabase, Neon) |
| Redis | Managed (ElastiCache, Upstash) |
| Storage | S3 or Wasabi |
| Proxy | Nginx/Caddy with TLS |
RUST_LOG=warn
JWT_SECRET=<64-character-cryptographically-random-string>
DATABASE_URL=postgres://...
REDIS_URL=redis://...
STORAGE_TYPE=s3
USE_PRESIGNED_URLS=true
CORS_ALLOWED_ORIGINS=https://yourdomain.com| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/login |
User login |
| POST | /api/auth/register |
User registration |
| POST | /api/public-upload/:token |
File request upload |
| GET | /api/public-download/:token |
Shared file download |
| GET | /api/auth/oidc/providers?email= |
Discover SSO providers (OIDC + SAML) |
| GET | /api/auth/oidc/authorize/:id |
Start OIDC login flow |
| GET | /api/auth/oidc/callback |
OIDC callback handler |
| GET | /api/auth/saml/metadata/:id |
SAML SP metadata XML |
| GET | /api/auth/saml/authorize/:id |
Start SAML login flow |
| POST | /api/auth/saml/acs |
SAML Assertion Consumer Service |
All require Authorization: Bearer <token> header.
| Resource | Operations |
|---|---|
/api/files |
CRUD, upload, download, share, lock, versions |
/api/file-requests |
Create portals, list submissions |
/api/users |
CRUD, roles, departments, suspend |
/api/tenants |
List, create, update, suspend (SuperAdmin) |
/api/departments |
CRUD, member management |
/api/roles |
CRUD, permission management |
/api/settings |
Compliance, branding, SMTP, blocked extensions |
/api/security/alerts |
List, resolve, dismiss alerts |
/api/audit-logs |
Query with filters, export |
/api/groups |
File groups CRUD, add/remove files |
/api/ai |
Summarization, Q&A, usage stats |
/api/oidc/providers |
OIDC provider CRUD (SuperAdmin) |
/api/saml/providers |
SAML provider CRUD (SuperAdmin) |
/api/sso/mappings |
Attribute mapping CRUD (SuperAdmin) |
/api/approvals |
Document approval workflow (pending, history, approve, reject) |
/api/approvals/policies |
Approval policy CRUD (Admin) |
See backend/README.md for complete API documentation.
Security is a core focus of ClovaLink. Key measures include:
- Tenant Isolation: Row-level
tenant_idenforcement on every table - JWT Hardening: Short expiry, issuer/audience validation, key rotation support
- Rate Limiting: Atomic Redis-based limiting on sensitive endpoints
- SQL Safety: Compile-time query validation with SQLx
- Content-Disposition: Filename sanitization prevents header injection
- Zip Slip Prevention: Path validation on archive extraction
- CORS Lockdown: Explicit origin allowlisting in production
- OIDC SSO: State/nonce CSRF protection, encrypted client secrets, lockout prevention
- SAML SSO: XML signature verification (pure Rust), assertion replay protection, time window validation, audience restriction
- Document Approval: Atomic approve/reject operations, tenant-isolated policies, role-based access control, audit logging
See Security Documentation for complete security documentation and hardening guide.
- Multi-tenant architecture
- HIPAA/SOX/GDPR compliance modes
- Role-based access control
- Extension system
- Security alerts dashboard
- Email notifications for alerts
- AI-powered document features (summarization, Q&A)
- File Groups (virtual collections)
- Company Folders (org-wide sharing)
- Office document preview (Excel, PowerPoint)
- OIDC Single Sign-On (Google, Microsoft, Okta)
- SAML 2.0 Single Sign-On (ADFS, Azure AD, Okta)
- IdP attribute/claim mapping (roles & departments)
- Document approval workflow (per-tenant, policy-based)
- Mobile apps (iOS/Android)
- WebDAV support
- Real-time collaboration
- Slack/Teams integration
How is this different from Nextcloud?
Nextcloud is a general-purpose collaboration suite. ClovaLink is purpose-built for:
- True multi-tenancy (not just user groups)
- Compliance-first design (HIPAA/SOX/GDPR modes lock settings)
- MSP-friendly architecture (manage many clients from one instance)
- Rust performance (handles more users with less resources)
Can I migrate from Box/Dropbox/SharePoint?
Not yet via built-in tools, but the API supports bulk upload. Community migration scripts are welcome!
Is there a hosted/SaaS version?
Yes! ClovaLink.com offers a fully managed enterprise version for teams of 10+ users. Get all the features without the infrastructure overhead — we handle updates, backups, and scaling.
Self-hosting remains free and open source for smaller teams or those who prefer full control.
How do I back up my data?
- Database: Standard PostgreSQL backup (pg_dump or managed provider snapshots)
- Files: Sync your storage backend (S3 versioning, rclone for local)
- Config: Version control your
.envfile (secrets in a vault)
What happens if I hit storage limits?
Per-tenant storage quotas can be configured. When exceeded, uploads are blocked until space is freed or quota increased. Admins receive storage warning emails at 80% capacity.
Backend won't start: "Database connection refused"
# Check if PostgreSQL is running
docker compose ps postgres
# View logs
docker compose logs postgres
# Verify DATABASE_URL in .env matches compose.ymlCORS errors in browser
For development, ensure CORS_DEV_MODE=true is set in compose.yml.
For production, set CORS_ALLOWED_ORIGINS to your exact frontend domain.
File uploads fail with "413 Entity Too Large"
Nginx has a default body size limit. Add to your nginx config:
client_max_body_size 100M;Redis connection errors
# Check Redis is running
docker compose ps redis
# Test connection
docker compose exec redis redis-cli ping
# Should return: PONG502 Bad Gateway after restarting the backend
Nginx resolves the backend hostname at startup and caches the IP address. If the backend container restarts and gets a new internal IP, the frontend will return 502 errors because it's still trying to reach the old IP.
Fix: Restart the frontend container after the backend restarts:
docker compose restart frontendThis applies to both Docker and Podman.
Backend crashes with "VersionMismatch"
This happens when a migration SQL file was modified after it was already applied to the database. SQLx stores a checksum for each migration and will refuse to start if it doesn't match.
Fix: Update the stored checksum to match the current file:
# Generate the new checksum
sha256sum backend/migrations/003_oidc_sso.sql
# Update it in the database (replace the hash with your output)
psql $DATABASE_URL -c "UPDATE _sqlx_migrations SET checksum = E'\\x<new_hash>' WHERE version = 3;"Alternatively, if you're in development and don't mind losing data, you can drop and re-run the migration:
psql $DATABASE_URL -c "DELETE FROM _sqlx_migrations WHERE version = 3;"
# Restart the backend — it will re-apply the migration
docker compose restart backendSSO provider not working after creation
SSO providers (OIDC and SAML) default to disabled when first created. This is a safety measure so you can finish configuring them before users can attempt login.
Fix: Go to Settings → SSO, find your provider, and toggle it to Enabled.
Contributions are welcome! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Backend (Rust)
cd backend
cargo run
# Frontend (React)
cd frontend
npm install
npm run dev- Rust:
cargo fmtandcargo clippy - TypeScript: ESLint + Prettier (configured in project)
MIT License — use it however you want. See LICENSE for details.
Stop renting your file management. Own it.





