LocalSend 完整教學

LocalSend 是一個用 Flutter(UI / 平台整合)+ Rust(core/ 網路核心) 寫的跨平台 P2P 檔案傳輸 app,主打「只用區網、不需網際網路、不需第三方伺服器」的 AirDrop 替代品。 8.2 萬星、Apache-2.0、官方 protocol 文件公開。

適合:分析師 / 開發者桌機 ↔ 手機 / NAS / 同事筆電 跨機搬資料,避開 USB、雲端、IM 訊息平台。 不適合:跨網際網路傳檔(沒有 relay server)、大量人對檔案做版本控管(不是 sync 工具)。


1. 專案定位

維度說明
屬性Flutter app(端到端產品)+ Rust core engine(可被其他語言綁定)
規模約 945 個原始檔,跨 app/(Flutter UI)、core/(Rust HTTP/TLS/WebRTC)、common/(Dart 共用 DTO/邏輯)、server/cli/ 五大模組
Protocol 版本目前 v2.1(app v1.18.0),相容 v1.0、v2.0
核心 abstraction「Device」: 一個 (alias, fingerprint, ip, port, version) 的本機可發現端點,所有 REST API 圍繞它設計
對齊的同類工具AirDrop(Apple)、Quick Share / Nearby Share(Android)、Snapdrop / PairDrop(web-only)
與 Snapdrop / PairDrop 差別LocalSend 是 native app(每個平台都打包),有 TLS + 公鑰固定,不只是 WebRTC + browser

2. 安裝指南(多平台)

LocalSend 強烈建議不要從 GitHub release 直接下載,而是用各平台原生套件管理器(這樣才能拿到更新)。

平台建議來源備選
Windowswinget install LocalSend.LocalSendScoop / Chocolatey / EXE installer / Portable ZIP
macOSApp Store(id1661733229)Homebrew (brew install --cask localsend) / DMG
LinuxFlathub (org.localsend.localsend_app)Snap / AUR / DEB / AppImage / TAR
AndroidPlay Store / F-DroidAPK 直裝
iOSApp Store(無 sideload 路徑)
Fire OSAmazon Appstore

最低版本需求:Android 5.0 / iOS 12 / macOS 11 Big Sur / Windows 10。

防火牆設定(最常見的「對方看不到我」原因):

TrafficProtocolPortAction
IncomingTCP + UDP53317Allow
OutgoingTCP + UDPAnyAllow

另外,Wi-Fi router 的 AP isolation 必須關閉(很多 guest network 預設打開)— 否則同網段的裝置之間互相看不到。

從原始碼編譯(給開發者):

 1# 1. 安裝 Flutter(用 fvm 鎖定版本,見 .fvmrc)
 2brew install fvm  # 或 https://fvm.app
 3fvm install        # 自動讀 .fvmrc
 4
 5# 2. 安裝 Rust
 6curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
 7
 8# 3. 取得 source
 9git clone https://github.com/localsend/localsend.git
10cd localsend/app
11
12# 4. 跑起來
13fvm flutter pub get
14fvm flutter run

注意:LocalSend 鎖 Flutter 版本(在 .fvmrc),系統全域 Flutter 版本不一定能編。fvm flutter 而不是 flutter

3. 核心架構解析

3.1 模組劃分

 1localsend/
 2├── app/          Flutter appUI、平台整合、native 呼叫)
 3   ├── lib/      Dart 業務邏輯(pages, provider, widget, util
 4   ├── android/ ios/ windows/ macos/ linux/ web/   平台 wrapper
 5   └── rust/     Rust core  flutter_rust_bridge binding 入口
 6├── core/         Rust 核心:HTTP server/clientTLSWebRTC signalingcrypto
 7   └── src/
 8       ├── http/       REST APIv1 / v2 dto+ rustls TLS
 9       ├── crypto/     cert generation / verifytokennoncehash
10       ├── webrtc/     WebRTC signalingv3 protocol,跨子網)
11       └── model/      Device / Transfer / Discovery 資料模型
12├── common/       Dart 共用 DTO / model / multicast discovery / API route
13   └── lib/
14       ├── model/dto/    request/response DTO(與 Rust core 對齊)
15       ├── api_route_builder.dart   REST path /api/localsend/{v1,v2}/{info,register,...}
16       └── constants.dart           protocol version, port, multicast group
17├── server/       headless server 模式(無 UI
18├── cli/          command line client
19└── submodules/   鎖定的 flutter SDK

3.2 P2P Discovery + Transfer 流程

LocalSend 的核心可拆成 3 個階段

階段 A:發現(Discovery)

  • 每個裝置啟動時,加入 UDP multicast group 224.0.0.167:53317(這個位址在 224.0.0.0/24 範圍,是某些 Android 唯一能收的 multicast 範圍)
  • 主動廣播自己的 MulticastDto(含 alias / fingerprint / port / protocol version)
  • 也監聽其他裝置的廣播 → 維護本機 device list
  • Fallback:若 multicast 被路由器擋掉,HTTP discovery(掃描子網 + GET /api/localsend/v2/info

階段 B:握手(Register / Prepare-Upload)

  • 發送方點選目標裝置 + 選好檔案 → POST /api/localsend/v2/prepare-upload
    • body 包含 device info + file metadata list + optional PIN
  • 接收方 UI 跳「對方要傳這些檔案,接受?」彈窗 → 使用者按下 → server 回傳 sessionId + fileId→token map

階段 C:實際傳輸

  • 對每個 fileId,發送方 POST /api/localsend/v2/upload?sessionId=...&fileId=...&token=...,body 是檔案 stream
  • 接收方寫入 download 目錄
  • 任一方可 POST /api/localsend/v2/cancel 終止

3.3 完整序列圖


sequenceDiagram
    autonumber
    participant A as Device A (sender)
    participant N as LAN multicast group
224.0.0.167:53317 participant B as Device B (receiver) Note over A,B: Phase A — Discovery (UDP multicast) A->>N: MulticastDto announce (alias, fp, port, v=2.1) B->>N: MulticastDto announce A->>B: (fallback) GET /api/localsend/v2/info B-->>A: InfoDto (alias, fingerprint, deviceType) Note over A,B: Phase B — Handshake (HTTPS REST) A->>B: POST /api/localsend/v2/prepare-upload
{info, files[]} Note right of B: UI 跳出「接受?」彈窗
可選 PIN 驗證 B-->>A: 200 OK {sessionId, files:{id→token}} Note over A,B: Phase C — Transfer (one POST per file) loop for each file A->>B: POST /upload?sessionId&fileId&token
(stream body) B-->>A: 200 OK end Note over A,B: Optional cancel A->>B: POST /cancel?sessionId

3.4 TLS / 加密設計(重點)

  • 每台裝置在第一次啟動時,本機產生 ECDSA self-signed 憑證core/src/crypto/cert.rs)— 私鑰存在本機加密 storage
  • HTTPS 流量用 rustls(不是 OpenSSL),server 與 client 都帶憑證
  • 不依賴 CA 信任鏈 — 因為是自簽,瀏覽器/系統信任無意義
  • 改用 public key pinning(公鑰固定)
    • 首次握手時,把對方的 cert public key 存進本機 device map
    • 之後每次連線都 verify「對方憑證的 public key 是否與第一次相同」
    • 若不同 → MITM 嫌疑,拒絕連線
  • 額外 fingerprint:device 用 cert 的 SHA-256 fingerprint 當 ID

4. 主要模組詳細用法

4.1 REST API 路由(common/lib/api_route_builder.dart)

Routev1 pathv2 path用途
info/api/localsend/v1/info/api/localsend/v2/info取得對方裝置資訊
register/api/localsend/v1/register/api/localsend/v2/registerHTTP discovery 註冊
prepareUpload/api/localsend/v1/send-request/api/localsend/v2/prepare-upload發起傳檔(v1 path 名不同)
upload/api/localsend/v1/send/api/localsend/v2/upload實際傳檔
cancel/api/localsend/v1/cancel/api/localsend/v2/cancel取消
show/api/localsend/v2/show顯示已收檔
prepareDownload/api/localsend/v2/prepare-download反向:對方來拿檔
download/api/localsend/v2/download反向下載

v2 多了 show / prepare-download / download 三個 endpoint,支援「Share via link」反向模式。

4.2 Multicast Discovery(common/lib/src/task/discovery/multicast_discovery.dart)

  • 綁定 UDP 53317
  • 加入 multicast group 224.0.0.167
  • 監聽 + 解析 MulticastDto,更新 device list
  • sendAnnouncement() 主動播報,新進裝置會立刻發一次

4.3 Rust core HTTP server(core/src/http/server/mod.rs)

  • hyper + rustls + tokio
  • 同時綁 IPv4 0.0.0.0:53317 與 IPv6 [::]:53317
  • nonce-based replay 防護(received/generated nonce LRU cache,size=200)
  • 支援 legacy mode(向後相容 v1 client)

4.4 Flutter app(app/lib/)

子目錄角色
pages/UI 頁面(settings, tabs, troubleshoot, debug, about, donation)
provider/Riverpod state providers(network, selection, logging)
widget/共用元件
util/native/平台 native 呼叫(檔案儲存、剪貼簿、tray、autostart、process 呼叫)
rust/api/flutter_rust_bridge 自動產生的 Dart binding(呼叫 Rust core)

5. 應用場景

場景為什麼選 LocalSend
跨 OS 桌機 ↔ 手機搬檔沒 USB cable,AirDrop 只在 Apple 生態內;LocalSend 真跨平台
公司資料禁雲端外傳純 LAN、不上 internet、可關閉加密以追蹤封包(合規場景)
同事間快速共享 PDF / 圖不必 Slack / Teams 上傳大檔
NAS / Raspberry Pi 取/送檔cli/server/ 模式跑 headless
Demo 場合(簡報 / 投影片)比 USB 隨身碟快;現場觀眾掃 QR 加入 share via link
不適合的場景跨網際網路(沒 relay);做檔案同步(這是 syncthing 的範疇);做大規模分發(用 BT / IPFS)

6. 資安掃描報告

6.1 評估範圍

LocalSend 是 P2P 跨裝置檔案傳輸工具,其資安需求集中在 (1) 網路通訊機密性、(2) 對方身份驗證、(3) 接收端授權、(4) 檔案系統權限邊界、(5) 平台原生 API 呼叫

6.2 風險逐項評估

維度等級說明
TLS 加密強度🟢 低rustls + ECDSA 自簽憑證 + 公鑰固定(pinning)。設計符合教科書 P2P 標準;可被使用者手動關閉加密(明文 HTTP)以利除錯,這在公開網段需謹慎
身份驗證(peer auth)🟢 低用 cert public key fingerprint 當 ID;首次連線即綁定(TOFU 模型)。MITM 在「首次握手」窗口仍有理論風險
接收端授權🟢 低所有 prepare-upload 都會跳 UI 彈窗讓使用者點「接受」;可設 PIN 強制驗證;不存在「靜默接收」模式
Replay 防護🟢 低nonce LRU map(received + generated),size=200
網路綁定範圍🟡 中同時 listen 0.0.0.0:53317 + [::]:53317;多網卡裝置(VPN / docker bridge)可能讓 LocalSend 暴露於非預期介面。提供 networkWhitelist / networkBlacklist 設定可緩解
Multicast discovery 隱私🟡 中在 LAN 內任何人都能看到 MulticastDto(alias、device type、fingerprint),等同公開廣播身份。在公共 Wi-Fi(咖啡店)建議關掉發現功能或改用 share-via-link
檔案系統權限🟡 中Android READ/WRITE_EXTERNAL_STORAGEREQUEST_INSTALL_PACKAGESQUERY_ALL_PACKAGES 等敏感權限;iOS NSLocalNetworkUsageDescriptionREQUEST_INSTALL_PACKAGES 在 Android 上意味可裝 APK — 接收 APK 時應確認來源
Process.run 呼叫🟡 中app/lib/util/native/cmd_helper.dart 呼叫 powershell 處理 Windows 整合;troubleshoot_page.dartrunInShell: true 跑診斷指令。已檢視:參數陣列化、無 user input concat,shell injection 風險低
檔案刪除🟢 低僅刪除自家目錄下檔案(autostart config、temp);無任意路徑 delete
密鑰儲存🟢 低私鑰由本機儲存(Dart StoredSecurityContext model),未發現上傳行為
依賴鏈🟢 低Apache-2.0,主要依賴:flutter、rustls、hyper、tokio、x509-parser。皆主流維護中
自動更新🟡 中官方明說「app 沒有 auto-update」,必須走 store / package manager。長期不更新的使用者會錯過安全修補

6.3 綜合結論

🟢 整體資安等級:低風險,可安心於受信任 LAN 使用。

關鍵設計亮點:

  • ✅ rustls + 自簽 ECDSA + key pinning:教科書級 P2P 加密
  • ✅ 所有接收都需明確使用者授權;無靜默後門
  • ✅ nonce + LRU 防 replay
  • ✅ 開源 + Apache-2.0 + 公開 protocol 文件可審計

需要注意:

  • ⚠️ 公共 Wi-Fi 場景:multicast announce 暴露 device fingerprint,建議關閉發現
  • ⚠️ REQUEST_INSTALL_PACKAGES 權限:收到 APK 時切勿無腦接受
  • ⚠️ Android QUERY_ALL_PACKAGES:Play Store 政策敏感權限,使用者應確認用途(多半是 share intent 整合用)
  • ⚠️ 多網卡裝置:用 networkWhitelist 鎖介面,避免從 VPN / docker 暴露

7. FAQ

Q: 為什麼對方看不到我? A: 三大原因。(1) 防火牆擋 UDP/TCP 53317;(2) Wi-Fi router 開了 AP isolation;(3) Windows 網路設定為「公用」(私人比較寬鬆)。macOS / iOS 還要去設定 → 隱私 → 本機網路打勾。

Q: 為什麼速度很慢? A: 用 5 GHz Wi-Fi;雙方都關掉加密(會用明文 HTTP,僅在信任的 LAN 用);Android 接收端有已知 SAF stream 慢的 issue。

Q: 可以跨網際網路用嗎? A: 不能直接用 — LocalSend 不跑 relay server。可以用:(1) Tailscale / ZeroTier 把兩端拉進同一 virtual LAN;(2) v3 protocol 提供的 WebRTC signaling 模式(experimental,core/src/webrtc/)。

Q: 自簽憑證安全嗎? A: 安全 — 因為配 key pinning。第一次連線後,對方的 public key 就被綁住,往後 MITM 會被偵測。風險只在「第一次握手的瞬間」,這是 TOFU(trust on first use)模型的本質限制。

Q: 為什麼有 Rust core?Flutter 不夠嗎? A: 近期路線(2026-03 commits)是把 HTTP client/server 從 Dart 遷到 Rust,原因:(1) 跨平台統一行為;(2) rustls 比 Dart 內建 TLS 更可控;(3) 效能(特別是大檔 streaming)。

Q: Web 端能用嗎? A: 有 app/web/,但 browser 無法綁 53317 port、無法 multicast,所以 web 端只能當 client 連到別人的 LocalSend(透過 share-via-link),不能當 server。

8. 進階技巧

8.1 Portable mode(攜帶式)

在執行檔同目錄建一個空的 settings.json → app 會把設定存到這檔,而不是 OS 預設位置。適合放隨身碟、跨機共用設定。

8.2 Hidden startup(背景啟動)

1localsend_app.exe --hidden

只在 system tray,無視窗 — 適合掛機當「接收伺服器」。

8.3 CLI 模式

cli/ 目錄有純命令列版本:

1dart pub get
2dart run cli/bin/cli.dart   # 細節參考 cli/README.md

8.4 鎖定網路介面

在 settings 把 networkWhitelist 設成你的實體 Wi-Fi/eth IP 範圍,避免 LocalSend 從 VPN / docker bridge 介面暴露。

v2 protocol 加的 show / prepare-download / download 三個 endpoint:發送方產 link,接收方在瀏覽器打開該 link 從發送方拉檔。對「web only」對方裝置很實用。

9. 整合進其他工作流

場景怎麼做
AI Knowledge Template 跨機同步 inbox/在 NAS 跑 server/ headless mode;本機跑 client,自動接收 daily fetch 後的 markdown
分析師 mobile ↔ workstation 互傳mobile 拍照 / 截圖 → LocalSend 一鍵推到 workstation 的 inbox/Image/
demo 影片 / paper PDF 投影現場分發開啟 share-via-link,投影 QR code,現場觀眾掃碼下載
避免 Slack / Teams 大檔上傳公司內部資料只走 LAN,不過外部 SaaS
替代 SFTP / SCP 的輕量方案不必開 ssh、不必管 key 分發,UI 點兩下就好

10. Checklist(自評清單)

  • 已用 store / package manager 安裝(非裸 release)
  • 防火牆放行 TCP+UDP 53317
  • Wi-Fi router 關閉 AP isolation
  • Windows 將網路設為「私人」
  • macOS / iOS 設定 → 隱私 → 本機網路打勾
  • 設好 device alias(不要用預設 hostname,避免洩漏)
  • 開啟 PIN(強化首次握手安全)
  • 公共 Wi-Fi 場景:關閉「自動發現」或改用 share-via-link
  • 多網卡裝置:設好 networkWhitelist
  • 確認接收的不是來路不明的 APK
  • 定期手動更新(沒有 auto-update)

11. 進一步閱讀

  • 官方協定文件:https://github.com/localsend/protocol — 對協定設計感興趣的必讀
  • README:本 repo 根目錄(多語版本在 readme_i18n/
  • CONTRIBUTING:https://github.com/localsend/localsend/blob/main/CONTRIBUTING.md
  • 入口檔速查:
    • common/lib/constants.dart — protocol version / port / multicast group
    • common/lib/api_route_builder.dart — REST 路由 v1/v2 對照
    • core/src/http/server/mod.rs — Rust HTTP server + TLS 主入口
    • core/src/crypto/cert.rs — 憑證生成 / 驗證 / 公鑰比對
    • core/src/model/discovery.rs — DeviceType enum
    • app/lib/util/native/ — 各平台原生整合
    • app/android/app/src/main/AndroidManifest.xml — Android 權限清單

教學完成度說明:本教學以協定 + 資安為主軸,UI / 翻譯 / store 上架等與「資料工程師如何使用 LocalSend」較無關的細節從略。若需深入 Flutter UI 實作,建議直接讀 app/lib/pages/app/lib/widget/;若需深入 Rust core,從 core/src/http/server/mod.rscore/src/crypto/ 開始最快。