Noureddine RAMDI / SkySend: zero-knowledge, end-to-end encrypted self-hosted file sharing with streaming AES-256-GCM

Created Sat, 23 May 2026 20:41:14 +0000 Modified Sat, 23 May 2026 20:41:27 +0000

Skyfay/SkySend

SkySend addresses a common pain point in self-hosted file sharing: how to truly keep your data private even from the server operator. It achieves this by implementing end-to-end encryption where the decryption key never leaves the client — it only lives in the URL fragment after upload. The server stores only ciphertext, never plaintext or keys, offering a genuine zero-knowledge architecture. This is increasingly rare in open source projects that claim encryption but often handle keys on the server side.

What SkySend provides and how it works

SkySend is a full-stack, self-hosted file and note sharing system built with TypeScript. The backend uses Node.js with the Hono framework, while the frontend is a React application bootstrapped with Vite. It implements AES-256-GCM streaming encryption, meaning large files can be encrypted and decrypted on the fly without loading everything into memory.

Key derivation uses HKDF with SHA-256, and all cryptographic operations occur client-side, using Web Crypto APIs and WASM Argon2id for password hashing. The decryption key lives only in the URL fragment (the part after # in a URL), so it is never transmitted to or stored on the server.

This design means the server acts as a dumb storage and relay layer, unaware of the file contents. Uploads can be gated by optional OIDC/SSO authentication, and files are stored on either local disk or any S3-compatible backend, making the storage layer pluggable.

The project includes a full CLI client compiled with Bun that mirrors the browser’s encryption pipeline exactly. This lets users upload and download encrypted files from the terminal with the same zero-knowledge guarantee. An admin CLI is also provided for server management tasks.

Deployment is simplified into a single Docker container image supporting multi-architecture (AMD64 and ARM64), easing installation on diverse server hardware.

Technical strengths and design tradeoffs

The standout feature is the zero-knowledge encryption model: the server never sees plaintext or keys. This is achieved by storing the decryption key solely in the URL fragment, which browsers do not send to servers in HTTP requests. The encryption uses AES-256-GCM in streaming mode, allowing efficient processing of large files without loading them entirely into memory.

Implementing HKDF-SHA256 key derivation and Argon2id password hashing client-side strengthens security against brute force. The encryption pipeline’s implementation in both browser and CLI clients ensures consistent security regardless of access method.

The codebase is intentionally minimal and maintainable, inspired by earlier projects like Mozilla Send and PrivateBin but rewritten from scratch with modern security practices and TypeScript’s type safety.

The tradeoff with this approach lies in usability: since the server does not see keys, it cannot assist with password recovery or enable server-side search or virus scanning. Users must securely store the URL containing the key fragment.

Another limitation is that the server must be trusted to not serve modified ciphertext maliciously, although the cryptographic design includes integrity checks via AES-GCM.

The optional OIDC/SSO integration allows deployment in environments requiring authenticated upload gating, improving control without compromising the zero-knowledge core.

On the deployment side, packaging everything as a single Docker container with multi-arch images and health checks simplifies operational burden. It supports configurable UID/GID for volume permissions and handles graceful shutdown signals, important for containerized environments.

Quick start

SkySend can be deployed rapidly using Docker Compose with the following configuration:

# docker-compose.yml
services:
  skysend:
    image: skyfay/skysend:latest
    container_name: skysend
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - ./data:/data
      - ./uploads:/uploads
    environment:
      - BASE_URL=http://localhost:3000
      # All environment variables: https://docs.skysend.app/user-guide/configuration/environment-variables
      # There are a lot of customization options available, so make sure to check the documentation for more details.

Run the stack in detached mode:

docker compose up -d

After starting, you can access the web interface at http://localhost:3000.

For command-line interactions, the official CLI client installs easily on Linux/macOS and Windows:

curl -fsSL https://skysend.app/install.sh | sh
irm https://skysend.app/install.ps1 | iex

The CLI supports uploading and downloading files with the same end-to-end encryption guarantees as the web client.

verdict

SkySend is a solid choice if you need a self-hosted file sharing solution with genuine zero-knowledge encryption. It’s particularly suited for users and organizations that want to eliminate any risk of server-side data exposure and are comfortable managing encryption keys solely client-side.

The codebase is compact and understandable, making it auditable and adaptable, which is important for security-critical applications. Support for OIDC/SSO and S3-compatible storage adds enterprise-friendly flexibility.

The main limitations stem from the zero-knowledge approach: no server-side key recovery, no plaintext indexing, and reliance on users securely sharing URLs containing decryption keys. These are common tradeoffs in end-to-end encrypted systems.

If your use case demands strong privacy guarantees without trusting the server, and you can handle client-side key management, SkySend is worth exploring. For less security-sensitive scenarios or where server-assisted features are needed, other solutions might be more appropriate.


→ GitHub Repo: Skyfay/SkySend ⭐ 192 · TypeScript