ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

「さくらのレンタルサーバ」用の FTP GitHub Actions でハマった話

1. FTP を使うしかない!

ホームページに「さくらのレンタルサーバ」を使っているのですが、
1番安い「ライトプラン」だと、SSHログインができず、
ファイルアップロードの手段が昔懐かしの FTP しかないんですよね。
(参考: 各プランの機能比較ページ )

なので、Windows でも macOS でも扱える FTP ソフトの FileZilla や Cyberduck 、
Windows ユーザーであれば昔ながらの FFFTP を使っています。

余談ですが、FFFTP は、SSL対応が難しく、オリジナルの作者である Sota さんは開発をやめてしまい、
セキュリティ観点で使用は非推奨とみなされていた時期もあるのですが、
開発を引き継ぐ方々が表れ、現在は sayurin さんが主にメンテナンスしています。
→ https://github.com/ffftp/ffftp

2. GitHub Actions で自動化したい……が!!

ホームページを久しぶりに更新するにあたり、
ファイルを変更するたびに FileZilla を開いてアップロードするのもめんどくさいな〜と思うようになってきて、
なんとか GitHub Actions で自動化できないかと考えるようになってきました。

で、ありました!

SamKirkland さんが作っていらっしゃる FTP-Deploy-Action です!

……が、上手くいかない!

Error: Server sent FIN packet unexpectedly, closing connection.
    at Socket.<anonymous> (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/v4.3.5/dist/index.js:5109:56)
    at Socket.emit (node:events:536:35)
    at endReadableNT (node:internal/streams/readable:1698:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Error: Error: Server sent FIN packet unexpectedly, closing connection.

このエラーが何度やっても出てきてしまいました。

Issue を見ていたら、この Action の元となる SamKirkland/ftp-deploy に passive のオプションがないのが原因かも?
と考察しているコメントもあったので、いったん別のツールを試してみることにしました。
(※その後に判明した原因から考えるに、 FTP-Deploy-Action にはなんの問題もないと思います)

次に使用したのが rclone です。
FTP機能部分がどのくらい更新されているかは見ていませんが、
頻繁にリポジトリのコミットがおこなわれているため、安心そうかなと思いました。

で、それ用の GitHub Actions を書いてみたのですが、やっぱり上手くいかない!! つらい!!

CRITICAL: Failed to create file system for "myftp:/home/***/www/": NewFs: failed to make FTP connection to "***.sakura.ne.jp:21": EOF
Error: Process completed with exit code 1.

ただ、先ほどのツールと違って rclone はより原始的なツールなので、
rclone ls のコマンドが失敗するなどを試すことで、
アップロード以前に FTP サーバーとの疎通が上手くおこなえていないということが判明していきました。

調査にあたっては、GitHub Actions への SSH ログインすることを可能にする
action-tmate も非常に役立ちました。

3. GitHub Actions の失敗する意外な理由が判明!

ChatGPT と話しながらデバッグを進めていく中で、
「 rclone --log-level=DEBUG --dump bodies lsf myftp: の実行ログを見る感じ、
 TLS ハンドシェイクは成功してるっぽいから、実はサーバー側のIP制限もあるんじゃね?」
という一説を挙げてくれました。

「IP制限はないんじゃないかな」と思って、他に挙げてくれた要因の調査をしばらくは進めていたのですが、
落ち着いて調べてみると、 さくらのレンタルサーバのIPアドレス制限、ありました……!

この記事が役立ちました! 感謝!!
→ 『GitHub Actionsで「さくらのレンタルサーバ」にFTPしようと思ったらドツボにハマって3日3晩寝不足になった話 - ユニファ開発者ブログ』

さくらのレンタルサーバにある「国外IPアドレスフィルター」の設定をオフにすることで、すべては解決したのです!
こいつかぁぁぁっ!!

ちなみに、それの設定ページで「許可リスト」という設定項目があって、
「これに GitHub の持つIPアドレスを設定すればいいのか〜」と思ったんですがそうではなく、
『許可リストが適用される対象はウェブアクセス(HTTP/HTTPS 特定ファイルのみ)』で、FTPアクセスは関係ないらしいです。
/wp-admin/ などの一部のパスへの海外アクセスを許可したい場合に使うそうな……。
(参考: https://help.sakura.ad.jp/rs/2234/#heading-2 )

4. 設定した GitHub Actions を公開します

最後に、自分の作成した GitHub Actions を公開します。

name: Deploy Website via FTP

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy:
    name: Deploy via FTP
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Install rclone
        run: |
          curl https://rclone.org/install.sh | sudo bash
      - name: Create exclude list
        run: |
          echo ".DS_Store" > exclude-list.txt
          echo "Thumbs.db" >> exclude-list.txt
          echo "desktop.ini" >> exclude-list.txt
          echo ".git/**" >> exclude-list.txt
      - name: Configure rclone for FTP
        run: |
          rclone config create myftp ftp \
            host=${{ secrets.FTP_USERNAME }}.sakura.ne.jp \
            port=21 \
            user=${{ secrets.FTP_USERNAME }} \
            pass=$(rclone obscure "${{ secrets.FTP_PASSWORD }}") \
            explicit_tls=true \
            no_check_certificate=true
      - name: Upload to FTP server
        run: |
          rclone sync ./dist/ myftp:/home/${{ secrets.FTP_USERNAME }}/www/ \
            --checksum \
            --exclude-from exclude-list.txt \
            --delete-during \
            --verbose

secrets.FTP_USERNAME と secrets.FTP_PASSWORD は、
GitHub Actions のシークレット環境変数として設定させています。

ポイントは、 rclone sync 内の --checksum オプションです。
rclone sync はミラーリングアップロードのようなことができて、
ローカル環境のファイル更新をリモート側に反応させつつ、ローカルにないファイルはリモートから削除してくれるコマンドです。

--checksum オプションを付けていないと、
GitHub Actions 内で actions/checkout をやったときにすべてのファイルは新規作成状態になるので、
rclone sync コマンドは、 すべてのファイルを、更新されたものとしてアップロードしようとしてしまいます。
これでは毎回アップロードに時間がかかってしまいます。

--checksum オプションを付けておくことで、
ファイルの変更があったのかをハッシュ値で比較してくれます。

ただ、FTPサーバーがチェックサムに対応している場合は少ないようで、
チェックサムに対応していない場合はファイルサイズの変化があったかを見て、アップロードするかを決めるようです。

私の使っているいるさくらのレンタルサーバもチェックサム機能は無いようで、
ファイルサイズの変化だけをチェックして、アップロードするかを判定します。
ファイルサイズの変化がなければFTPサーバーへのアップロードがおこなわれないことに注意が必要です。

5. おわりに

というわけで、丸一日苦しんだ GitHub Actions のエラーが、
さくらのレンタルサーバの設定を1つ変えるだけで上手くいくようになった話でした。

まさかそこに原因があったなんて……!!🤯

これは気付かなかったなあ……。
丸一日ムダにつぶれて苦しかったですので、この記事がどなたかを救うことになりましたら幸いです🙏