自架位置追蹤 App 怎麼選?Traccar、OwnTracks、Dawarich 比較
比較 Traccar、OwnTracks、Dawarich 與 Home Assistant,依位置歷史、即時地圖或自動化需求選擇,並將 ingest endpoint 留在公開網際網路之外。
適合你情境的自架位置追蹤應用程式
自架位置追蹤取決於一個問題:你要保留自己的位置歷史,還是要和其他人一起查看即時位置?Dawarich 適合前者。它是 Google Maps Timeline 的自架替代方案,也能匯入你現有的位置歷史。Traccar 適合後者。它是為 GPS 硬體與車隊打造,並將手機視為另一個追蹤器。OwnTracks 則位於兩者底層,作為手機應用程式與訊息格式使用。如果你有執行 Home Assistant,它已經知道手機的位置,但預設會在十天後刪除位置軌跡。
請依照你下個月想查看的內容選擇:
- 上個 3 月去過的所有地方、地點與行程地圖:Dawarich。
- 多台裝置的即時地圖、地理圍籬與事件規則:Traccar。
- 讓一支手機將位置傳送到你已在執行的系統:使用 HTTP mode 的 OwnTracks。
- 居家與離家自動化,不需要位置歷史:單獨使用 Home Assistant。
在手機能連線到你控制的 HTTPS endpoint 之前,這些方案都無法運作,因此下方會另設一節說明伺服器端。如果你還在整理這台伺服器上應該部署哪些服務,今年值得自架的服務完整清單能說明追蹤器在整體服務中的位置。
Traccar:GPS 硬體、車隊與即時位置
Traccar 是追蹤伺服器。它支援專用 GPS 追蹤器使用的通訊協定,每個協定使用自己的連接埠。目前的協定清單使用 5001 到 5266 的連接埠;Traccar 的 Docker 說明則會針對 TCP 與 UDP 發布完整的 5000 到 5300 範圍。此外,它提供即時地圖、地理圍籬、事件規則與報表。Web 介面預設監聽 8082 埠。
手機可使用 Android 與 iOS 的 Traccar Client 應用程式。它透過 OsmAnd 協定回報位置,該協定預設監聽 5055 埠。應用程式設定會影響電池續航力與位置回報筆數。Distance 會在移動時每隔 N 公尺要求更新。Interval 會在距離為 0 時,依時間間隔回報。Angle 會在行進方向變更指定角度時觸發更新,單位為度。Stationary Heartbeat 控制裝置停止移動時的行為。Traccar 官方文件指出,這些設定的實際結果都無法保證,因為回報時機由手機決定。
Traccar 內建 H2 資料庫,讓安裝程式無須額外設定即可運作,但專案不建議在正式環境使用 H2。文件說明可改用 MySQL、MariaDB 與 PostgreSQL,並建議大型部署使用 TimescaleDB;TimescaleDB 是建置在 PostgreSQL 上的時間序列資料庫。請在累積歷史資料前搬移資料庫,因為之後轉換 H2 檔案必須手動處理,而且沒有受支援的工具。
Traccar 不適合的情境:它是用來即時查看追蹤物件的主控台。報表內容是車隊報表、行程、停留與摘要,因此,若要查看自己一整年的週末活動,結果會比較像查詢結果,而不是時間軸。
OwnTracks:手機應用程式與端點,僅此而已
OwnTracks 是最精簡的經典設定。應用程式在判定裝置已移動時,會發布一小段 JSON payload;它可以透過 MQTT(message queuing telemetry transport)或一般 HTTP 發布。在 HTTP 模式中,端點是格式為 http[s]://[user[:password]@]host[:port]/path 的 URL,並使用 HTTP Basic 驗證;該專案強烈建議使用 https:// scheme。對 OwnTracks Recorder 而言,路徑是 /pub。
監測模式比任何伺服器設定都重要。Quiet 只會在你要求時發布。Manual 會加入區域監測與低耗電定位要求。Significant 是一般的自動模式。在 iOS 上,Move 會在裝置移動 locatorDisplacement 公尺或經過 locatorInterval 秒時發布,兩者以先發生者為準;預設值分別為 100 公尺與 300 秒。在 Android 上,Move 預設每 10 秒要求一次定位。OwnTracks 文件指出,Move 模式的耗電量與導航應用程式相當,建議在旅途中或充電時使用,而不要作為日常設定。
OwnTracks Recorder 會儲存收到的資料,並提供簡易地圖。許多人完全不安裝它,因為無論應用程式指向 Recorder、Dawarich 或 Home Assistant,payload 都完全相同。這就是從這裡開始的原因:應用程式是穩定且單純的資料產生端,之後仍可改用其他資料消費端。
Dawarich:自架的 Google Maps Timeline
Dawarich 採用 AGPL-3.0 授權,並透過 Docker Compose 檔案執行。可正常運作的安裝包含 4 個容器:Rails 應用程式、處理背景工作的 Sidekiq worker、PostgreSQL,以及 Redis。應用程式提供 3000 埠。可匯入的來源包括 Google Maps Timeline、OwnTracks、Strava、Immich、GPX 與 GeoJSON 檔案,以及相片中的 EXIF 資料。這份匯入來源清單使它成為時間軸,而不只是即時地圖,因為它能納入早於伺服器建置時間的歷史資料。
資料匯入使用攜帶帳戶頁面所提供 API key 的 HTTP endpoint。OwnTracks 會將資料 POST 至 /api/v1/owntracks/points?api_key=...,Overland 則會 POST 至 /api/v1/overland/batches?api_key=...。GPSLogger 會重用 OwnTracks endpoint。
請注意該 key 的傳遞位置。它位於 query string 中,而 nginx 的預設日誌格式會寫入完整的 request line,因此每一筆位置資料都會讓該 key 以明文寫入 /var/log/nginx/access.log。請將此日誌視為 secret。若將日誌傳送到任何集中式系統,請先輪替該 key。切勿將可正常使用的 URL 貼到支援討論串中。
至於 compose 檔案本身、volumes 與 restart policy,請參閱在 VPS 上執行 compose 的容器機制。本頁內容到此僅提供判斷依據。
Home Assistant:適合目前位置,不適合歷史記錄
如果你已經在執行 Home Assistant,就已經具備裝置追蹤功能。Companion app 會回報位置,而 OwnTracks integration 會提供 webhook URL 與加密金鑰,供你貼到應用程式中。設定 MQTT 後,該 integration 會改為接收 MQTT 訊息,而不是 HTTP。
限制在於保留期限。Home Assistant 的 recorder 預設為 purge_keep_days: 10,而自動清除功能每天在當地時間 04:12 執行,以避免資料庫無限制增長。這項預設值適合家庭自動化資料庫,但不適合位置封存。Home Assistant 能回答「目前有人在家嗎?」但無法回答「我在 14 March 的哪裡?」除非你將同一串資料傳送到能夠保留資料的其他系統。
持續追蹤或偶爾分享?
持續追蹤表示應用程式全天發布位置,不論你是否正在移動,而它建立的歷史紀錄就是主要用途。偶爾分享表示人們在旅途中互相查看位置,而歷史紀錄只是沒有人要求的副作用。同一套軟體可支援這兩種用途,但設定方式不同。
若要持續追蹤,應優先使用位移觸發的回報方式,而不是短時間計時器。資料庫應放在確實會備份的儲存空間。保留期限應在第一天決定,而不是等磁碟空間用滿時才處理。若要偶爾分享,只在需要時提高回報頻率,之後再將手機切回低耗電模式。OwnTracks 可在應用程式中直接控制這些設定,Traccar Client 則透過距離與間隔欄位提供相同功能。
若你要的是單次旅程使用 2 小時的分享連結,選定伺服器前應先查看其 release notes。這項功能在不同版本之間的變化最大,也是這裡所有選項中最薄弱的部分。
是否真的需要 MQTT broker?
先不要使用 broker。HTTP mode 只需要 URL、密碼與 TLS(傳輸層安全性),上述每台伺服器都接受這種模式。當同一個資料流需要在同一時間供多個元件使用時,broker 才值得加入。例如 Home Assistant 可在錄影器寫入歷史資料的同時,對區域狀態做出反應;家庭成員也能彼此查看。
MQTT 是 publish and subscribe 通訊協定,Mosquitto 是常用的 broker。它在 1883 以明文監聽,在 8883 提供 TLS,而你只應使用 8883。存取控制以 topic 為單位,因此可以允許某個帳戶 publish owntracks/alice/phone,但無法讀取其他內容。這是家庭環境採用 MQTT 的真正理由:broker 會在應用程式下層強制執行誰能查看誰,因此應用程式錯誤不會擴大可見範圍。
代價是多一個服務,並且需要管理自己的憑證、使用者清單與故障模式。broker 停止接受連線時,看起來就像手機沒有訊號;這兩種情況都不會告訴你原因。
單支手機會產生多少筆位置資料?
以下數字是算術結果,不是測量值。計算假設固定回報間隔、每次回報產生一筆資料,且沒有其他資料來源。
The data behind this chart
[
{
"label": "Every 30 seconds",
"points_30d": "86,400",
"points_365d": "1,051,200"
},
{
"label": "Every 60 seconds",
"points_30d": "43,200",
"points_365d": "525,600"
},
{
"label": "Every 5 minutes",
"points_30d": "8,640",
"points_365d": "105,120"
},
{
"label": "Every 15 minutes",
"points_30d": "2,880",
"points_365d": "35,040"
}
]手機每分鐘回報一次時,每月會寫入 43,200 筆資料,每年會寫入 525,600 筆資料。將間隔調整為 15 分鐘後,每年的資料量會變成 35,040 筆。實際應用程式通常更複雜,因為除了依時間回報,也會在位置位移時回報;手機靜止時則會停止回報。因此,請將第一列視為上限,而不是預測值。
每年 500000 筆資料對 PostgreSQL 來說很少。最先造成負擔的通常是繪圖:如果地圖要以完整解析度呈現一整年的位置資料,瀏覽器會在資料庫察覺問題之前就停止回應。這也是這類應用程式會將歷史資料彙整為行程與地點的原因。請在自己的伺服器上測量實際數量,不要直接採用部落格文章中的數字:
SELECT pg_size_pretty(pg_total_relation_size('tc_positions'));這是 PostgreSQL 中 Traccar 的 positions 資料表。選定伺服器後,正常使用一個月,再執行對應的查詢,最後將結果乘以 12。這些伺服器都不會自行刪除舊位置資料。只要你持續傳送資料,它們就會保留資料,直到你手動移除為止。因此,請在資料表仍小時訂定保留規則,並確認備份涵蓋資料庫,而不只是設定檔,因為位置歷史無法從其他資料重建。
電池耗電量由手機決定,不是伺服器決定
自架服務不會改變這一點。作業系統會決定何時喚醒 GPS、背景應用程式可執行多久,以及手機能否撐過一整晚。Android 會積極暫停背景工作,iOS 則會提供重大位置變更,而不是持續的位置資料。伺服器無法影響這些行為,因此在應用程式中縮短回報間隔只是提出要求,手機會自行決定如何處理。
你能控制的是手機上的設定:將背景位置權限設為始終允許,將追蹤應用程式排除在電池最佳化之外,並依照當天的行程選擇回報模式。整週使用移動模式,手機可能在下午 4 點前就耗盡電力。
伺服器端的症狀是一次寫入大量帶有舊時間戳記的資料列。Traccar Client 和 OwnTracks 都會在離線時暫存位置點,網路恢復後再一次送出,因此寫入時間與定位時間會是不同的值。地圖若在城市中畫出一條直線,表示定位資料有間隔,不代表那是一條道路。
伺服器端:TLS 與經過驗證的資料接收路徑
手機需要一個可解析的主機名稱,以及它信任的憑證。自簽憑證是全新安裝完全收不到資料最常見的原因:應用程式會因 TLS 交握失敗而放棄,伺服器日誌也會維持空白,因為請求從未完成。空白日誌看起來像是手機的問題,但實際上不是。
有兩種直接的做法。使用 nginx 搭配正式憑證終止 TLS,也就是 在 nginx 前方使用 Let's Encrypt 憑證,並且只開放 443。或者使用 Cloudflare Tunnel,讓公開 IP 上完全沒有監聽中的連接埠,完全不暴露任何入站連接埠。這適合 Dawarich 與 OwnTracks,因為它們的資料接收使用一般 HTTP。
使用 tunnel 路徑時有一項限制。Traccar 的 OsmAnd protocol 使用 HTTP,因此手機用戶端可順利通過反向代理或 tunnel。專用 GPS 硬體使用的二進位通訊協定則是在各自連接埠上的原始 TCP。這些連接埠必須真正對外開放,除了在 VPS 防火牆上開放,也要在供應商的獨立網路防火牆上開放。多數主機供應商會在不同的控制面板中管理這項防火牆。
服務回應後,使用一個請求驗證整條路徑,不要只根據應用程式的狀態猜測:
curl -si -u alice:secret -H 'Content-Type: application/json' \
-d '{"_type":"location","lat":51.5,"lon":-0.12,"tst":1788480000}' \
https://track.example.com/pub | head -1正常運作的 endpoint 會回應 2xx 狀態碼。401 表示認證資訊錯誤,但傳輸正常。若 curl 在收到任何狀態列之前就發生錯誤,表示問題出在 DNS 或 TLS。先修正憑證,再處理應用程式。
開放的 ingest endpoint 會洩漏你的位置
未設定驗證的 ingest URL 會將你的位置交給任何找到它的人,而且確實有人會找到。
- 持有該 URL 的任何人都能將位置點寫入你的歷程。虛假的位置點很難察覺,移除時也很麻煩。
- URL 不是秘密。它會出現在手機的應用程式設定、reverse proxy access log,以及你曾在瀏覽器分頁中測試過該 URL 時留下的瀏覽記錄,也可能出現在你尋求協助時附上的螢幕截圖中。
- 若 endpoint 會回應未經驗證的 GET 請求,猜中路徑的 crawler 就能取得你最近的位置。
- 無論採取何種措施,hostname 都是公開的。新簽發的憑證會在數分鐘內出現在 certificate transparency logs,因此,即使你從未公開某個位址,仍然可以被找到。
OwnTracks 使用 TLS 上的 HTTP Basic,Dawarich 使用 API key,Traccar 則使用其帳戶模型,並設定唯一的裝置識別碼。將 admin interface 與 ingest path 放在相同的驗證機制後方,因為整段行蹤都能在該介面中讀取。第一週過後,再查看有哪些來源持續嘗試連線:
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20清單中應以手機的 mobile IP 位址為主。其他來源若計數很高,就值得進一步檢查;在 nginx 的 ingest location 上設定 rate limit 也不會增加成本。
追蹤系統也可能在沒有明顯錯誤的情況下失效。container 停止後,手機仍會持續緩衝資料,而你可能要到數週後發現某趟行程遺失,才知道系統出了問題。將 container health check 或 systemd OnFailure= 指向你自己的 ntfy server,讓這段沉默透過同一支負責回報的手機傳達給你。
誰還能查看這些軌跡,以及如何強制執行存取控制
Traccar 透過使用者與裝置權限控管存取:帳戶只能查看管理員授權給它的裝置,API 則使用工作階段或 token。OwnTracks 透過 MQTT 時,會在 broker 端使用主題 ACL。這是上述方案中最強的控管方式,因為無法訂閱主題的帳戶,無論任何應用程式如何處理,都無法讀取該主題。OwnTracks 透過 HTTP 時沒有相等的控管層,因此 endpoint 後方的元件就是完整的存取控制機制。Dawarich 的設計是讓單一使用者查看自己的歷史記錄。因此,若多人需要互相即時查看位置,Traccar 或 broker 會是較合適的選擇。
家庭追蹤同時涉及同意與技術問題。凡是使用手機發布位置的人,都應知道手機會發布位置,也應知道如何停止發布。無法由本人關閉的追蹤器,不是家庭功能。
自架服務無法解決的問題
- 手機的作業系統會決定何時啟用 GPS,因此耗電與軌跡中的缺口主要是手機造成的,不是伺服器造成的。
- Google 已變更 Timeline 資料的匯出方式。規劃遷移前,請先閱讀 Dawarich 最新的匯入文件,因為 Google 目前提供的檔案,與兩年前使用者匯入的檔案不同。
- 每次請求都會讓端點看到你的行動 IP 位址,中間經過的每個網路也一樣。自架服務會改變由誰保留這筆記錄,但不會移除這筆記錄。
- 位置歷史無法替代。請備份資料庫,並還原一次以確認備份可用;此外,請以加密方式保存備份副本,因為它是伺服器上最敏感的檔案。
FAQ
哪個自架應用程式可以取代 Google Maps Timeline?
Dawarich。它是可自行託管的 Google Timeline 替代方案,可匯入 Google Maps Timeline 匯出資料,以及 OwnTracks、Strava、Immich、GPX、GeoJSON 資料和相片 EXIF,並以地點與行程呈現歷史紀錄,而不是即時地圖。Traccar 也能儲存相同的位置點,但其介面是車隊管理主控台,報表也是車隊報表。規劃遷移前,請先查看 Dawarich 的匯入文件,確認它所需的匯出格式,因為 Google 的匯出格式曾經變更。
可以在沒有 MQTT broker 的情況下使用 OwnTracks 嗎?
可以。將應用程式設為 HTTP 模式,並提供格式為 http[s]://[user[:password]@]host[:port]/path 的 URL;對 OwnTracks Recorder 而言,該 URL 是 /pub。它會傳送相同的 JSON payload,並以 HTTP Basic 進行驗證;OwnTracks 強烈建議使用 https:// scheme。等到兩個服務需要同時使用相同的資料流,或需要依 topic 設定存取控制,讓 broker 決定誰能查看哪些資料時,再加入 broker。
一年的位置歷史紀錄需要多少儲存空間?
請以資料列數量規劃,而不是以 GB 規劃。每支手機每分鐘回報一次,一年會產生 525,600 列;每十五分鐘回報一次則會產生 35,040 列。這兩種數量對 PostgreSQL 而言都很小。實際限制在於瀏覽器要在一張地圖上繪製一年的位置點,因此這類應用程式會進行彙總。使用 pg_total_relation_size 在一個月後測量自己的資料表,再乘以十二。
為什麼我的位置歷史紀錄會有缺口?
手機的作業系統會決定何時喚醒 GPS,以及何時停止背景應用程式,因此大多數缺口都始於此處。授予應用程式「永遠」的背景定位權限,將其排除在電池最佳化之外,並確認回報模式。在 iOS 的 OwnTracks 中,Move 模式每 locatorDisplacement 公尺或 locatorInterval 秒發布一次,預設值為 100 公尺和 300 秒;在 Android 上,則預設每 10 秒要求一次定位。無論是哪種情況,其耗電量都相當於導航應用程式。如果資料列延遲成批抵達,且帶有較早的時間戳記,表示離線緩衝區正在清空;定位資料已經取得,只是上傳延遲。
只使用秘密 URL 足以保護位置端點嗎?
不行。未經驗證的 ingest endpoint 會讓任何得知 URL 的人都能將虛假的位置點寫入你的歷史紀錄;URL 並不是秘密,因為它會存在於應用程式設定、反向代理存取日誌、瀏覽器歷史紀錄,以及你分享的任何螢幕截圖中。主機名稱本身即可被查出,因為新憑證簽發後不久就會出現在 certificate transparency logs 中。請在 TLS 上使用 HTTP Basic 或 API key,對 ingest path 設定速率限制,並讓管理介面使用相同的驗證機制。