這次案子有需要使用 .net core 存取 FTP 的功能,且又要求 FTP 要分三種登入方式

  1. 使用帳號密碼登入 FTP Server
  2. 使用帳號密碼登入 SFTP Server
  3. 使用 SSH 金鑰登入 SFTP Server

為了 開發環境 需要,最快方法就是使用容器產生這三種 FTP 的環境。 今天就要來說明,怎麼使用 Docker 產生這三種 FTP 環境。

使用工具說明

此篇會說明使用 pure-ftpd 建立 FTP 環境,atmoz/sftp 建立 SFTP 環境。 使用 FileZilla FTP 工具測試連線,以及使用 OpenSSH 工具產生 SSH 金鑰。

建立 FTP Server

根據 pure-ftpd 的說明,只要執行下面的指令,你的 FTP Server 就跑起來囉。

bash
  • bash
1
$ docker run -d --name ftpd_server -p 23:21 -p 30010-30019:30010-30019 -e "FTP_PASSIVE_PORTS=30010:30019" -e FTP_USER_HOME=/home/miles -e FTP_USER_NAME=miles -e FTP_USER_PASS=123456 -e "PUBLICHOST=localhost" stilliard/pure-ftpd

參數說明

參數 說明
-p 23:21 使用 host 23 port 連線到容器的 21 port。 而 21 port 是 FTP 預設的連接 port 。
-e "FTP_PASSIVE_PORTS=30010:30019" stilliard/pure-ftpd 預設使用 30000-30009 port 做資料傳輸,如果要使用預設以外的 port 做資料傳輸,則一定要設定 FTP_PASSIVE_PORTS 環境變數,此案例我改使用 30010-30019 port 做資料傳輸。
-p 30010-30019:30010-30019 這邊要特別注意的是,host 的 port 一定要跟容器設定的資料傳輸的 port 一樣,否則是無法正常運作。 以我的例子,因為資料傳輸的 port 是 30010-30019 ,所以這裡也是使用 host port 30010-30019 作對應。
-e FTP_USER_NAME=miles 使用者的帳號。
-e FTP_USER_PASS=123456 使用者的密碼。
-e FTP_USER_HOME=/home/miles 登入使用者存取的資料夾,home 的子目錄一定要是使用者帳號的名稱,否則會有權限無法存取的問題。 以我的例子,使用者帳號是 miles ,所以我要設定資料夾路徑是 /home/miles
-e "PUBLICHOST=localhost" 我是本地開發使用,沒有要提供其他電腦存取,則可以設定為 PUBLICHOST=localhost。 如果此 FTP Server 要給其他電腦使用的話,一定要設定為 host 的對外 IP,以我電腦 IP 192.168.2.103 為例,所以就要設定 PUBLICHOST=192.168.2.103

作者有提供 docker-compose 範例: https://github.com/stilliard/docker-pure-ftpd/blob/master/docker-compose.yml

啟用 FTP Server 後,成功連線圖

建立 SFTP Server,使用帳號密碼登入

根據 atmoz/sftp 的說明,只要執行下面的指令,你的 SFTP Server 就跑起來囉,SSH 金鑰預設都會自動產生。

bash
  • bash
1
$ docker run -p 2223:22 -d atmoz/sftp miles:123456:::upload

參數說明

參數 說明
-p 2223:22 使用 host 2223 port 連線到容器的 22 port。 而 22 port 是 SFTP 預設的連接 port
miles:123456:::upload 這是設定帳號、權限、資料夾的指令格式,格式是 帳號:密碼:uid:gid:子資料夾子資料夾會建立在 /home 資料夾底下,這一定要設定,因為建立的使用者沒辦法在 /home 資料夾底下寫檔案,預設情況下,只能在此子資料夾寫檔案。

啟用 SFTP Server 後,成功連線圖

建立 SFTP Server,使用 SSH 金鑰登入

使用 SSH 金鑰登入會稍微麻煩一點,我把步驟拆解如下

  1. 產生一組 public/private SSH 金鑰
  2. 寫一個 Dockerfile 將 public key 複製到 atmoz/sftp 的指定資料夾底下,並使用 docker build 產生新的 Image
  3. 執行步驟 2 建立的 Image 與 使用 FileZilla 加 SSH 金鑰連線

1. 建立 public/private SSH 金鑰

atmoz/sftp 裡面有提到建立 SSH 金鑰,可以使用 OpenSSHssh-keygen 指令。 而我這邊使用 RSA 加密演算法 產生金鑰。

bash
  • bash
1
$ ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key

指令執行完就會產生一對 public/private key 了

rsa_keyrsa_key

這邊要注意的是 Enter passphrase (empty for no passphrase):,這是在建立金鑰的時候會問你要不要輸入 private key 的密碼,如果有設定的話,在使用 private key 登入的時候會請你輸入 private key 的密碼,如果保留空白的話,則不會要求輸入密碼。

2. 將 public key 放到容器裡面

atmoz/sftp 裡面有提到說,要把 public key 放在 /home/{username}/.ssh/keys/ 底下,而我的 usernamemiles ,所以會放在 /home/miles/.ssh/keys/ 底下,為了完成這件事情,我會建立一個 Dockerfile 做兩件事情

  1. 先把 /home/miles/.ssh/keys/ 資料夾建立出來
  2. 將剛剛產生的 public key ssh_host_rsa_key.pub 複製到 /home/miles/.ssh/keys/
Dockerfile
  • Dockerfile
1
2
3
FROM atmoz/sftp
RUN mkdir -p /home/miles/.ssh/keys
COPY ./ssh_host_rsa_key.pub /home/miles/.ssh/keys/

寫好 Dockerfile 後,只要執行 $ docker build . -t mysftp 就可以把 Image 建立好,如下圖

build_imagebuild_image

3. Run Image 與使用金鑰連線

執行下方指令,將容器執行起來

bash
  • bash
1
docker run -p 2223:22 -d mysftp miles::::upload

可以注意我使用 miles::::upload 當作參數,這代表我使用者 miles 沒有設密碼,這是為了強迫使用者 miles 使用 private key 登入。

再到 FileZilla 的 setting 加入剛剛產生的 private key

fz_settingfz_setting

add_keyadd_key

設定完後,就可以成功使用 SSH 金鑰登入了。

ssh-loginssh-login

使用 Docker-Compose

最後附上寫好的 Docker-Compose ,只要將專案 clone 下來,執行 $ docker-compose up ,此篇說明的三種 FTP Server 就都會執行起來了。

延伸閱讀

[解說 FTP Protocol 的運作原理]