Documentation

Deploy in Minutes

One command. Full stack. This guide gets you from zero to a running TenzoShare instance.

checklistPrerequisites

deployed_code
Docker Engine
v24.0+
schema
Docker Compose
v2.0+ plugin
dns
Domain / Port
Port 80 exposed, or a domain pointed at the host

Use docker compose (v2 plugin) — not the legacy docker-compose binary.

rocket_launchQuickstart

1 Clone the repository
git clone https://github.com/marcusottosen/TenzoShare.git
cd tenzoshare
2 Configure environment & generate secrets
cp infrastructure/docker/.env.example infrastructure/docker/.env

# Generate required secrets — paste each output into .env
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out jwt_private.pem
openssl rsa -in jwt_private.pem -pubout -out jwt_public.pem
openssl rand -hex 32   # → PASSWORD_PEPPER
openssl rand -hex 32   # → STORAGE_ENCRYPTION_KEY
3 Deploy
cd infrastructure/docker
docker compose up -d
4 Verify (wait ~30s for healthy state)
docker compose ps
5 Log in

Visit http://localhost in your browser.

Admin credentials are set via BOOTSTRAP_ADMIN_EMAIL and BOOTSTRAP_ADMIN_PASSWORD in your .env.

Default email: [email protected]

lightbulb
Exposing TenzoShare externally? Cloudflare Tunnel is a zero-open-ports option — install cloudflared, point the tunnel at http://localhost:80, and you get HTTPS with no port-forwarding or certificate management needed.

settingsKey Environment Variables

VariableRequiredDescription
POSTGRES_PASSWORDRequiredPostgreSQL password
REDIS_PASSWORDRequiredRedis password
JWT_PRIVATE_KEYRequiredRS256 private key (PEM, \n-escaped)
JWT_PUBLIC_KEYRequiredRS256 public key (PEM, \n-escaped)
PASSWORD_PEPPERRequired32-byte hex — mixed into all password hashes
STORAGE_ENCRYPTION_KEYRequired32-byte hex — AES-256-GCM file encryption key
MINIO_ROOT_USERRequiredMinIO admin user
MINIO_ROOT_PASSWORDRequiredMinIO admin password
S3_ACCESS_KEY / S3_SECRET_KEYRequiredS3 credentials (same as MinIO root for local)
BOOTSTRAP_ADMIN_EMAILRequiredEmail for the first admin account
BOOTSTRAP_ADMIN_PASSWORDRequiredPassword for the first admin account
BASE_URLRequiredPublic URL e.g. https://share.example.com
DEV_MODEOptionaltrue relaxes CORS/cookies for local dev
warning

Write-once values: PASSWORD_PEPPER and STORAGE_ENCRYPTION_KEY — changing them invalidates all existing passwords and encrypted files.

storageStorage Configuration

TenzoShare ships with MinIO out of the box — no extra setup needed. To switch to AWS S3 or any S3-compatible store, update these variables:

VariableMinIO (default)AWS S3
S3_ENDPOINThttp://tenzoshare-minio:9000leave blank
S3_BUCKETtenzoshareyour bucket name
S3_REGIONus-east-1your region
S3_ACCESS_KEYMinIO root userIAM access key
S3_SECRET_KEYMinIO root passwordIAM secret key
S3_USE_SSLfalsetrue
tune

Quota, per-user limits, and max upload size are configurable at runtime via the admin portal — no restart needed.

apiAPI Reference

All routes are prefixed with /api/v1 and routed through Traefik on port 80.

Auth /api/v1/auth
POST/register
POST/login
POST/login/mfa
POST/refresh
POST/logout
GET/me
PATCH/me
POST/mfa/setup
POST/mfa/verify
POST/password-reset/request
POST/password-reset/confirm
Files /api/v1/files Bearer JWT required
POST/
GET/
GET/:id
DELETE/:id
GET/:id/presign
GET/:id/download
GET/usage
Transfers /api/v1/transfers Bearer JWT required
POST/
GET/
GET/:id
DELETE/:id
Public Transfer Access /api/v1/t/:slug No auth required
GET/:slug
GET/:slug/files/:fileId/download
File Requests /api/v1/requests Bearer JWT required
POST/
GET/
GET/:id
DELETE/:id
API Keys /api/v1/users/apikeys Bearer JWT required
GET/
POST/
DELETE/:id

bookFurther Reading

monitoring
Observability
Add docker-compose.observability.yml to get Prometheus, Grafana, Loki, and Tempo.
phonelink_lock
TOTP MFA
Enable per-user via the profile page. Admins can enforce it globally from the admin portal.
preview
View-only Transfers
Set view_only: true at transfer creation — files open inline in-browser, no save dialog.
upload_file
File Requests
Share an upload link with anyone — recipients upload directly without needing an account.