據(jù)庫面板Linux部署與遠(yuǎn)程端口映射實踐)
DbGate 這個工具很多做后端和運維的朋友第一次聽到會誤以為是某種數(shù)據(jù)庫其實它是個開源的數(shù)據(jù)庫管理客戶端帶 Web 界面能把 MySQL、PostgreSQL、SQL Server、SQLite、MongoDB 這些連接統(tǒng)一收在一個瀏覽器頁面里管。這次要聊的事情很具體在 Linux 機器上把 DbGate 跑起來讓它在本地提供 Web 管理入口再借助內(nèi)網(wǎng)端口映射與遠(yuǎn)程端口轉(zhuǎn)發(fā)讓在外網(wǎng)環(huán)境下的自己也能打開這個面板查看數(shù)據(jù)。適合的人群挺明確——手上有多臺內(nèi)網(wǎng)服務(wù)器、經(jīng)常要臨時查庫改數(shù)據(jù)、又不想在每臺電腦上裝一堆客戶端的開發(fā)者以及喜歡自建服務(wù)、家里放著 NAS 或小主機的折騰黨。整套東西不算復(fù)雜但坑不少尤其是鏈路通了卻打不開頁面、頁面開了卻連不上庫這兩類問題下面會一個個拆開講。1. 先把需求想清楚為什么是本地 DbGate 加遠(yuǎn)程訪問1.1 DbGate 到底是數(shù)據(jù)庫還是數(shù)據(jù)庫面板先把最容易混淆的概念掰正。DbGate 不是數(shù)據(jù)庫它本身不存業(yè)務(wù)數(shù)據(jù)它是一層管理和查詢界面底層還是要去連真正的 MySQL、PostgreSQL 之類的實例。之所以要強調(diào)這一點是因為我見過不少人照著教程裝完 DbGate發(fā)現(xiàn)里面空空如也就以為裝壞了實際上是還沒在里面添加數(shù)據(jù)庫連接。DbGate 的價值在于把多種數(shù)據(jù)庫的連接配置、SQL 編輯器、表結(jié)構(gòu)瀏覽、數(shù)據(jù)導(dǎo)入導(dǎo)出集中到一個界面里而且它提供 Web 形態(tài)瀏覽器打開就能用不用在每臺工作機上裝客戶端。對于經(jīng)常在多臺機器之間切換、或者臨時借用別人電腦處理緊急問題的人來說這個特性非常實用。它支持 Docker 部署鏡像體積不大一臺 1 核 1G 的小機器就能跑起來資源占用比想象中低。1.2 幾種常見方案放在一起對比在選擇具體做法之前值得把幾條路擺在一起看看因為不同的出發(fā)點會導(dǎo)向完全不同的方案。下面這張表是我在實際項目里反復(fù)權(quán)衡后整理出來的參數(shù)以常見配置為準(zhǔn)具體還要按自己的環(huán)境微調(diào)方案部署位置優(yōu)點明顯短板適合場景桌面版 DbGate本機零配置開箱即用換電腦就要重裝重配單機開發(fā)Web 版跑在數(shù)據(jù)庫同機內(nèi)網(wǎng)服務(wù)器網(wǎng)絡(luò)路徑最短延遲低面板暴露在業(yè)務(wù)機上風(fēng)險集中小型內(nèi)網(wǎng)Web 版單獨一臺機器內(nèi)網(wǎng)獨立主機與數(shù)據(jù)庫隔離權(quán)限好控制多一層網(wǎng)絡(luò)跳轉(zhuǎn)團隊共用本地 Web 版 端口映射本地/家中主機數(shù)據(jù)不落外網(wǎng)面板可遠(yuǎn)程訪問依賴中轉(zhuǎn)鏈路可用性個人遠(yuǎn)程辦公我個人的選擇基本固定為第四種面板跑在自己控制的一臺內(nèi)網(wǎng) Linux 機器上數(shù)據(jù)庫連接信息只存在這臺機器里外部訪問通過端口轉(zhuǎn)發(fā)臨時打通。這樣做的好處是面板本身不在公網(wǎng)長期暴露需要的時候開一下用完關(guān)掉攻擊面可控。代價是要多維護一條鏈路但這點維護成本換來的是心里踏實我覺得很劃算。1.3 遠(yuǎn)程訪問的邊界必須先說清楚在動手之前有一句必須講在前面的話這類端口映射與遠(yuǎn)程轉(zhuǎn)發(fā)的做法只應(yīng)該用于訪問你自己擁有管理權(quán)限的自建服務(wù)比如家里的開發(fā)機、實驗室的內(nèi)網(wǎng)測試環(huán)境。它解決的是“我在外面想看一眼自己機器上的面板”這個需求不是用來繞過任何網(wǎng)絡(luò)管理策略的。如果你所在的網(wǎng)絡(luò)環(huán)境對出站連接有明確管理規(guī)定那就老老實實遵守別拿技術(shù)手段去試探邊界。另外把數(shù)據(jù)庫管理面板暴露到公網(wǎng)本身就是高風(fēng)險動作后面第 4 節(jié)會專門講加固務(wù)必別跳過。我見過太多案例面板掛上去三天日志里全是來自各地的掃描請求雖然多數(shù)只是探測但這種噪音本身就說明問題。2. Linux 上把 DbGate 跑起來的完整過程2.1 系統(tǒng)與資源的最低要求DbGate 的 Web 版對系統(tǒng)要求不高我實測下來Debian 系和 RHEL 系的常見發(fā)行版都能跑內(nèi)核版本別太老就行。資源方面1 核 CPU、1G 內(nèi)存是能起來的底線但如果要同時在里面開多個 SQL 編輯標(biāo)簽頁、加載大表結(jié)構(gòu)建議給到 2G 內(nèi)存否則瀏覽器端操作會有明顯卡頓。磁盤空間主要看你要不要在里面做數(shù)據(jù)導(dǎo)出留 10G 以上比較從容。系統(tǒng)層面需要預(yù)裝 Docker 與 Docker Compose這是最省事的方式如果你堅持不用容器也可以走 Node 源碼方式跑但依賴管理會麻煩不少我不推薦新手走那條路。下面給的是基于容器的流程也是我目前唯一在用的方式。2.2 用一條 docker run 命令先跑通先別急著上編排文件用最簡單的單條命令驗證一下鏡像能正常啟動這是排錯時最高效的做法# 拉取鏡像并后臺啟動映射默認(rèn) Web 端口 3000 docker run -d \ --name dbgate \ --restart unless-stopped \ -p 3000:3000 \ -v /opt/dbgate/data:/home/dbgate/.dbgate \ dbgate/dbgate這里有幾個參數(shù)值得解釋。--restart unless-stopped保證機器重啟后容器自動拉起省得每次手動敲命令這個在長期運行的自建服務(wù)里幾乎是必備項。-v掛載的是容器內(nèi)的數(shù)據(jù)目錄DbGate 會把連接配置、查詢歷史、界面偏好都存在這里如果不掛載容器一刪配置全丟我之前就因為偷懶沒掛載重裝后手工補了十幾個數(shù)據(jù)庫連接那滋味不好受。路徑可以按自己的磁盤規(guī)劃調(diào)整但要確保宿主目錄存在且容器內(nèi)用戶有寫權(quán)限權(quán)限不對會導(dǎo)致啟動后數(shù)據(jù)目錄不可寫表現(xiàn)是頁面能開但保存連接時報錯。啟動之后用docker ps看一眼狀態(tài)再用瀏覽器訪問http://你的內(nèi)網(wǎng)IP:3000。如果頁面出不來先用curl -I http://127.0.0.1:3000在本機驗證服務(wù)是否在監(jiān)聽這一步能把“服務(wù)沒起來”和“網(wǎng)絡(luò)不通”兩種情況區(qū)分開是排查的第一刀。2.3 換成 compose 編排把配置固化下來單條命令適合驗證長期使用我還是會換成 compose 文件理由很簡單環(huán)境變量、數(shù)據(jù)卷、端口映射這些配置寫進(jìn)文件里換機器時復(fù)制一份就能重建不用回憶當(dāng)初敲了什么。下面是我在用的版本可以直接抄version: 3.8 services: dbgate: image: dbgate/dbgate container_name: dbgate restart: unless-stopped ports: - 127.0.0.1:3000:3000 environment: - LOGINadmin - PASSWORD換成你自己的強口令 - CONNECTIONSmysql_main,pg_dev - LABEL_mysql_main業(yè)務(wù)庫 - SERVER_mysql_main192.168.1.20 - PORT_mysql_main3306 - USER_mysql_mainreader - PASSWORD_mysql_main只讀賬號口令 - ENGINE_mysql_mainmysqldbgate-plugin-mysql - LABEL_pg_dev測試庫 - SERVER_pg_dev192.168.1.21 - PORT_pg_dev5432 - USER_pg_devdevuser - PASSWORD_pg_dev測試賬號口令 - ENGINE_pg_devpostgresdbgate-plugin-postgres volumes: - /opt/dbgate/data:/home/dbgate/.dbgate這里有幾個關(guān)鍵點需要點出來。第一端口映射寫成127.0.0.1:3000:3000意思是只監(jiān)聽本機回環(huán)地址外部直連壓根連不上必須走后面的轉(zhuǎn)發(fā)鏈路才能訪問這是安全設(shè)計的一部分別圖省事寫成0.0.0.0。第二LOGIN和PASSWORD是開啟登錄校驗的環(huán)境變量不同版本的變量名可能略有差異配置前建議對一眼官方文檔但思路是一致的——一定要開認(rèn)證絕不能裸奔。第三CONNECTIONS里列出的名字要和后面LABEL_、SERVER_、PORT_等前綴拼接的變量名對得上拼錯一個字母那個連接就不會出現(xiàn)在列表里而且不會有明顯報錯只能靠自己核對這個坑我踩過兩次后來養(yǎng)成了先只配一個連接跑通、再批量復(fù)制的習(xí)慣。2.4 首次進(jìn)入面板要做的幾件事容器起來、頁面能打開之后別急著建連接先把幾個基礎(chǔ)動作完成。第一是確認(rèn)登錄認(rèn)證生效退出瀏覽器再進(jìn)一次如果沒有提示登錄就能直接看到界面說明認(rèn)證變量沒起作用得回頭檢查拼寫或者版本兼容性。第二是添加數(shù)據(jù)庫連接時密碼這類敏感信息盡量用只有讀權(quán)限的賬號別圖方便直接上 root這一點后面還會展開。第三是留意面板右上角的風(fēng)味設(shè)置比如查詢結(jié)果的默認(rèn)行數(shù)限制大表查詢不設(shè)限制很容易把瀏覽器卡死我一般設(shè)成 1000 行先看需要全量再用導(dǎo)出功能。第四如果打算長期使用建議把面板的時區(qū)、語言、默認(rèn)編輯器樣式這些一次性調(diào)好因為這些偏好存在數(shù)據(jù)卷里一旦確定下來就不用再動了。3. 內(nèi)網(wǎng)端口映射的實現(xiàn)思路與兩種落地方式3.1 為什么家里或內(nèi)網(wǎng)的機器外面訪問不到大部分家庭寬帶和小型辦公網(wǎng)絡(luò)機器拿到的都是內(nèi)網(wǎng)地址比如192.168.x.x這種它在局域網(wǎng)內(nèi)部互通沒問題但外部世界根本不知道這個地址的存在。路由器背后通常還有一層網(wǎng)絡(luò)地址轉(zhuǎn)換把內(nèi)網(wǎng)多個設(shè)備共享一個出口地址這就導(dǎo)致外部無法主動向內(nèi)的某個端口發(fā)起連接。這是網(wǎng)絡(luò)結(jié)構(gòu)的客觀結(jié)果不是什么故障。要解決它思路只有一條借助一臺在公網(wǎng)上能被訪問到的中轉(zhuǎn)機器讓內(nèi)網(wǎng)這臺主動向外建立一條長連接外部訪問先到中轉(zhuǎn)機再順著這條已經(jīng)建立好的連接回送到內(nèi)網(wǎng)服務(wù)上。這就是端口映射與反向端口轉(zhuǎn)發(fā)的基本原理后面的兩種做法都是這個思路的不同實現(xiàn)。打個生活化的比方內(nèi)網(wǎng)機器像是一個沒有對外電話的辦公室中轉(zhuǎn)機是總機。內(nèi)網(wǎng)機器主動給總機打個電話說“我在這有事轉(zhuǎn)給我”這通電話一旦保持住外面的人打總機總機就知道該轉(zhuǎn)接到哪個分機。關(guān)鍵在于“主動撥出去”這個動作因為內(nèi)網(wǎng)向外發(fā)起連接通常不受限制而外部向內(nèi)發(fā)起連接往往被攔住。3.2 方式一用 SSH 遠(yuǎn)程端口轉(zhuǎn)發(fā)打通如果你手上有一臺帶公網(wǎng)地址的 Linux 中轉(zhuǎn)機而且能 SSH 登錄那最輕量的辦法就是直接用 SSH 自帶的遠(yuǎn)程端口轉(zhuǎn)發(fā)不需要裝任何額外軟件。核心命令就一行# 在中轉(zhuǎn)機上把 18080 端口轉(zhuǎn)發(fā)到本地內(nèi)網(wǎng)的 3000 端口 ssh -N -R 0.0.0.0:18080:127.0.0.1:3000 user你的中轉(zhuǎn)機地址-R表示遠(yuǎn)程轉(zhuǎn)發(fā)含義是“在中轉(zhuǎn)機上監(jiān)聽 18080收到連接后通過這條 SSH 連接送回我這邊的 3000 端口”。-N表示不執(zhí)行遠(yuǎn)程命令只做轉(zhuǎn)發(fā)不加這個參數(shù)會開一個交互式 shell雖然也能用但不夠干凈。這條命令必須在運行 DbGate 的那臺內(nèi)網(wǎng)機器上執(zhí)行因為127.0.0.1:3000是相對于執(zhí)行命令的一方來解析的這個細(xì)節(jié)搞反了是新手最常見的錯誤表現(xiàn)為命令沒報錯但外面訪問中轉(zhuǎn)機 18080 端口時連接被拒。還有一個坑要提前處理中轉(zhuǎn)機上的 SSH 服務(wù)默認(rèn)可能不允許遠(yuǎn)程轉(zhuǎn)發(fā)綁定到非回環(huán)地址需要檢查配置里是否允許網(wǎng)關(guān)端口否則你在命令里寫0.0.0.0也不會生效只會綁定在127.0.0.1上。改完之后重啟服務(wù)再試。另外這種命令行方式有個天然缺陷SSH 連接斷了轉(zhuǎn)發(fā)就沒了網(wǎng)絡(luò)抖動一次就得手動重連所以實際使用我一定會配合autossh做?;钏茉谶B接斷開后自動重連配置好之后基本不用管。?;顓?shù)里那個監(jiān)控端口別設(shè)成和轉(zhuǎn)發(fā)端口一樣否則會互相干擾。3.3 方式二用開源隧道工具做中轉(zhuǎn)映射第二種方式適合沒有現(xiàn)成公網(wǎng) SSH 環(huán)境、或者想更省心的情況在中轉(zhuǎn)機上部署一套開源的反向隧道服務(wù)端內(nèi)網(wǎng)機器上跑客戶端兩邊通過配置文件約定映射關(guān)系。這類工具的原理和上面 SSH 轉(zhuǎn)發(fā)是一樣的只是把?;?、重連、多路復(fù)用這些瑣事封裝好了穩(wěn)定性更好適合長期掛著。配置大體分兩塊。服務(wù)端這邊要確認(rèn)監(jiān)聽端口、認(rèn)證方式、以及允不允許客戶端自定義映射端口客戶端這邊寫清楚本地服務(wù)的地址和端口指向中轉(zhuǎn)機的地址和認(rèn)證憑據(jù)。典型的客戶端配置思路是這樣# 客戶端配置示意字段名以所選工具文檔為準(zhǔn) server_addr: 你的中轉(zhuǎn)機地址 server_port: 服務(wù)端監(jiān)聽端口 auth_token: 一段足夠長的隨機串 tunnels: dbgate: local_addr: 127.0.0.1 local_port: 3000 remote_port: 18080這里auth_token千萬別用弱口令或者默認(rèn)值中轉(zhuǎn)機是公網(wǎng)可達(dá)的認(rèn)證強度直接決定了別人能不能把你的隧道掛上去。我見過有人圖省事用123456結(jié)果被掃描到之后隧道被別人復(fù)用雖然只跑了幾天沒造成實質(zhì)損失但日志里一堆陌生連接看著就頭皮發(fā)麻。另外local_addr寫127.0.0.1的前提是 DbGate 和客戶端在同一臺機器上如果分開了就要改成實際內(nèi)網(wǎng)地址并且確保那臺機器防火墻放行了對應(yīng)端口。3.4 域名、端口與訪問鏈路的對齊檢查鏈路打通之后訪問地址通常是“中轉(zhuǎn)機地址 映射端口”的組合比如http://中轉(zhuǎn)機地址:18080。如果想讓地址好看一點可以給中轉(zhuǎn)機綁個域名但這一步涉及域名解析配置需要確保解析記錄指向中轉(zhuǎn)機且中轉(zhuǎn)機的網(wǎng)絡(luò)策略允許該端口的入站連接。這里最容易出問題的是防火墻中轉(zhuǎn)機上的系統(tǒng)防火墻、以及云服務(wù)商側(cè)的安全組策略兩處都要放行映射端口只改一處是徒勞的。我的排查順序固定為先在中轉(zhuǎn)機上curl -I http://127.0.0.1:18080看服務(wù)端有沒有活再從另一臺外網(wǎng)機器訪問逐段定位。這個順序能快速判斷問題出在轉(zhuǎn)發(fā)鏈路本身還是外圍網(wǎng)絡(luò)策略上。4. 安全加固別把數(shù)據(jù)庫面板變成公共入口4.1 認(rèn)證、端口與暴露面控制把面板映射到公網(wǎng)等于給數(shù)據(jù)庫開了一扇窗加固必須同步做不能等出了問題再補。第一層是面板自身的登錄認(rèn)證前面已經(jīng)強調(diào)過務(wù)必開啟并且使用足夠復(fù)雜的口令長度建議 16 位以上包含大小寫、數(shù)字和符號。第二層是端口策略映射用的對外端口不要選 3000、8080 這類掃描器重點關(guān)照的常見端口換一個高位隨機端口能過濾掉大量無差別探測雖然這不是真正的安全措施但能顯著減少噪音。第三層是訪問來源限制如果你的外網(wǎng)出口地址相對固定可以在中轉(zhuǎn)機上做來源地址白名單只允許自己的地址訪問映射端口這一招的效果比改端口強得多。第四層也是最容易被忽略的鏈路用完就關(guān)臨時排查問題沒必要讓它 7×24 小時掛著。4.2 數(shù)據(jù)庫賬號的最小權(quán)限原則這一條比面板加固更重要因為它決定了“萬一被突破損失有多大”。在 DbGate 里添加連接時盡量用專門為查詢場景創(chuàng)建的賬號只授予目標(biāo)庫的讀取權(quán)限需要改數(shù)據(jù)時再單獨開一個受限賬號而不是直接拿業(yè)務(wù)主賬號或者管理賬號往上連。我自己的習(xí)慣是給每個用途建一個獨立賬號日常查數(shù)據(jù)一個只讀賬號改配置一個限定表范圍的賬號兩個絕不混用。這樣即使面板憑據(jù)泄露攻擊者能拿到的也只是只讀視圖破壞面被限制住了。另外 DbGate 里保存的連接口令是存在數(shù)據(jù)卷里的那臺機器的訪問權(quán)限本身也要管好別讓不相干的人能登進(jìn)去翻文件。4.3 日志留痕與異常發(fā)現(xiàn)加固做完不等于萬事大吉還得有發(fā)現(xiàn)問題的能力。中轉(zhuǎn)機上的連接日志要留意正常使用時的連接來源相對固定如果出現(xiàn)大量陌生地址的探測記錄說明端口已經(jīng)被掃到了這時候要么收緊白名單要么直接換端口。DbGate 自身也會記錄操作歷史定期看一眼有沒有非自己發(fā)起的查詢這個習(xí)慣在多人共用的環(huán)境里尤其重要。我的做法是每周掃一眼日志發(fā)現(xiàn)異常來源就加進(jìn)攔截列表成本很低但很有效。另外提醒一句這些日志本身也別亂丟保留一段時間萬一真出事它是唯一能還原過程的依據(jù)。5. 常見問題與排查速查表5.1 頁面打不開的三類原因鏈路問題基本可以歸為三類按下面這個順序查效率最高。第一類DbGate 服務(wù)本身沒起來表現(xiàn)為內(nèi)網(wǎng)直連127.0.0.1:3000也不通這時候看容器日志多半是數(shù)據(jù)卷權(quán)限或者端口沖突。第二類轉(zhuǎn)發(fā)鏈路沒建立表現(xiàn)為內(nèi)網(wǎng)能訪問但走映射地址不通這時候在中轉(zhuǎn)機上驗證映射端口有沒有被監(jiān)聽再看客戶端或 SSH 會話是否還活著。第三類外圍策略攔截表現(xiàn)為中轉(zhuǎn)機本機訪問映射端口正常但從外部機器訪問超時基本可以鎖定是防火墻或安全組沒放行?,F(xiàn)象最可能原因快速驗證方式內(nèi)網(wǎng)本機都打不開頁面容器未啟動或端口沖突docker logs dbgate查看報錯內(nèi)網(wǎng)通、映射地址不通轉(zhuǎn)發(fā)會話斷開或未綁定對外地址中轉(zhuǎn)機上檢查端口監(jiān)聽狀態(tài)中轉(zhuǎn)機本機通、外網(wǎng)不通防火墻或安全組未放行換一臺外網(wǎng)機器做對比訪問頁面能開但登錄后白屏瀏覽器緩存或前端資源加載失敗無痕窗口重試、查看網(wǎng)絡(luò)請求5.2 連接上數(shù)據(jù)庫卻查詢報錯面板通了不代表數(shù)據(jù)庫通了這類問題跟映射鏈路無關(guān)純粹是連接配置的事。最常見的是主機地址填錯尤其在容器里跑 DbGate 的時候容器內(nèi)的127.0.0.1指的是容器自己不是宿主機要連宿主機的數(shù)據(jù)庫得用宿主機內(nèi)網(wǎng)地址或者特殊的網(wǎng)關(guān)地址。其次是賬號權(quán)限連接成功但查詢某張表報拒絕說明賬號對該庫沒有授權(quán)需要回去補權(quán)限。第三是字符集問題某些老版本數(shù)據(jù)庫默認(rèn)字符集不一致查詢中文會出亂碼這個在連接配置里指定一下字符集就能解決。還有一種情況是連接池被占滿表現(xiàn)是間歇性超時適當(dāng)調(diào)小 DbGate 并發(fā)查詢數(shù)或者給數(shù)據(jù)庫放寬連接上限即可。5.3 幾條踩過之后才記住的實際經(jīng)驗最后分享幾條文檔里不會寫、但實際用起來很關(guān)鍵的經(jīng)驗。第一條先在純內(nèi)網(wǎng)環(huán)境把 DbGate 和數(shù)據(jù)庫連接全部調(diào)通確認(rèn)能正常查詢之后再動手做映射順序反了會把兩類問題攪在一起排查成本翻倍。第二條映射端口和 DbGate 的監(jiān)聽端口不要設(shè)成同一個數(shù)字雖然理論上不沖突但在排查時容易自己把自己繞暈。第三條數(shù)據(jù)卷的備份比想象中重要那里面存著所有連接配置我現(xiàn)在的做法是每周打包一次丟到另一臺機器上成本幾秒鐘省過大事。第四條如果映射鏈路經(jīng)常斷先別懷疑工具去看看中轉(zhuǎn)機的網(wǎng)絡(luò)質(zhì)量或者家寬出口是不是在頻繁重?fù)芎芏鄷r候問題出在底層鏈路而不是配置。第五條任何一次配置變更之后都從外部完整走一遍訪問流程再收工別只驗證一半就離開我有過一次改完防火墻只測了本機就收手第二天在外面死活連不上白白浪費一個上午。