Localsendy is a Docker-first LocalSend node with a responsive web interface. The Rust service handles LocalSend v2 discovery, encrypted receiving, transfer approval, sending, and storage; the browser remains a small control surface for any device on your LAN.
- LocalSend v2 HTTPS receiver and sender built on LocalSend's official Rust core
- Automatic multi-interface IPv4/IPv6 UDP multicast discovery with optional advanced filtering
- Automatic Ethernet-over-Wi-Fi preference when both adapters reach the same network, with runtime failover
- Multi-file and clipboard-text sending to one or many LocalSend devices
- Official-style link sharing with approval, automatic acceptance, optional PIN protection, QR codes, and repeatable browser downloads
- Explicit accept/decline flow or automatic acceptance configurable from the Settings > Environment variables panel
- Live send/receive byte progress plus persistent outgoing and receive history
- Responsive Send / Receive / Settings navigation based on the official LocalSend information architecture
- English, Simplified Chinese, and Traditional Chinese UI foundations
- Persistent official-style localized random device names with configurable prefix, type, and model
- Light, dark, and system themes with reduced-motion and keyboard support
- Non-root multi-stage Docker image and GHCR publishing workflow
Linux host networking is recommended because LocalSend discovery uses multicast UDP.
docker compose up -dOpen http://<server-ip>:52222. Received files are written to ./data/downloads.
To share selected files with a browser, choose Share via link on the Send screen. Localsendy defaults to the current browser domain, which keeps reverse-proxy and LazyCat domains intact. Enable LAN address only when recipients should connect directly, then select one interface to generate http://<interface-ip>:52222/share. No additional HTTP port is required.
Link sharing follows LocalSend's single-session model: one file batch is active at a time, starting another share replaces it, and accepted browsers may download its files repeatedly while it remains active. Leaving or stopping the share invalidates the link and removes its staged files. Each browser address can be approved or declined, or requests can be accepted automatically; an optional PIN can be embedded in the QR code.
The web control API is intentionally unauthenticated, so expose port 52222 only on a trusted LAN. Do not publish it directly to the Internet; bind it to loopback or protect it with your network controls when the host is on an untrusted network. This boundary also applies to /share: use approval or a PIN when link access should be restricted. When auto-accept is enabled, any device that can reach the relevant receiver or active share can transfer files without an approval prompt, subject to the configured upload limit.
The first start creates a persistent official-style random identity in /data/device-identity.json. To use a fixed name instead:
LOCALSENDY_ALIAS="Home NAS" docker compose up -dDocker Desktop host networking support varies by version and platform. On Linux,
network_mode: hostgives the most reliable discovery and inbound transfer behavior.
LocalSend multicast discovery stays inside the same broadcast domain. On routed or cross-subnet networks, use the manual IP probe in the Send screen or configure a multicast relay.
With Linux host networking, Localsendy automatically monitors every eligible host interface; there is nothing to select for normal use. Newly available Ethernet, Wi-Fi, bridge, VPN, and tunnel interfaces are detected at runtime. Advanced settings can restrict discovery to specific interfaces and attach human-readable labels. Discovery supports the LocalSend IPv4 group 224.0.0.167 and IPv6 group ff12::fd3a:e420, including ULA networks such as fc00::/7 when the network carries IPv6 multicast.
When Ethernet and Wi-Fi have the same non-link-local network prefix, automatic mode announces through Ethernet only. If Ethernet disappears, the five-second interface refresh activates Wi-Fi. Tunnels, Docker bridges, and virtual interfaces stay independent even when their prefixes overlap.
Network preferences and interface labels are saved to /data/network-settings.json. LOCALSENDY_NETWORK_INTERFACES is used as the initial fallback when no persisted settings exist.
| Variable | Default | Purpose |
|---|---|---|
LOCALSENDY_BIND |
0.0.0.0:52222 |
Web UI and control API bind address |
LOCALSENDY_ALIAS |
unset | Fixed device name; overrides generated names and prefixes |
LOCALSENDY_ALIAS_PREFIX |
unset | Prefix added to the generated localized name |
LOCALSENDY_ALIAS_LOCALE |
auto |
Generated-name locale: auto, en, zh-CN, or zh-TW; auto follows LC_ALL/LANG |
LOCALSENDY_DEVICE_TYPE |
server |
Standard LocalSend type: mobile, desktop, web, headless, or server |
LOCALSENDY_DEVICE_MODEL |
detected OS | Arbitrary display model shown to peers, such as Linux, Windows, or a product name |
LOCALSENDY_PORT |
53317 |
LocalSend HTTPS and discovery port |
LOCALSENDY_DATA_DIR |
/data |
Persistent storage root |
LOCALSENDY_DOWNLOAD_DIR |
/data/downloads |
Initial directory-selection scope for a new instance; the directory selected in the UI is persisted and restored first |
LOCALSENDY_TEMP_DIR |
/data/tmp |
Temporary workspace for runtime data |
LOCALSENDY_AUTO_ACCEPT |
false |
Startup default for accepting incoming transfers automatically; the Settings panel can override it and persist the choice |
LOCALSENDY_DISCOVERY_INTERVAL_SECONDS |
30 |
Presence announcement interval, minimum 5 seconds |
LOCALSENDY_NETWORK_INTERFACES |
all |
Initial fallback: all, *, or a comma-separated interface list; persisted UI settings take precedence |
LOCALSENDY_MAX_UPLOAD_BYTES |
10737418240 |
Maximum total size of one browser send request |
RUST_LOG |
localsendy=info,tower_http=info |
Rust tracing filter |
The Settings UI persists automatic acceptance, the LocalSend display name, the random-name language, and the selected receive directory in /data/localsendy.sqlite3. These UI values override the corresponding environment defaults and apply immediately. LOCALSENDY_DOWNLOAD_DIR initializes the directory-selection scope only when the instance is first created; later environment changes do not replace the persisted scope or selected directory. Device type, device model, and port remain startup identity values; change their environment variables and restart the container to apply them.
Localsendy exposes only settings that the current service can enforce. Automatic acceptance, the LocalSend display name, the random-name language, the save directory, and link-share access controls are supported. Favorite-device trust rules and configurable multicast groups are not implemented by the current service and are intentionally not shown as working controls.
Requirements: Rust 1.97+, Node.js 24+, npm 12+.
npm --prefix web ci
npm --prefix web run devIn another terminal, build the frontend once and start Rust:
npm --prefix web run build
cargo runVite proxies /api to 127.0.0.1:52222 during development.
npm --prefix web run typecheck
npm --prefix web run test:ci
npm --prefix web run build
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
docker build -t localsendy:dev .Browser (React/Vite)
│ /api/v1 and /share
▼
Localsendy (Axum, :52222)
├── multicast discovery (UDP :53317)
├── LocalSend HTTPS receiver (TCP :53317)
├── LocalSend client for outgoing transfers
└── /data/downloads + /data/tmp
See docs/architecture.md and the persisted design system.
- Saved manual targets for networks where multicast is unavailable
- Transfer cancellation
- History retention controls
- Additional official LocalSend locale coverage
The product flow and interoperability target are informed by the official LocalSend project. Localsendy is an independent project and is not affiliated with or endorsed by LocalSend.
The protocol implementation is vendored from LocalSend's MIT-licensed official Rust core. Upstream revision details are recorded in third_party/localsend-core/UPSTREAM.md.
MIT