こんにちは、てつです!
前回の記事では、GitHub Actions(ギットハブ・アクションズ)のデプロイ結果をDiscord(ディスコード)へ自動通知する仕組みを解説しました 。
記事のリンクはこちら[【自宅サバ】GitHub Actionsのデプロイ結果をDiscordへ自動通知する設定3ステップ]
スマホに「デプロイ成功!」とリアルタイムに飛んでくるプッシュ通知の快感、もう体験していただけましたか?
さて、手軽に本格的なDevOps(デブオプス:開発と運用の連携を高める手法)環境が手に入る「自宅サーバー(ホームラボ)」。
平日の夜や休日にコツコツ構築した環境で、Wiki.jsにナレッジを蓄積したり、自作ツールを動かしたりするのは最高に楽しい時間ですよね 。
しかし、ここで皆さんに1つの恐ろしい質問をさせてください。
「もし今、自宅サーバーのディスクが突然死したり、OSがクラッシュしたりしたら、中のデータはどうなりますか?」
「バックアップは手動でそのうちやろう……」そう思って後回しにしていませんか?
物理ハードウェアのトラブルは、ある日突然、前触れもなくやってきます。せっかく作った環境や蓄積したデータが一瞬で消え去ったとき、私たちのモチベーションは完全にゼロになります 。
クラウドストレージを個別に有料契約してスクリプトを組むのは少しハードルが高い…… 。
そんな悩みを抱えるあなたに、今回は「サーバーが物理的に大破しても、数分で環境を100%完全復元できるプロ仕様の自動運用サイクル」を伝授します 。
プロのインフラエンジニアが現場で実践しているInfrastructure as Code(IaC:コードによるインフラ管理)の思想とデータ保護を融合させ、完全無料で「鉄壁のバックアップ体制」を構築しましょう!
なぜやるのか?プロが自宅サーバーのバックアップにGitHubを選ぶ理由
具体的な手順に入る前に、なぜ今回「GitHubへの自動プッシュ」という手法を採用するのか、そのロジック(理由)を解説します。
ここを理解することが、手順を丸暗記するだけの初心者から、応用が効く中級者へステップアップするための最重要ポイントです。
インフラの世界には、ディサスタリカバリ(災害復旧)という概念があります。万が一、データセンターが火災や地震で物理的に消滅しても、別の安全な拠点(クラウドなど)にデータがあればシステムは即座に復元できます 。
今回の設計思想は以下の通りです:
- 設定(コード)とデータ(DB)を分離してGit管理に落とし込む
Docker Composeの設定ファイルだけでなく、データベース(DB)の中に溜まった可変データも自動でダンプ(抽出)して、まとめてGitHubのPrivateリポジトリ(非公開のデータ保存庫)へ格納します 。 - 定時実行(cron)をクラウド側で集中管理する
サーバー内部のcron(定時実行ツール)だけに頼ると、「サーバー自体が停止していたらバックアップが動かない」「実行ログが残らない」という問題が起きます。
今回は、GitHub Actionsのcronトリガー機能(定時実行スケジュール機能)を使用します 。
クラウド側から自宅サーバーを定期的に叩き起こしてバックアップを実行させることで、プロと同じ一元管理されたクリーンなワークフローが実現します 。
これにより、「自宅サーバーが物理的に燃えても、クラウド側に知識とデータが100%残る」という絶対的な安心感が手に入ります 。さらに、前回の設定を活かし、「バックアップの成功・失敗」もDiscordへリアルタイムにプッシュ通知させます 。
自宅サーバー自動バックアップ環境の構築に必要なツールと前提条件
本環境を作るために、以下の環境が整っていることを前提とします:
- 自宅サーバー(Linux環境、Docker / Docker Composeが導入済みであること)
- GitHubアカウント(バックアップ先として、自分だけが見られる「Privateリポジトリ」を作成しておきます)
- Discordアカウント(前回の記事で作成したWebhook URLをそのまま使用します)
👉 【前回の記事】[【自宅サバ】GitHub Actionsのデプロイ結果をDiscordへ自動通知する設定3ステップ] をまだ読んでいない方は、まずこちらから環境を作ってみてください!
ステップ1:自宅サーバー側の設定(Docker DBダンプと定時実行スクリプト
次に、サーバー内のデータを安全に整理してGitにコミットするためのシンプルなシェルスクリプト(自動化コマンド集)を作成し、それを朝4:00に自動起動するYAMLファイルを作成します 。
1. 自宅サーバー側のバックアップスクリプト作成
Dockerコンテナで動いているデータベース(例: PostgreSQLやMySQL)から、データを安全にダンプ(抽出)するコマンドを含んだスクリプトをサーバー内に配置します 。
サーバーの任意のディレクトリ(例: /home/user/backup.sh)に以下のスクリプトを作成します。
#!/bin/bash
# 1. バックアップ対象のディレクトリへ移動
cd /home/user/homelab
# 2. DockerコンテナのDBからデータを安全にダンプ(抽出)
# docker compose execを実行し、コンテナ内のpg_dumpを使ってデータを抽出します
docker compose exec -T db-container pg_dump -U db-user my_database > ./backup/db_dump.sql
# 3. 抽出したデータファイルをGitの追跡対象に追加
git add ./backup/db_dump.sql
# 4. 日時をコミットメッセージにしてコミット
git commit -m "Auto Backup: $(date +'%Y-%m-%d %H:%M:%S')"
【1行ずつ解説!】
#!/bin/bash- このファイルがLinuxの「Bash」というシェルで実行されるスクリプトであることを宣言しています。
cd /home/user/homelab- Docker ComposeのファイルやGitリポジトリが置かれている作業ディレクトリへと移動しています。
docker compose exec -T db-container pg_dump -U db-user my_database > ./backup/db_dump.sqldocker compose execは稼働中のコンテナ内でコマンドを実行する命令です。-Tオプション(※後述の補足参照)をつけ、db-containerという名前のDBコンテナ内でpg_dump(データベース抽出コマンド)を実行し、その中身を./backup/db_dump.sqlというファイルとしてサーバー側に保存(出力)しています。
git add ./backup/db_dump.sql- 新しく抽出・更新されたバックアップファイルを、Gitの管理対象(ステージングエリア)に追加しています。
git commit -m "..."- 現在の「日付と時刻」を自動的にメッセージ(例:
Auto Backup: 2026-06-12 04:00:00)として付与し、ローカル環境のGitリポジトリに保存を確定させています。
- 現在の「日付と時刻」を自動的にメッセージ(例:
2. プロ仕様のワークフローファイル(YAML)の作成
GitHub Actionsのリポジトリ側(.github/workflows/backup.yml)に、毎朝4:00にフルオートで起動し、バックアップを実行してDiscordへ通知するワークフローファイルを書き込みます 。
name: server-ops Backup
"on":
schedule:
- cron: '0 19 * * *'
workflow_dispatch:
jobs:
backup:
runs-on: self-hosted
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Run backup script
run: |
chmod +x backup.sh
./backup.sh
- name: Push backup to GitHub
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git push origin main
- name: Send Discord Notification
if: always()
uses: tsickert/discord-webhook@v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK }}
content: |
Backup workflow finished with status: ${{ job.status }}.
Repository: ${{ github.repository }}
トリガー設定(1〜5行目)
- 1行目(
name: ...)- GitHubの管理画面に表示される、この自動化処理の識別名です。
- 2行目(
"on":)- この自動化処理を「どういうタイミングで起動するか」の条件を設定する構文です。
- 3〜4行目(
schedule:/- cron: ...)- 定期的に自動実行する設定です。時間は世界標準時(UTC)で指定するため、日本時間の午前2時に実行したい場合は、9時間を引いた「前日の19:00(0 19 * * *)」と記述します。
- 5行目(
workflow_dispatch:)- GitHubの画面上に「手動実行」ができるボタンを表示する設定です。テストしたい時にいつでも手動で動かせます。
ジョブ環境とマスターキー設定(7〜10行目)
- 7〜8行目(
jobs:/backup:)- ここから具体的な作業内容(ジョブ)の定義を開始します。
- 9行目(
runs-on: self-hosted)- 処理を実行する場所の指定です。GitHubのクラウドではなく、自分で用意したサーバー(Linux等)の上で処理を動かします。
- 10〜11行目(
permissions:/contents: write)- 自動発行される暗号鍵(
GITHUB_TOKEN)に対する権限設定です。自分のリポジトリに対して、変更を保存(書き込み)する権限を許可しています。
- 自動発行される暗号鍵(
ステップ1:ソースコードの取得(13〜17行目)
- 13行目(
steps:)- ここから実際に実行する具体的な作業手順を箇条書きで並べていきます。
- 14〜15行目(
- name: .../uses: ...)- GitHub公式の「ファイル取得ツール」を呼び出し、最新のプログラム一式をサーバーにダウンロード(チェックアウト)します。
- 16〜17行目(
with:/persist-credentials: true)- 11行目で許可を与えた「自動発行の鍵」のログイン状態を、後ろのステップにそのまま引き継ぐ設定です。これにより、self-hostedランナー特有の認証エラーを回避できます。
ステップ2:バックアップの実行(19〜22行目)
- 19〜20行目(
- name: .../run: |)- Linuxコマンドを上から順番に実行する手順を開始します。
- 21行目(
chmod +x backup.sh)- サーバー内にある「
backup.sh」というファイルを実行できるように準備(権限変更)しています。
- サーバー内にある「
- 22行目(
./backup.sh)- 実際にバックアップを実行するプログラム(シェルスクリプト)を起動します。
ステップ3:GitHubへの保存(24〜28行目)
- 24〜25行目(
- name: .../run: |)- 作成されたデータをGitHubに送信(Push)する手順を開始します。
- 26〜27行目(
git config --global ...)- ファイルを保存する人の「名前」と「メールアドレス」を、GitHubの自動ロボット(github-actions[bot])として登録しています。
- 28行目(
git push origin main)- キャッシュの邪魔を受けない最も標準的なコマンドです。メインの保存先(mainブランチ)へデータを安全に送信します。
ステップ4:Discordへの結果通知(30〜36行目)
- 30行目(
- name: Send Discord Notification)- 結果をDiscordに送信する手順です。
- 31行目(
if: always())- 手前のバックアップ処理が成功しても失敗しても、途中で止めずに「必ず常に」この通知を実行する設定です。
- 32〜34行目(
uses: .../with:/webhook-url: ...)- Discordへ安全にメッセージを送信してくれる外部の公開ツールを呼び出し、事前に画面で登録しておいた通知先URL(Webhook)を読み込んでいます。
- 35〜37行目(
content: |/ メッセージ本文)- Discordに送信される本文です。
${{ job.status }}には実行結果(success等)、${{ github.repository }}には対象のリポジトリ名が自動で当てはまります。
- Discordに送信される本文です。
ステップ2:動作確認とDiscordへの自動通知テスト
設定が完了したら、いよいよお楽しみの動作確認です!
GitHubリポジトリの Actions タブを開くと、左側に 例:server-ops Backup というワークフローが表示されています。

それを選択し、右側に現れる Run workflow ボタンをクリックして手動でトリガーしてみてください 。

数秒後……あなたのスマホのDiscordが「ピコン!」と鳴り、「Backup workflow finished with status: success」というリアルタイム通知が飛んできたら大成功です!

GitHubリポジトリのコミット履歴を確認すると、朝4:00のタイムスタンプとともに、最新のDBダンプデータが綺麗に整理されて保存されているはずです 。
現役インフラエンジニアが教える「プロ仕様」の設計思想とセキュリティ注意点
今回の構成が、なぜただの趣味レベルを超えた「プロ仕様」と言えるのか、現役エンジニアとしての視点から2つのポイントをお伝えします。
- インフラの流行「GitOps」の体験
インフラの設定やデータをすべてGitリポジトリで管理し、Gitへのプッシュをトリガーに自動運用を行う仕組みをGitOps(ギットオプス)と呼びます。
今回の構成を作れたあなたは、エンタープライズ(企業向け)の現場でも導入が進んでいる最先端のDevOps手法を、自分の手で実装したことになります。 - セキュリティ上の最重要注意点
今回、バックアップ対象にパスワードやAPIキーなどの「生データ(機密情報)」が直接含まれていないか、必ず確認してください 。
機密情報は必ず環境変数(.envファイルなど)として切り離し、.gitignore(Gitの管理から除外する設定ファイル)に登録してGitHubへコミットされないようにするスタイルがプロの鉄則です 。また、リポジトリの設定が絶対に「Private(非公開)」になっていることを二重、三重に念押ししてチェックしてください 。
補足・トラブルシューティング(エラーハンドリング集)
自宅サーバー環境はネットワークや権限の設定が人それぞれ異なるため、一発で動かないことも多々あります。
エラーが発生した際は、答えを急ぐ前に「エラーメッセージのどこに注目すべきか」をまず確認しましょう。よくあるトラブルと対処法をまとめました 。
Q1. Actionsのログに the input device is not a TTY と出てDB抽出に失敗する
- 注目すべきエラー箇所:
not a TTYという文言に注目してください。 - 原因と対策:
docker compose execコマンドは、標準では人間がキーボード入力を行うための「対話モード(TTY)」を要求します。しかし、GitHub Actionsなどの自動スクリプトから実行する場合、入力デバイスが存在しないためこのエラーになります。対策として、コマンドに-Tオプション(TTYを無効化する魔法の引数)を必ず付与してください。- ❌ 修正前:
docker compose exec db-container pg_dump ... - ⭕️ 修正後:
docker compose exec -T db-container pg_dump ...
- ❌ 修正前:
Q2. Permission denied(権限エラー)でスクリプトが実行されない
- 注目すべきエラー箇所: スクリプト実行ステップで出る
Permission deniedやcommand not found。 - 原因と対策: 作成した
backup.shファイルに「実行権限」が与えられていないことが原因です。Linux環境では、新しく作ったファイルはただのテキストとして扱われます。ワークフローの実行前にchmod +x ./backup.shコマンド(ファイルに実行権限を付与する命令)を明示的に実行させるか、サーバー側であらかじめ権限を付与しておくことで解決します。
Q3. バックアップが成功しているのに Discord に通知が来ない
- 注目すべきエラー箇所: ワークフロー全体の最後、
Discord Notificationステップのログ。 - 原因と対策: GitHubのSecretsに登録した
DISCORD_WEBHOOKの名前に、スペースなどの余計な文字が入っていないか、またはWebhook URLのコピーが途中で途切れていないか確認してください。また、前回の記事 で解説した通り、Discord側のチャンネル設定でWebhookが削除されていないかも合わせて確認が必要です。
最後に
最高のデータ保護環境(ホームラボの要塞化)がこれで完成しました!
これで明日から、どれだけアグレッシブに自宅サーバーの設定をいじくり回して壊しても、一瞬で元通りに復元できます 。
一歩ずつプロのインフラエンジニアの環境へと近づいていく楽しさを、ぜひこれからも一緒に味わっていきましょう。
また、今回の連載で構築する「自宅自動化環境」のより高度なエラーハンドリング集や、ワンクリックで環境を爆速構築できる「自動化シェルスクリプトの完成版テンプレート」は、将来的にnoteにて販売も予定しています。
気になる方は今のうちにブログのブックマークとnoteのフォローをお願いします!
それでは、また次回の記事でお会いしましょう!



コメント