こういった手作業のミスは、サーバーが2台でも10台でも確実に起きる。とくに同じ設定ファイルを複数のサーバーへ展開する作業は、コピーミス・権限ミス・バックアップ漏れの温床だ。
この記事では、Ansibleの
copyモジュールとfileモジュールを使って、設定ファイルの配布・権限設定・バックアップを冪等に自動化する方法を解説する。RHEL 9.4 / Rocky Linux 9環境で動作確認済み。基本的なPlaybookの構造は理解している前提で、実務で即使える設計パターンを中心に説明する。この記事のポイント
・copyモジュールはコントロールノードのファイルをリモートサーバーへ冪等に配布する
・backup: yesを指定すると上書き前に元ファイルが自動でバックアップされる
・fileモジュールはstate: directory/link/absentでディレクトリ・リンク・削除を冪等管理できる
・fetchモジュールでリモートの設定ファイルをコントロールノードへ一括回収できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Ansibleのファイル操作で発生しがちな問題
手作業でサーバーに設定ファイルを配布する場合、以下の問題が繰り返し発生する。・古いファイルをバックアップせず上書きしてしまい、ロールバックできなくなる
・
chmodやchownを忘れてサービスが起動しない・10台のうち1台だけ古い設定が残り、動作が異なる
・どのサーバーに何のバージョンが入っているか追跡できない
Ansibleの
copyモジュールとfileモジュールを正しく使えば、これらを一括で解消できる。いずれも冪等性(何度実行しても結果が同じになる性質)を持っているため、意図しない二重変更が発生しない。copyモジュールで設定ファイルを複数サーバーへ配布する
1. copyモジュールの基本構文
copyモジュールは、コントロールノード(Ansibleを実行するサーバー)側のファイルを、リモートホスト側の指定パスへコピーする。# files/postfix/main.cf を複数サーバーの /etc/postfix/main.cf へ配布 - name: postfix main.cf を配布する copy: src: files/postfix/main.cf dest: /etc/postfix/main.cf owner: root group: root mode: '0644'
・src:コントロールノード側のファイルパス(Playbookからの相対パスまたは絶対パス)
・dest:リモートホスト側の配置先パス
・owner / group:コピー後のファイル所有者とグループ
・mode:コピー後のパーミッション(
'0644'のようにクォートした文字列で指定する)・content:srcの代わりに直接ファイル内容を文字列で指定できる(短い設定ファイルに便利)
実行すると以下のように出力される。ファイルに差分がある場合は
changed、すでに同じ内容ならok(変更なし)になる。$ ansible-playbook -i hosts.yaml site.yml TASK [postfix main.cf を配布する] **** changed: [192.168.10.11] changed: [192.168.10.12] ok: [192.168.10.13] # すでに同じ内容のため変更なし PLAY RECAP ***** 192.168.10.11 : ok=2 changed=1 unreachable=0 failed=0 192.168.10.12 : ok=2 changed=1 unreachable=0 failed=0 192.168.10.13 : ok=1 changed=0 unreachable=0 failed=0
192.168.10.13はすでに最新の設定が配布済みだったため変更されていない。これが冪等性の動作だ。2. backup: yesで元ファイルを上書き前に自動退避する
本番サーバーへ設定ファイルを配布する場合、上書き前に元ファイルをバックアップしておきたい。backup: yesを加えると、変更が発生した場合に自動でバックアップファイルが生成される。- name: httpd.conf を配布する(上書き前に自動バックアップ) copy: src: files/apache/httpd.conf dest: /etc/httpd/conf/httpd.conf owner: root group: root mode: '0644' backup: yes
backup: yesを指定すると、変更が発生した場合に元のファイルが以下のような名前で同じディレクトリに退避される。# バックアップ後の確認 $ ls -la /etc/httpd/conf/ -rw-r--r-- 1 root root 11764 8月 10 09:15 httpd.conf -rw-r--r-- 1 root root 11502 8月 8 14:30 httpd.conf.68494.2026-08-10@09:15:22~
cpコマンドでこのバックアップを元に戻せる。3. ディレクトリをまるごと配布する(srcのスラッシュに注意)
srcにディレクトリを指定する場合、末尾のスラッシュ有無で動作が変わる。# スラッシュなし: conf/ ディレクトリごと dest 配下にコピーされる # 結果: /etc/nginx/conf/nginx.conf のような形になる src: files/nginx/conf dest: /etc/nginx/ # スラッシュあり: conf/ の中身だけ dest に展開される # 結果: /etc/nginx/nginx.conf のような形になる src: files/nginx/conf/ dest: /etc/nginx/
rsyncコマンドと同じルールだ。「ディレクトリの中身だけを配置したい」場合はスラッシュあり、「ディレクトリ自体を配置したい」場合はスラッシュなし、と覚えておく。
Ansible実践ハンズオンの詳細を見る >>
fileモジュールでパーミッション・ディレクトリ・シンボリックリンクを一括管理する
fileモジュールは、ファイルやディレクトリの「属性」(パーミッション・所有者・グループ・シンボリックリンク・存在有無)を冪等に管理するモジュールだ。copyと組み合わせることで、「ファイルを配布して、権限を正しく設定する」という一連の作業をPlaybookで完結させられる。1. fileモジュールの基本構文
# 既存ファイルのパーミッションと所有者を設定する - name: /var/log/app のパーミッションを設定する file: path: /var/log/app/access.log owner: nginx group: nginx mode: '0640'
stateパラメータを指定しない場合、対象パスの現在の状態(ファイル・ディレクトリ・リンク)を変更せず、属性だけを変更する。2. state: directoryでディレクトリを冪等に作成する
state: directoryを指定すると、ディレクトリが存在しない場合は作成し、すでに存在する場合は属性のみ変更する。mkdir -p相当の動作だ。# アプリケーションのログディレクトリを作成する - name: ログディレクトリを作成する file: path: /var/log/myapp state: directory owner: appuser group: appuser mode: '0755' # 配布前にディレクトリを先に作成するパターン(依存関係が明確になる) - name: nginx設定ディレクトリを用意する file: path: /etc/nginx/conf.d state: directory owner: root group: root mode: '0755' - name: nginx仮想ホスト設定を配布する copy: src: files/nginx/vhost.conf dest: /etc/nginx/conf.d/vhost.conf owner: root group: root mode: '0644'
fileタスクを先に置くことで、「配布先ディレクトリがない」エラーを防げる。3. state: linkでシンボリックリンクを管理する
state: linkを指定すると、srcからpath(またはdest)へのシンボリックリンクを作成する。# /etc/nginx/sites-enabled/default -> /etc/nginx/sites-available/default - name: Nginx仮想ホストを有効化する(シンボリックリンク) file: src: /etc/nginx/sites-available/default dest: /etc/nginx/sites-enabled/default state: link owner: root group: root
ok、存在しなければchanged(リンク作成)になる。4. state: absentでファイルを冪等に削除する
state: absentを指定すると、対象パスが存在する場合に削除する。存在しない場合は何もしない(冪等)。# 不要な設定ファイルを削除する - name: デフォルトのNginx設定を無効化する file: path: /etc/nginx/sites-enabled/default state: absent # 古いバックアップファイルを削除する - name: 旧バージョンの設定ファイルを除去する file: path: /etc/httpd/conf/httpd.conf.old state: absent
fetchモジュールでリモートサーバーの設定を手元に回収する
fetchモジュールはcopyの逆方向だ。リモートサーバー側のファイルをコントロールノード側へ回収する。本番サーバーの現在の設定をまとめてバックアップしたい場合に使う。1. fetchモジュールの基本構文とflat: trueの使い分け
# リモートの /etc/nginx/nginx.conf をコントロールノードへ回収する(デフォルト) # 保存先: ./backup/192.168.10.11/etc/nginx/nginx.conf - name: Nginx設定を回収する fetch: src: /etc/nginx/nginx.conf dest: ./backup/ flat: no # デフォルト: ホスト名ディレクトリ配下に保存される # flat: yes の場合 # 保存先: ./backup/nginx.conf(ホスト名ディレクトリは作成されない) # 複数ホストから回収すると上書きされるため注意 - name: Nginx設定を回収する(flat形式) fetch: src: /etc/nginx/nginx.conf dest: ./backup/nginx.conf flat: yes
flat: no(デフォルト)にしておくことを推奨する。flat: yesは単一ホストからの回収か、ループでホストごとにファイル名を変えるケースで使う。2. 複数ホストから設定ファイルを一括回収する実践パターン
# 全Webサーバーから現在の設定を一括回収してバックアップする - name: 本番Webサーバーの設定を回収する fetch: src: /etc/httpd/conf/httpd.conf dest: ./backup/{{ inventory_hostname }}/httpd.conf flat: yes
$ ansible-playbook -i hosts.yaml fetch_configs.yml TASK [本番Webサーバーの設定を回収する] ***** changed: [web01.example.internal] changed: [web02.example.internal] changed: [web03.example.internal] # 回収後のディレクトリ構造 $ tree backup/ backup/ ├── web01.example.internal │ └── httpd.conf ├── web02.example.internal │ └── httpd.conf └── web03.example.internal └── httpd.conf
diff backup/web01.example.internal/httpd.conf backup/web02.example.internal/httpd.confで差分を確認できる。実務パターン:Postfix設定の一括配布と権限設定
実際の現場ではcopyとfileを組み合わせて1つのroleまたはPlaybookにまとめることが多い。Postfix設定の配布を例にすると以下のようになる。Postfixの基本設定については「Postfix の基本設定の解説」を参照してほしい。
--- - name: Postfix設定の配布と権限設定 hosts: mail_servers become: yes tasks: # 1. 配布前のバックアップ - name: 現在のmain.cfを回収する fetch: src: /etc/postfix/main.cf dest: ./backup/{{ inventory_hostname }}/main.cf flat: yes # 2. 設定ファイルを配布(上書き前に自動バックアップ) - name: main.cf を配布する copy: src: files/postfix/main.cf dest: /etc/postfix/main.cf owner: root group: postfix mode: '0640' backup: yes notify: postfix を再起動する # 3. キューディレクトリのパーミッション確認 - name: Postfixキューディレクトリの権限を設定する file: path: /var/spool/postfix state: directory owner: root group: postfix mode: '0755' handlers: - name: postfix を再起動する service: name: postfix state: restarted
$ ansible-playbook -i hosts.yaml postfix_deploy.yml --diff TASK [main.cf を配布する] ***** --- before: /etc/postfix/main.cf +++ after: /home/ansible/.ansible/tmp/ansible-tmp-.../main.cf @@ -71,6 +71,7 @@ myhostname = mail.example.internal +mynetworks = 192.168.10.0/24 changed: [mail01.example.internal] RUNNING HANDLER [postfix を再起動する] ***** changed: [mail01.example.internal] PLAY RECAP ***** mail01.example.internal : ok=4 changed=2 unreachable=0 failed=0
--diffオプションを付けると変更内容がdiff形式で表示されるため、適用前に変更箇所を確認できる。よくあるエラーと対処法
「Permission denied」が出た時の確認手順
fatal: [192.168.10.11]: FAILED! => { "msg": "Destination /etc/nginx/nginx.conf not writable" }
become: yesの設定を確認する。Playbook全体またはタスク単位でbecomeを指定していないと、接続ユーザー権限でのコピーとなるため権限エラーになる。# Playbook全体にbecome: yesを付ける - name: Nginx設定配布 hosts: web become: yes # これを追加 tasks: - name: nginx.conf を配布する copy: src: files/nginx/nginx.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644'
srcのスラッシュ有無でディレクトリ配布の挙動が変わる罠
# スラッシュなし: files/conf ディレクトリ自体が /etc/nginx/conf として作成される # 結果: /etc/nginx/conf/nginx.conf - copy: src: files/conf dest: /etc/nginx/ # スラッシュあり: files/conf/ の中身が /etc/nginx/ 配下に展開される # 結果: /etc/nginx/nginx.conf - copy: src: files/conf/ dest: /etc/nginx/
--diffと--checkを組み合わせて実行前に確認することを習慣にしてほしい。# 本番適用前のdry-run確認 $ ansible-playbook -i hosts.yaml site.yml --check --diff
本記事のまとめ
| やりたいこと | モジュール・設定 |
|---|---|
| 設定ファイルを複数サーバーへ配布する | copy: src: ... dest: ... |
| 上書き前に元ファイルを自動退避する | copy: backup: yes |
| パーミッション・所有者を設定する | copy: owner: ... group: ... mode: ... |
| ディレクトリを冪等に作成する | file: state: directory |
| シンボリックリンクを作成する | file: state: link src: ... dest: ... |
| ファイルを冪等に削除する | file: state: absent |
| リモートの設定ファイルを手元に回収する | fetch: src: ... dest: ... |
| ディレクトリ全体を配布する | copy: src: .../(スラッシュあり)dest: ... |
copyでファイルを配布し、fileで属性を管理し、fetchでバックアップを回収する。この3つの組み合わせで、手作業によるミスをほぼゼロにできる。まずは自分のチームで最もよく使う設定ファイル(Nginx、Postfix、Samba等)の1種類から始めて、Playbookに落とし込む習慣をつけてほしい。Samba設定ファイルの配布例については「Samba バージョン確認の方法」も合わせて参照してほしい。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Ansible・Puppet・Chefの違いを比較する|エージェントレス構成管理を選ぶ判断基準と導入設計
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます