Everything you need to install, configure, secure, and get the most out of your
private file workspace — from first docker pull to daily operations.
docker pull ghcr.io/suryaprakash251201/nexora:latest-8141398
Docker Compose is the recommended deployment path. It builds both applications and exposes Nexora on port 80.
# 1. Configure the instance
cp .env.example .env
openssl rand -hex 32 # set as NEXORA_SESSION_SECRET
# 2. Start Nexora
docker compose up -d --build
docker compose ps
# 3. Verify it's healthy
curl -f http://localhost/healthz
→ {"service":"nexora","status":"ok","version":"1.9.0"}
# 4. Open your browser and complete first-run setup
open http://localhost
Three supported ways to run Nexora — pick whichever fits your workflow.
git clone https://github.com/suryaprakash251201/nexora.git
cd nexora
cp .env.example .env
docker compose up -d --build
The included Compose file mounts these host folders:
| Host folder | Container path | Access |
|---|---|---|
./data/files | /mnt/files | Read/write |
./data/media | /mnt/media | Read-only |
./data/backups | /mnt/backups | Read/write |
./data/shared | /mnt/shared | Read/write |
The named nexora-data volume contains SQLite, the thumbnail cache, and the temporary archive workspace. Back it up alongside the mounted storage folders.
Pull the official image from GitHub Container Registry and run it directly — no build required:
# 1. Pull the official image
docker pull ghcr.io/suryaprakash251201/nexora:latest-8141398
# 2. Run it — web UI on http://localhost:8080
docker run -d --name nexora \
-p 8080:80 \
-v nexora-data:/app/data \
-v ./data/files:/mnt/files \
-e NEXORA_LISTEN_ADDR=:80 \
-e NEXORA_SESSION_SECRET=$(openssl rand -hex 32) \
ghcr.io/suryaprakash251201/nexora:latest-8141398
Prerequisites: Go 1.26+, Node.js 20+, and npm. Local development works when storage root paths are valid for your host operating system.
# Terminal 1 — API (http://localhost:8080)
go run ./cmd/nexora
# Terminal 2 — web app (http://localhost:5173)
cd web && npm install && npm run dev
The Vite dev server proxies /api and /healthz to http://localhost:8080. For a local root, replace the Docker-oriented defaults in .env:
NEXORA_DEFAULT_ROOTS=Files:./data/files:false
http://localhost in your browser.NEXORA_DEFAULT_ROOTS and grants that administrator access.NEXORA_SECURE_COOKIES=false while testing on plain http://localhost — secure cookies are only sent over HTTPS, so enabling them early will lock you out of logging in. Flip it to true once a TLS proxy is in front (see the next section).
Nexora serves HTTP inside its container. For an internet-facing server, place Caddy, Nginx, Traefik, Cloudflare Tunnel, or another TLS proxy in front of it.
NEXORA_BASE_URL to the public HTTPS URL (used for generated share links).NEXORA_SECURE_COOKIES=true.NEXORA_TRUSTED_PROXIES only to the proxy networks that should be trusted for X-Forwarded-For and X-Real-IP.Two copy-paste starting points. Caddy handles certificates automatically; Nginx needs certbot or your own certificate.
files.example.com {
reverse_proxy 127.0.0.1:8080
}
server {
listen 443 ssl;
server_name files.example.com;
client_max_body_size 0; # no upload ceiling at the proxy
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
client_max_body_size 0 (Nginx) matters — Nginx caps request bodies at 1 MB by default, which surfaces as mysterious failed uploads.
# Public URL for generated share links; no trailing slash
NEXORA_BASE_URL=https://files.example.com
# Use a stable random secret for sessions
NEXORA_SESSION_SECRET=replace-with-a-long-random-secret
# Required when HTTPS is terminated by a reverse proxy
NEXORA_SECURE_COOKIES=true
# Set only when a trusted proxy supplies client-IP headers
# NEXORA_TRUSTED_PROXIES=172.16.0.0/12
Copy .env.example to .env for documented defaults. Key settings:
| Variable | Purpose |
|---|---|
NEXORA_LISTEN_ADDR | HTTP listen address; Compose sets this to :80. |
NEXORA_BASE_URL | Public base URL for generated share links. |
NEXORA_DATA_DIR | Database, cache, and archive-workspace directory. |
NEXORA_DATABASE_TYPE | Metadata store: sqlite (default) or postgres. |
NEXORA_DATABASE_PATH / NEXORA_DATABASE_URL | SQLite path or PostgreSQL connection URL. |
NEXORA_SESSION_SECRET | Session-signing secret (generate with openssl rand -hex 32). |
NEXORA_SESSION_LIFETIME | Session lifetime, e.g. 168h. |
NEXORA_SECURE_COOKIES | Set to true for HTTPS. |
NEXORA_MAX_UPLOAD_SIZE | Maximum upload size, e.g. 512GB (default: effectively unlimited). |
NEXORA_ALLOWED_MIME | Optional comma-separated upload allowlist. |
NEXORA_DEFAULT_ROOTS | Roots created on first setup: Name:/path:readOnly[:indexed]. |
NEXORA_RATE_LIMIT_PER_MIN | Login rate limit (default 60). |
NEXORA_LOCKOUT_ATTEMPTS / NEXORA_LOCKOUT_WINDOW | Account lockout policy (default 5 / 15m). |
NEXORA_TRUSTED_PROXIES | Proxy CIDRs allowed to send client-IP headers. |
NEXORA_CORS_ORIGINS | Allowed browser origins; empty disables CORS. |
NEXORA_ENABLE_FFMPEG_THUMBS | Enables FFmpeg video thumbnail generation. |
NEXORA_THUMBNAIL_MAX_SIZE / NEXORA_THUMBNAIL_TTL | Thumbnail cache policy (default 20MB / 168h). |
NEXORA_ENABLE_PROMETHEUS | Enables the /metrics endpoint. |
NEXORA_MAX_EDITABLE_SIZE | Maximum file size for the built-in editor. |
NEXORA_LOG_LEVEL | Log verbosity: debug, info (default), warn, or error. |
NEXORA_LOG_FORMAT | Log output format: text (default) or json. |
NEXORA_THUMBNAIL_CACHE_DIR | Override the thumbnail cache location (inside NEXORA_DATA_DIR by default). |
Right-click any file for the full action menu: download, preview, rename, move, copy, delete (to trash), archive as ZIP, or add to favorites.
Named locations managed from one UI, with per-user read or write access on each root. Configure defaults in .env:
NEXORA_DEFAULT_ROOTS=Files:/mnt/files:false,Media:/mnt/media:true,Backups:/mnt/backups:false
Create revocable public links with optional expiry, password protection, and download limits. The shared page works for anyone — no account required.
Users, roles, root access, storage settings, storage analytics dashboards, audit history, search reindexing, and file versioning — all from the Admin panel.
Press ? (or Cmd+/ / Ctrl+/) anywhere to see the full searchable overlay.
| Shortcut | Action |
|---|---|
| Cmd+K / Ctrl+K | Open command palette |
| ? / Cmd+/ / Ctrl+/ | Keyboard shortcuts overlay |
| Esc | Close modal / clear selection |
| Shortcut | Action |
|---|---|
| Cmd+N / Ctrl+N | New folder |
| Cmd+Shift+N / Ctrl+Shift+N | New text file |
| Cmd+U / Ctrl+U | Upload files |
| F5 | Refresh view |
| Cmd+D / Ctrl+D | Download selected |
| Cmd+Shift+S / Ctrl+Shift+S | Share selected |
| Cmd+Shift+F / Ctrl+Shift+F | Toggle favorite |
| F2 | Rename selected item |
| Cmd+Shift+M / Ctrl+Shift+M | Move selection |
/tmp filesystem.GET /healthz — livenessGET /readyz — database readinessBack up the nexora-data volume and every mounted storage folder before upgrades. The volume holds:
docker run --rm \
-v nexora-data:/data \
-v $(pwd):/backup alpine \
tar czf /backup/nexora-data.tar.gz -C /data .
# From source builds
docker compose up -d --build
docker compose logs -f nexora
# From a GHCR image, just pull the new tag and recreate
docker pull ghcr.io/suryaprakash251201/nexora:latest-8141398
Application endpoints live under /api/v1; public health checks are /healthz and /readyz. The complete route list is in internal/api/server.go in the repository.
curl -f http://localhost/healthz
→ {"service":"nexora","status":"ok"}
curl -f http://localhost/readyz
→ {"status":"ready"}
Design tokens and visual guidance are in docs/design-system.md; a complete feature walkthrough is in docs/features.md — both in the GitHub repository.
Yes — it's open source under the MIT license. Run it forever, modify it, host it for as many users as you like.
Yes. Set NEXORA_DATABASE_TYPE=postgres and provide NEXORA_DATABASE_URL. SQLite remains the zero-config default. See docker-compose.postgres.yml in the repo.
Follow the instructions in SECURITY.md — do not open a public issue for vulnerabilities.
Mount the exact folder into the container and register it as its own root — roots are paths, not whole drives.
The failure modes people actually hit, and the fix for each.
Nginx caps request bodies at 1 MB by default. Set client_max_body_size 0; in your server block (see the config above). Caddy and Traefik have no default cap.
If NEXORA_SECURE_COOKIES=true is set while the site is still served over HTTP, the browser silently drops the session cookie. Only enable it once TLS is actually in front — or test locally with it set to false.
Thumbnails and transcoding need FFmpeg inside the container (the official image includes it). Verify with docker exec nexora ffmpeg -version, and confirm NEXORA_ENABLE_FFMPEG_THUMBS=true. Direct streaming still works without it via HTTP Range requests.
Two-factor codes depend on server clock accuracy. Check docker exec nexora date against real time — drift breaks RFC 6238 validation. On hosts without RTC (some VPS/ARM boards), enable NTP.
Newly added files are picked up automatically, but if an external process modified the storage folder directly, trigger Admin → Reindex to rebuild the search index.
session secret must be at least 32 bytes on startupThe config validator enforces a strong signing key. Generate one with openssl rand -hex 32 and put it in NEXORA_SESSION_SECRET — or leave it empty once and Nexora will generate and persist one for you.