# SealShare A simple, self-hosted file sharing solution built with Laravel. Upload files, get a shareable link, done. All files are encrypted at rest with AES-256-GCM. **Website:** [sealshare.nonameweb.ch](https://sealshare.nonameweb.ch) ## Screenshots

Uploading files and folders with share options A new share with its link and QR code button

The recipient's download page on a phone

## Features - **File Uploading** — Drag & drop or browse to upload single/multiple files and folders with real-time progress - **Shareable Links** — Each upload generates a unique link for recipients, also as a QR code (saved as a PNG) or through the device's share sheet - **Encryption at Rest** — Files are encrypted on the server as they arrive, with AES-256-GCM (chunked, streaming); with a share password the key is derived from it and never stored. It is not end-to-end encryption: the server handles the files unencrypted while they are uploaded and downloaded - **Password Protection** — Optionally protect shares with a password - **Expiration** — Shares auto-expire after a configurable duration (1 hour to 30 days) - **Download Limits** — Set a maximum number of downloads per share - **ZIP Downloads** — Download all files in a share as a single ZIP archive - **Auto-Cleanup** — Expired shares and files are automatically deleted (hourly) - **Admin Dashboard** — View, manage, and delete all shares - **Admin Settings** — Configure upload limits, storage quotas, branding, and more - **Site Branding** — Custom logo, title, and description - **Colour Profiles** — Eight Material 3 colour profiles (Indigo, Blue, Teal, Green, Amber, Rose, Violet, Graphite); the admin picks one for every page, mail and error page - **System Password** — Optional global password gate to restrict upload access - **User Authentication** — Login, password reset, email verification - **Two-Factor Authentication** — TOTP-based 2FA via Laravel Fortify - **Light and Dark Themes** — Material 3 Expressive design that follows the system theme, or light or dark by choice - **Setup Wizard** — First-run wizard to create the initial admin account ## Tech Stack | Layer | Technology | |-------|-----------| | **Framework** | Laravel 13 | | **Application Server** | FrankenPHP (via Laravel Octane) | | **Frontend** | Livewire 4, Tailwind CSS 4, [Livewire Material](https://gitea.nonameweb.ch/noNameWEB/livewire-material) (Material 3 Expressive) | | **Authentication** | Laravel Fortify | | **Encryption** | Chunked AES-256-GCM with PBKDF2-SHA256 key derivation | | **ZIP Downloads** | Native PHP ZipArchive | | **Testing** | Pest 5 with browser tests (Playwright) | | **Code Style** | Laravel Pint | | **Build Tool** | Vite | ## Installation — Development ### Docker (recommended) ```bash # Build and start the dev container docker compose -f docker-compose.dev.yml up -d --build # View logs (including Vite output) docker compose -f docker-compose.dev.yml logs -f ``` The app is available at `http://localhost:8000` with Vite HMR on port `5173`. ## Installation — Production ### Docker (recommended) ```bash mkdir sealshare && cd sealshare curl -O https://gitea.nonameweb.ch/noNameWEB/SealShare/raw/branch/main/docker-compose.example.yml cp docker-compose.example.yml docker-compose.yml # Generate an app key and paste it into docker-compose.yml docker run --rm gitea.nonameweb.ch/nonameweb/sealshare:latest php artisan key:generate --show # Edit docker-compose.yml — set APP_KEY, APP_URL, and SERVER_NAME # Then start: docker compose up -d ``` Migrations run automatically on startup. Open your configured domain — the Setup Wizard will create the first admin account. **Key environment variables:** | Variable | Required | Description | |----------|----------|-------------| | `APP_KEY` | Yes | Laravel encryption key | | `APP_URL` | Yes | Full URL (e.g. `https://share.example.com`) | | `SERVER_NAME` | Yes | Domain for auto-TLS (e.g. `share.example.com`) | **Volumes:** | Volume | Path | Purpose | |--------|------|---------| | `sealshare_storage` | `/app/storage/app` | Encrypted uploaded files | | `sealshare_database` | `/app/database` | SQLite database | | `caddy_data` | `/data` | TLS certificates | | `caddy_config` | `/config` | Caddy configuration | **Large files:** Uploads beyond the defaults need these limits raised together: | Limit | Where | Default | |-------|-------|---------| | `PHP_UPLOAD_MAX_FILESIZE` / `PHP_POST_MAX_SIZE` | Environment | `4G` — hard cap per file / per upload batch | | Max file size / Max size per share | Admin → Settings | 100 MB / 2 GB | | `LIVEWIRE_MAX_UPLOAD_TIME` | Environment | 30 minutes per upload | | `OCTANE_MAX_EXECUTION_TIME` / `PHP_MAX_EXECUTION_TIME` | Environment | 300 seconds — encrypting a large file takes a while | Behind a reverse proxy, raise its request body limit and read timeout as well (nginx: `client_max_body_size`, `proxy_read_timeout`). ### Manual (without Docker) ```bash git clone https://gitea.nonameweb.ch/noNameWEB/SealShare.git cd SealShare composer install --no-dev --optimize-autoloader npm install && npm run build cp .env.example .env php artisan key:generate # Edit .env — set APP_ENV=production, APP_DEBUG=false, APP_URL=https://your-domain.com touch database/database.sqlite php artisan migrate --force php artisan storage:link php artisan config:cache php artisan route:cache php artisan view:cache ``` Start with Octane: ```bash php artisan octane:frankenphp --host=0.0.0.0 --port=80 ``` Or point your web server (Nginx/Apache) to the `public/` directory for a traditional PHP-FPM setup. Add the scheduler to your crontab: ```bash * * * * * cd /path-to-sealshare && php artisan schedule:run >> /dev/null 2>&1 ``` ## License This project is open-source software licensed under the [MIT License](LICENSE).