π ndrop is a self-hosted data transfer utility for text, files, and folders, built in Go.
It uses a self-hosted HTTP server accessible locally or remotely, with end-to-end encryption so the server stores only ciphertext.
Similar in spirit to AirDrop-style sharing, but uses HTTP and E2E encryption instead of OS-specific peer-to-peer discovery.
- Run
ndropdon your laptop for local quick transfers. - Deploy
ndropdon a VPS or remote machine for internet-based drops. - Use
ndropfrom any network-capable client to push/pull text, files, and folders over HTTPS.
- π End-to-end encrypted content transfer
- π€ Push text, files, folders, or clipboard contents from the CLI
- π₯ Pull shared content to stdout, system clipboard, saved file, or extracted folder
- π§© API-key-based isolation per shared buffer
- βοΈ Configurable with TOML, CLI flags, and environment variables
- π₯οΈ
ndropdCLI withinit,start,stop, andhelp
./ndrop initThis creates ~/.config/ndrop/ndrop.toml with:
[server]
url = "http://localhost:8080"
api_key = "your-api-key"
timeout_seconds = 120
[pull]
default_save_dir = "~/Downloads"./ndropd initThis creates ~/.config/ndrop/ndropd.toml with:
port = "8080"
max_size_mb = 10
ttl_hours = 1
allow_any_api_key = true
allowed_api_keys = []./ndropd start# Push inline text
./ndrop push "Hello World!"
# Push a file
./ndrop push ./archive.tar.gz
# Push a folder
./ndrop push ./my-folder
# Push clipboard contents
./ndrop push --clipboard
# Push command output
./ndrop push -c "date"
# Pull text to stdout (default)
./ndrop pull
# Pull text to system clipboard
./ndrop pull --clipboard
# Pull a file or folder to a directory
./ndrop pull --save ./downloads/
# Pull raw bytes to stdout
./ndrop pull --stdoutndrop initβ create default client configndrop push [text|file|folder]β push text, a file, or a folderndrop pullβ pull the latest entry
--clipboardβ push text from the system clipboard-c, --cmd <command>β execute a command and push its output
--clipboardβ write text to the system clipboard--save <dir>β save a file or extract a folder to a directory--stdoutβ write raw bytes to stdout
ndropd initβ create server configndropd startβ run server in the foregroundndropd stopβ stop the running serverndropd helpβ show help
ndropd serves an embedded web UI at /.
Open the server URL in a browser, enter the same API key used by the CLI, and use the page to:
- pull and decrypt the latest text, file, or folder transfer locally in the browser
- copy pulled text to the system clipboard
- download pulled files and folders; folders are downloaded as zip files
- push text or a file
The web UI uses the browser WebCrypto API for AES-GCM encryption and decryption, so the server still stores only ciphertext. WebCrypto requires a secure browser context: use https:// for remote deployments or http://localhost for local testing.
ndrop uses the configured API key for two separate purposes:
- It derives a stable
bucket_id, which selects the shared buffer on the server. - It derives an AES-256-GCM encryption key, which encrypts and decrypts the payload.
When you run ndrop push, the client encrypts the text, file, or zipped folder before uploading it. The server stores only:
- the derived
bucket_id - encrypted
data - the
nonceneeded to decrypt that encrypted payload - metadata such as device name, MIME type, and payload name
The nonce is a random 12-byte value generated for every push. It is not secret, but it must be unique for each encryption with the same API key. The pull client receives data and nonce, then decrypts locally using the same API key.
The raw API key is sent to the server in the Authorization: Bearer <api-key> header so the server can route the request and optionally enforce allowed_api_keys. The server does not store the raw API key, but deployments should still use HTTPS when the server is accessed over a network.
File: ~/.config/ndrop/ndrop.toml
[server]
url = "http://localhost:8080"
api_key = "my-secret-api-key"
# Client-side HTTP request timeout in seconds (0 uses default 120s)
timeout_seconds = 120
[pull]
default_save_dir = "~/Downloads"File: ~/.config/ndrop/ndropd.toml
port = "8080"
max_size_mb = 10
ttl_hours = 1
allow_any_api_key = true
allowed_api_keys = []Set allow_any_api_key = false and list accepted keys to reject unknown clients:
allow_any_api_key = false
allowed_api_keys = ["laptop-key", "phone-key"]Client config can be overridden with:
NDROP_URLNDROP_API_KEY
Server config can be overridden with:
PORTMAX_SIZE_MBTTL_HOURSALLOW_ANY_API_KEYALLOWED_API_KEYS
When exposing ndropd to the internet, it is strongly recommended to run it behind a reverse proxy like Nginx with SSL termination.
Because ndrop processes large files via memory/Base64, streaming raw data instantly without proxy buffering is critical to prevent timeouts and connection drops.
Add the following configuration inside your Nginx server block (handling port 443 with SSL):
location / {
proxy_pass http://localhost:8080; # or your docker container name
# 1. Disable all buffering for instant streaming of large payloads
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 0; # Disables Nginx upload size limits
# 2. Extend timeouts to handle large multi-megabyte transfers over slow networks
proxy_connect_timeout 3600s;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
send_timeout 3600s; # Crucial: prevents Nginx from cutting off slow pull streams
# 3. Standard headers for proxying
proxy_set_header Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}A Docker Compose setup is included under docker/docker-compose.yml.
Use docker/Dockerfile to build the image and docker/build.sh to run the workflow.
From the repository root:
./docker/build.sh buildThis builds the ndropd image only.
./docker/build.sh upThis rebuilds the image and starts the ndropd service in detached mode.
The compose service publishes port 8080 and sets:
PORT=8080MAX_SIZE_MB=10TTL_HOURS=1ALLOW_ANY_API_KEY=true
A sample systemd unit is available at deploy/systemd/ndropd.service.
It assumes:
ndropdis installed at/usr/local/bin/ndropd- a dedicated Linux user and group named
ndropexist - server state is stored under
/var/lib/ndrop
Example setup:
sudo useradd --system --home-dir /var/lib/ndrop --create-home --shell /usr/sbin/nologin ndrop
sudo install -m 0755 ndropd /usr/local/bin/ndropd
sudo install -m 0644 deploy/systemd/ndropd.service /etc/systemd/system/ndropd.service
sudo systemctl daemon-reload
sudo systemctl enable --now ndropdBefore starting the service on a public host, edit /etc/systemd/system/ndropd.service and replace:
Environment=ALLOWED_API_KEYS=change-meFor multiple API keys, use a comma-separated value:
Environment=ALLOWED_API_KEYS=laptop-key,phone-keyThe canonical project version is defined in internal/version/version.go.
Plain go build, Docker builds, and Make-based release builds use that value.
Update it there before cutting a new release.
Both binaries can print their version:
ndrop --version
ndropd --versiongo build -o ndrop ./cmd/ndrop
go build -o ndropd ./cmd/ndropdThe repository includes a Makefile with platform targets.
Built artifacts are packaged as ZIP archives in the build/ directory.
make linux-amd64
make windows-amd64
make darwin-amd64
make darwin-arm64To build all supported targets:
make releaseTo remove generated build artifacts:
make cleanSupported targets:
linux-amd64linux-armv5linux-armv6linux-armv7windows-amd64darwin-amd64darwin-arm64
Each target builds both ndrop and ndropd, then creates a zip package like:
build/ndrop-linux-amd64-1.1.0.zipbuild/ndrop-windows-amd64-1.1.0.zipbuild/ndrop-darwin-arm64-1.1.0.zip
MIT Β© 2026 Ruslan Huzii