Skip to content
1REDfriendPublic

About

I love tinkering with Single Board Computers and turning them into powerful servers. My latest project is a 'Web NAS' a complete file management system running on Linux, powered by Next.js and accessible via Webssh terminal.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

231 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hello Guy | OpenSource

wellcome to my File Manager web application. this tools will make easy to upload, download file and it has a terminal to use control your linux

Introduction

The File Manager Easy to use, It is opensource u can optimzie, customize your theme and you can pull request for your best edit to me. feature : Drang and Drop, formiddle, xterm, webssh, Nexjs, Manage User, Manager Root Folder.

image

webssh be create by huashengdun GahubLink and Me Modify style to Boostrap -> tailwindcss

Quick Install

curl -fsSL https://raw.githubusercontent.com/1REDfriend/web-nas/main/script.sh | bash

and setup your envorument , npm install && npx prisma generate , etc...

Installation

  • step 1 : install Node js, npm
  • step 2 : download this Web-nas to your favorite directory.
  • step 3 : cd into, npm install && npx prisma generate
  • step 4 : sudo apt install libnss3-tools
  • step 5 : Edit your .env File
  • step 6 : npm run dev or npm run build if you setup .env successful.

NOTE if error xterm your should install sudo apt install build-essential -y for complie "C" lang to type script.

noVNC NOTE if use x64 or AMD please config a docker compose file.

Cloudflare Tunnel ....

If you use cloudflare. You should Disable TLS on cloudflare zero trush

Run cloudflared on the Docker host and point the tunnel at https://localhost:5491. Caddy then takes the visitor's address from Cf-Connecting-IP, so login and API limits count each visitor on their own. It trusts that header only from Docker and loopback addresses (see CaddyFile); widen trusted_proxies there if cloudflared runs somewhere else.

ENV

DATABASE_URL="file:./main.sqlite" => Docker overrides this to /app/data/main.sqlite

TOKEN_COOKIE="your-token_cookie"

JWT_SECRET="your-jwt_secret"

STORAGE_ROOT="your-storage_root" => Docker overrides this to /host_root

STORAGE_INTERNAL="your-storage_internal" => default storage; Docker overrides this to /app/data/storage

TERMINAL_HOST="" => optional host of the web terminal, e.g. nas-ssh.example.com behind a tunnel; read at runtime, so no rebuild is needed; empty means <the host you opened>:7255

COOKIE_DOMAIN="example.com" => optional; set it when the terminal is on another subdomain (e.g. nas.example.com + nas-ssh.example.com) so the login cookie reaches both

PROTECTED_PATHS="" => optional, comma-separated absolute paths that no role (not even ADMIN) can touch from the web UI

STORAGE_WRITABLE_PATHS="" => optional, comma-separated absolute paths that are real disk; when set, uploads, new folders, renames, moves and deletes are refused anywhere else, and these folders themselves cannot be deleted. Docker sets it to the mounted NAS_HOST_DIR

Docker-only (read by docker-compose.yaml):

NAS_HOST_DIR="/mnt" => the only host folder the app can see, mounted at /host_root/mnt; folder assignments use paths like /mnt/...

PUID="1000" / PGID="1000" => host user the app runs as; it can only change files that user may change

WEBNAS_PORT="5491" / WEBSSH_PORT="7255" => host ports published by Caddy

NAS_DROPS_DIR="/mnt/drops" => host folder for drops, inside NAS_HOST_DIR; default NAS_HOST_DIR/drops. The PUID user must be able to create it (e.g. /mnt/sda1/drops when /mnt itself belongs to root)

API_KEY_RATE_LIMIT="120" => optional, requests per minute each API key may make (see API)

PUBLIC_URL="" => optional address people use to reach the app (e.g. https://nas.example.com), used for the links in API answers; empty = taken from the request

DROPS_DEFAULT_DIR="" => folder for drops until an admin picks another one; empty = <STORAGE_INTERNAL>/drops. Docker sets it from NAS_DROPS_DIR

DROPS_SWEEP_SECONDS="300" => how often expired drops are deleted

NOTE the web terminal (port 7255) is ADMIN-only: Caddy checks the file manager login before every request. Open it on the same host name as the file manager, or set COOKIE_DOMAIN, otherwise the browser does not send the login cookie and the terminal answers 401.

Docker

mkdir -p data
docker compose up -d --build

The container syncs the database schema on start and keeps everything that must survive a rebuild in ./data (database and trash).

Upgrading from the old layout (whole host mounted, database in prisma/)

docker compose down
mkdir -p data
cp prisma/main.sqlite data/main.sqlite
sudo cp -a storage data/storage && sudo chown -R 1000:1000 data
docker compose up -d --build

Keep the old files until everything works. Folder assignments outside NAS_HOST_DIR show as Offline until that folder is mounted too.

API

Other programs and servers can store and fetch files through /api/v1 with an API key.

Getting a key

In the web UI open Settings → API keys (/settings/api-keys, ADMIN and USER accounts) and create a key. Choose:

  • Permissions: list (folders and file details), read (download), upload (upload and create folders), delete (move to trash), drop (share temporary files by link, see Drops)
  • Only this folder (optional): the key cannot reach anything outside it, symlinks included
  • Largest upload and Expires after

The full key (wnas_<prefix>_<secret>) is shown once. Only its hash is stored; if you lose it, revoke it and create a new one. A key never gets more than its owner has: folder assignments and Protected Folders rules still apply.

Send it on every request:

Authorization: Bearer wnas_xxxxxxxx_...

Keys work only on /api/v1; every other route needs a browser login.

Endpoints

Method Path Permission Notes
GET /api/v1/me – the key's owner, permissions, folder and limits
GET /api/v1/files?path=/folder list folder contents; page, limit (max 1000), sort=name|size|modified, order=asc|desc. Without path: the key's folder, or your assigned folders
GET /api/v1/files/stat?path=/folder/file list one file or folder
GET /api/v1/files/download?path=/folder/file read supports Range; a folder comes as a zip (not for folder-locked keys)
PUT /api/v1/files/raw?path=/folder/file upload the body is the file; overwrite=1 to replace, mkdirs=0 to require the folder to exist
POST /api/v1/files/upload upload multipart: file, path (folder), optional name, overwrite, mkdirs
POST /api/v1/folders upload JSON { "path": "/folder/new" }, creates parents too
DELETE /api/v1/files?path=/folder/file delete moves it to the owner's trash (restorable from the web UI)

Drops (see below):

Method Path Permission Notes
PUT /api/v1/drops/raw?name=report.pdf drop the body is the file; optional expiresIn (30m, 24h, 7d) and maxDownloads
POST /api/v1/drops/upload drop multipart: file, optional name, expiresIn, maxDownloads
GET /api/v1/drops drop your drops that can still be downloaded; ?id= for one
DELETE /api/v1/drops?id=... drop stop sharing now; the file is deleted shortly after

Responses are JSON: { "ok": true, "data": ... } or { "ok": false, "error": "...", "code": "..." }, except downloads. Codes: BAD_REQUEST, UNAUTHORIZED, INVALID_API_KEY, API_KEY_NOT_ALLOWED, PASSWORD_CHANGE_REQUIRED, FORBIDDEN, NOT_FOUND, CONFLICT, PAYLOAD_TOO_LARGE, RATE_LIMITED, INTERNAL.

Examples

KEY=wnas_xxxxxxxx_...
NAS=https://nas.example.com

curl -H "Authorization: Bearer $KEY" "$NAS/api/v1/me"
curl -H "Authorization: Bearer $KEY" "$NAS/api/v1/files?path=/mnt/backup"
curl -T report.pdf -H "Authorization: Bearer $KEY" "$NAS/api/v1/files/raw?path=/mnt/backup/report.pdf"
curl -F path=/mnt/backup -F file=@photo.jpg -H "Authorization: Bearer $KEY" "$NAS/api/v1/files/upload"
curl -o report.pdf -H "Authorization: Bearer $KEY" "$NAS/api/v1/files/download?path=/mnt/backup/report.pdf"
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"path":"/mnt/backup/2026"}' "$NAS/api/v1/folders"
curl -X DELETE -H "Authorization: Bearer $KEY" "$NAS/api/v1/files?path=/mnt/backup/report.pdf"

Limits

  • Each key may make API_KEY_RATE_LIMIT requests a minute (default 120); after that it gets 429 with Retry-After.
  • Uploads stop at the key's Largest upload (or the server cap of 100 GB) with 413; nothing is left behind.
  • Too many invalid keys from one address get 429 for 15 minutes. Valid keys are never blocked by this.
  • Behind Cloudflare, a single request body is capped by your Cloudflare plan (100 MB on Free), whatever the key allows.

Uploads stream straight to disk; they do not pass through proxy.ts, which would hold the whole body in memory.

Drops (temporary files by link)

A drop is a file that anyone with its link can download until it expires, or until it has been downloaded maxDownloads times. Then it is deleted on its own.

curl -T report.pdf -H "Authorization: Bearer $KEY" "$NAS/api/v1/drops/raw?name=report.pdf&expiresIn=24h&maxDownloads=3"

The answer has url (a page to hand to people) and downloadUrl (for curl/wget), plus expiresAt. Lifetime starts when the upload finishes.

The page at url needs no login. It shows the name, size and time left, previews images, video and audio, and has a Download button. Every download is counted; a link that expired, ran out of downloads or was removed answers 404.

  • A drop without a download limit can be resumed (Range) and previewed.

  • A drop with a download limit is always sent whole and is never previewed, so nobody can fetch it without it being counted.

  • ADMIN sets the default lifetime (24 hours), the longest lifetime (7 days) and a quota per user (10 GB of live drops) in PUT /api/admin/drops.

  • Drops are kept in one drop folder, NAS_HOST_DIR/drops with Docker. An ADMIN can pick another one; the drops already stored move there in the background. The new folder must be empty, missing, or an old drop folder, and nobody can open it from the file manager.

  • GUEST accounts cannot create drops.

Tests

npm run test:e2e runs the end-to-end suites against a throwaway server, database and storage tree; see tests/e2e/README.md. npm run test:unit runs the unit tests in tests/unit.

Protected Folders

Admins can block actions (view, download, upload, rename, move, delete, share) on any folder per role from Settings → Protected folders (/settings/admin/protected-folders). Built-in rules protect OS folders (/etc, /usr, /var, ...) and make GUEST read-only; they can be edited, removed, or restored with Restore defaults.

The app folder and STORAGE_INTERNAL are always locked, and so is anything in PROTECTED_PATHS.

Without Docker, update the database after pulling: npx prisma db push (existing install) or npx prisma migrate deploy (fresh database).

Screen Shot

image image image image

About

I love tinkering with Single Board Computers and turning them into powerful servers. My latest project is a 'Web NAS' a complete file management system running on Linux, powered by Next.js and accessible via Webssh terminal.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages