JavaScript >> Javascript 文檔 >  >> Node.js

如何使用 Node.js 通過 SSH 連接到服務器

如何在 Digital Ocean 上設置服務器,創建 SSH 密鑰,並使用 node-ssh 使用您的 SSH 密鑰打包到 SSH 到該服務器。

開始使用

在本教程中,我們將使用 CheatCode 的全棧 JavaScript 框架 Joystick。 Joystick 將前端 UI 框架與用於構建應用的 Node.js 後端結合在一起。

首先,我們要通過 NPM 安裝 Joystick。確保在安裝之前使用 Node.js 16+ 以確保兼容性(如果您需要學習如何安裝 Node.js 或在計算機上運行多個版本,請先閱讀本教程):

終端

npm i -g @joystick.js/cli

這將在您的計算機上全局安裝操縱桿。安裝好之後,接下來我們新建一個項目:

終端

joystick create app

幾秒鐘後,您將看到一條消息已註銷到 cd 進入你的新項目並運行 joystick start .在你運行之前,我們需要安裝一個依賴,node-ssh

終端

cd app && npm i node-ssh

一旦你安裝了這個,你就可以開始你的應用了:

終端

joystick start

在此之後,您的應用應該可以運行了,我們可以開始了。

生成 SSH 密鑰

為了演示使用 SSH 與服務器通信,最好先確保我們手頭有 SSH 密鑰。當你可以 使用用戶名和密碼 SSH 到服務器,應該避免這種情況,因為單獨的密碼比 SSH 文件更容易受到攻擊。

首先,我們將使用 ED25519 標準生成 SSH 密鑰,這是一種更新、更快、更安全的加密標準。首先,我們要在 joystick start 為我們生成的應用程序的根目錄下創建一個新文件夾 稱為private 然後在該文件夾中,我們將創建另一個名為 ssh

終端

mkdir private
cd private
mkdir ssh
cd ssh

一旦你有 cd 'd 進入 /private/ssh 接下來,我們要從應用的根目錄生成 SSH 密鑰:

終端

ssh-keygen -t ed25519 -C "[email protected]"

在您的計算機上,您應該有一個名為 ssh-keygen 的內置工具 .顧名思義,它用於生成 SSH 密鑰 .在這裡,我們調用 ssh-keygen 傳遞兩個標誌:-t 它代表要生成的密鑰的“類型”(這裡是 ed25519 鍵),然後是 -C 代表“評論”(在這裡,我們使用它來輸入我們的電子郵件地址,因為評論附加到我們的公鑰末尾並暗示其原始意圖)。

這將提示您幾個問題(在為每個問題輸入答案後按回車鍵)...

  1. 對於“輸入保存密鑰的文件”提示,您要輸入 ./<your-email-address> 其中 <your-email-address> 應替換為您要用於此密鑰的電子郵件地址(例如,./[email protected] )。 注意 :./ 開頭很重要,因為它確保文件存儲在 private/ssh 我們剛剛創建的文件夾。
  2. 接下來,系統會提示您輸入密碼。 強烈推薦 .向您的 SSH 密鑰添加密碼可增加另一層安全性,以便在您的 SSH 密鑰洩露/暴露的情況下,攻擊者 需要密鑰的密碼才能使用它。 記下您輸入的密碼,我們稍後會用到它 .
  3. 接下來,系統會提示您確認您在第 2 步中輸入的密碼。

完成後,您應該會看到類似這樣的內容打印到終端:

終端

Your identification has been saved in ./[email protected]
Your public key has been saved in ./[email protected]
The key fingerprint is:
SHA256:VUwq60W7bY4hWW/rmr4LdvggZ5Vg+JNwGo9nONfe5hs [email protected]
The key's randomart image is:
+--[ED25519 256]--+
|           oo    |
|       .   o.    |
|      + = +      |
|       @ O o     |
|      = S B      |
|       * O =     |
|      . @ = E    |
|       = * X o   |
|         .O=*.   |
+----[SHA256]-----+

更重要的是,您還應該在 private/ssh 中看到兩個文件 :private/ssh/<your-email-address>private/ssh/<your-email-address>.pub .第一個是你的私鑰 後者是您的 公鑰 .

這裡的區別很重要。正如我們稍後會看到的,我們將給出我們的 .pub 或我們服務器所在主機的“公鑰”。稍後,當我們“SSH 進入”我們的服務器時,我們會將我們的私鑰與請求一起傳遞。在幕後,我們的主機將檢查它是否具有與該私鑰對應的公鑰。如果它確實 並且簽名相互匹配(並且密碼正確),我們的請求將被允許通過。

創建數字海洋水滴

為了演示使用 SSH,我們需要一個可以實際通信的遠程服務器。對於我們的示例,我們將在 Digital Ocean 上設置一個 Droplet(Droplet 是 Digital Ocean 的服務器實例品牌名稱)。我們的目標是獲得對服務器的訪問權——更具體地說,是它的 IP 地址——並在我們的 SSH 請求中使用它。

首先,如果您還沒有 Digital Ocean 帳戶,請前往註冊頁面並創建一個帳戶。

設置並驗證您的帳戶後,我們將前往項目儀表板並在右上角單擊“創建”按鈕,然後從下拉菜單中選擇“Droplets”。

在下一個屏幕中,我們需要選擇以下選項:

  1. 在“選擇圖像”下,我們要選擇第一個框“Ubuntu”,並確保在該框底部的下拉列表中選擇了“20.04 (LTS) x64”選項。
  2. 在“Choose a plan”下,我們要選擇“Basic”,然後在“CPU options”下選擇“Regular with SSD”和第一個“$5/mo”選項,1GB/1CPU。
  3. 在“選擇數據中心區域”下,選擇離您最近的區域(我在本教程中選擇“紐約 1”)。
  4. 在“身份驗證”下確保選中“SSH 密鑰”,然後在此下方的框中單擊“新建 SSH 密鑰”按鈕。這將顯示一個新窗口,提示您輸入“SSH 密鑰內容”和“名稱”。對於“SSH 密鑰內容”,您要粘貼 <your-email-address>.pub 的內容 private/ssh 中的文件 文件夾和“名稱”,您要輸入您的電子郵件地址。
  1. (可選)在底部的“選擇主機名”下輸入一個比自動生成的名稱更友好的名稱(例如“ssh-tutorial”或“c​​heatcode-tutorial”),以便您記住它的用途。
  2. 點擊綠色的“創建 Droplet”按鈕。

在此之後,您將被重定向回您的項目儀表板。你應該 查看您剛剛創建的 Droplet 的加載欄,但如果沒有,請點擊刷新,它應該會出現。完成後,單擊其名稱以顯示其儀表板:

一旦你看到這個,你就準備好了!現在我們有了一個可以通過 SSH 連接的服務器,接下來,我們想進入我們的應用程序代碼並學習如何通過 Node.js 使用 SSH。

將 getter 連接到 SSH 到我們的服務器

現在是有趣的部分。為了演示使用 SSH 連接到我們的服務器的過程,我們將在 Joystick 應用程序中連接一個 getter。在 Joystick 中,getter 是一種快速定義響應 HTTP GET 請求的 REST API 路由的方法。 Getter 很靈活,因為它們可以直接作為普通 HTTP 端點調用,或者通過 get() @joystick.js/ui 內置函數 和 @joystick.js/node 包。

從應用程序的根目錄,我們要打開 /api/index.js 當我們運行 joystick create app 時為我們生成的文件 早些時候。這個文件被稱為我們在 Joystick 中的 API 的“模式”。在裡面,你會看到一個普通的 JavaScript 對像被導出,上面預定義了兩個屬性:getterssetters .

在操縱桿應用中,getters 包含 getter 的定義 您希望在應用程序中定義的端點(同樣,這些是 HTTP GET 端點)和 setters 包含 setter 的定義 您希望在應用程序中定義的端點(這些是 HTTP POST 端點)。前者旨在“獲取”或閱讀 應用中的數據,而後者旨在創建、更新和刪除應用中的數據。

在這個文件中,我們將定義一個名為 serverFileTree 的 getter .這個 getter 的目標是通過 SSH 連接到我們的服務器並運行 Linux ls -al 命令列出了我們正在通過 SSH 連接的機器的根目錄中的所有文件(稍後會詳細介紹)。如果我們得到一個列表,我們可以確認我們已經成功建立了連接。

/api/index.js

import joystick from '@joystick.js/node';
import { NodeSSH } from 'node-ssh';

export default {
  getters: {
    serverFileTree: {
      get: async () => {
        const ssh = new NodeSSH();

        await ssh.connect({
          host: joystick?.settings?.private?.ssh?.ipAddress,
          username: 'root',
          privateKey: `${process.cwd()}/private/ssh/[email protected]`,
          passphrase: joystick?.settings?.private?.ssh?.passphrase,
        });

        const result = await ssh.execCommand(`ls -al`, { cwd: '/', options: { pty: true } });

        return result?.stdout;
      },
    },
  },
  setters: {},
};

因為我們不需要太多代碼,所以我們在這裡輸出了完整的實現。從頂部開始,我們要導入兩個東西:

  1. joystick 來自 @joystick.js/node 我們將用於訪問應用程序設置的包。
  2. { NodeSSH } 來自 node-ssh 這將幫助我們與服務器建立經過身份驗證的 SSH 連接並在其上執行命令。

在我們現有的 getters 中 對象,我們添加了一個屬性 serverFileTree 這是我們的 getter 的名稱,我們為它分配了一個對象,該對象將 定義 那個吸氣劑。在該對像上,我們添加了一個屬性 get 分配給一個函數。

那個函數get() 每當向 serverFileTree 發出請求時,操縱桿會自動調用它 吸氣劑。就像我們上面解釋的那樣,這可以通過 get() 來完成 @joystick.js/ui 中的函數 和 @joystick.js/nodeget('serverFileTree') ,或者,直接通過像 http://localhost:2600/api/_getters/serverFileTree 這樣的 HTTP 請求 (/api/_getters/<getter-name> 該 URL 中的一部分是由 Joystick 自動為我們生成的)。

在該函數內部,我們的目標是“獲取”一些數據並將其返回。該數據可以來自任何地方 .在這種情況下,我們希望通過 SSH 連接到我們之前設置的服務器,在其上執行命令,然後從我們的 getter 中返回執行該命令的輸出。

為此,首先,我們需要使用 new NodeSSH() 創建一個 NodeSSH 實例 .這為我們提供了一個新的“工作區”(可以這麼說),用於連接到我們的服務器並在其上運行我們的命令。在這裡,我們獲取該實例並將其存儲在變量 ssh 中 .

接下來,將前面的函數傳遞給我們的get 屬性,我們添加了關鍵字 async 允許我們使用簡寫 await 使用 JavaScript Promises 時的語法。我們在這裡這樣做是因為我們期望來自 node-ssh 的方法 包返回 JavaScript Promises。

我們的第一步——也是最重要的一步——是與我們的服務器建立連接。為此,我們調用 await ssh.connect() 傳遞一個選項對象:

  • host 這是我們要連接的服務器的 IP 地址。
  • username 這是我們要連接的服務器上的用戶名(在這種情況下,我們使用的是 root Ubuntu 提供的用戶(我們告訴 Digital Ocean 安裝在我們服務器上的操作系統)。
  • privateKey 這是我們之前生成的私鑰文件的路徑(請記住,我們之前將其中的公鑰部分提供給了 Digital Ocean)。這裡,process.cwd() 正在檢索 Node.js “當前工作目錄”路徑,我們希望它是 app 的完整路徑 我們使用 joystick create app 創建的文件夾 .我們將它與 /private/ssh/<your-email-address> 連接在一起 指向我們的 SSH 私鑰。
  • passphrase 您在生成 SSH 密鑰時輸入的密碼。

把房間裡的大象叫出來,我們這裡有兩行可能沒有意義:joystick?.settings?.private?.ssh?.ipAddressjoystick?.settings?.private?.ssh?.passphrase .在這裡,我們從尚未討論的設置文件中提取值。

/settings.development.json

{
  "config": {
    "databases": [
      {
        "provider": "mongodb",
        "users": true,
        "options": {}
      }
    ],
    "i18n": {
      "defaultLanguage": "en-US"
    },
    "middleware": {},
    "email": {
      "from": "",
      "smtp": {
        "host": "",
        "port": 587,
        "username": "",
        "password": ""
      }
    }
  },
  "global": {},
  "public": {},
  "private": {
    "ssh": {
      "ipAddress": "<ip address goes here>",
      "passphrase": "<ssh key password goes here>"
    }
  }
}

如果我們打開那個文件,在底部的 private 對象,我們要添加另一個對象 ssh 並在該對像上,定義兩個設置為字符串的屬性:ipAddresspassphrase .如此處所述,我們將使用 IP 地址填充它們(在 Digital Ocean 儀表板中表示為 ipv4: 167.99.145.55 我們服務器的 Droplet 摘要頁面頂部附近)和您在生成 SSH 密鑰時輸入的密碼。

/api/index.js

import joystick from '@joystick.js/node';
import { NodeSSH } from 'node-ssh';

export default {
  getters: {
    serverFileTree: {
      get: async () => {
        const ssh = new NodeSSH();

        await ssh.connect({
          host: joystick?.settings?.private?.ssh?.ipAddress,
          username: 'root',
          privateKey: `${process.cwd()}/private/ssh/[email protected]`,
          passphrase: joystick?.settings?.private?.ssh?.passphrase,
        });

        const result = await ssh.execCommand(`ls -al`, { cwd: '/', options: { pty: true } });

        return result?.stdout;
      },
    },
  },
  setters: {},
};

一旦您的設置更新並保存,最後,我們就可以在我們的服務器上運行命令了。為此,我們只需要調用 await ssh.execCommand() .對於該函數,作為第一個參數的字符串,我們傳遞我們想要運行的命令,然後作為第二個參數,請求的選項對象。在這裡,我們設置了兩個:cwd/ (就是說“當你執行這個命令時,從服務器的絕對根目錄執行”)和 pty: true 它告訴 node-ssh 允許文本輸入/輸出,並且是某些命令使用此過程工作所必需的。

這樣,我們將調用存儲在變量 const result 中 我們希望包含一個帶有 stdout 的對象 (標準輸出)和 stderr (標準錯誤)屬性,兩者都是在服務器上運行命令的輸出字符串。

最後,因為我們可以相信我們正在運行的命令應該可以正常運行,所以我們從 getter 返回 result?.stdout .有了這個,我們應該有一個工作 SSH 連接回到我們的服務器。如果我們打開網絡瀏覽器並訪問 http://localhost:2600/api/_getters/serverFileTree 稍等片刻後,我們應該會看到返回到瀏覽器的命令輸出。

總結

在本教程中,我們學習瞭如何創建 SSH 密鑰對、在 Digital Ocean 上設置服務器以及使用 SSH 連接到該服務器。我們學習瞭如何在 Joystick 應用中創建 getter 端點以及如何使用 node-ssh 從該 getter 中打包以在遠程服務器上運行命令並將其輸出作為端點的響應返回。


Tutorial JavaScript 教程
  1. 1.調用棧

  2. Javascript 基於原型是什麼意思?

  3. 使用 Spotify 的後台構建更好的開發者門戶

  4. 失敗的程度如何?

  5. 使用 Svelte 商店構建通知中心

  6. 漸進式 Web 應用程序:漫長的遊戲

  7. [TypeScript][Express] 試試 React

  1. NodeJS 服務器的簡單示例:Express、Koa 和 Hapi |討論。

  2. PHP Javascript表單formData 70:使用ajax完成(XMLHttpRequest)

  3. 使用 Firebase v9、TypeScript 和 Yup 進行 React 身份驗證。

  4. Javascript 中的數組 | Javascript速成課程

  5. 重構:功能性可重用部件

  6. 在電子的渲染器進程中使用 npm 模塊

  7. DIY VS 代碼擴展 2:發布

  1. 初看 Remix.run

  2. 寫新卡片

  3. DO Hackaton 日誌 #3

  4. React-Leaflet/React-Routing-Machine:刪除路線和航路點