初めに
新規でEC2を構築する際に同一の設定を入れるケースがあると思います。(localeやtimezoneなど)
このような場合は、AnsibleやPuppetなどの構成管理ツールで管理するのもよいですが、もう少し小規模に使いたい場合はEC2構築時に設定できるUserDataという機能が選択肢に入ってきます。
この記事ではUserDateの使って起動時にコマンドを実行させる方法について解説します。
初めに
OSは「AmazonLinux 2023」を使います。
まずは何も設定しなかった場合の初期状態を確認します。
sh-4.2$ date
Mon Nov 3 09:58:44 UTC 2025
sh-4.2$ timedatectl
Local time: Mon 2025-11-03 09:58:47 UTC
Universal time: Mon 2025-11-03 09:58:47 UTC
RTC time: Mon 2025-11-03 09:58:47
Time zone: n/a (UTC, +0000)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
sh-4.2$ localectl status
System Locale: LANG=en_US.UTF-8
VC Keymap: n/a
X11 Layout: n/a
sh-4.2$
- timezon ⇒ UTC
-
locale ⇒ en_US.UTF-8(米国における英語表記)
が設定されていることが確認できました。
UserDataを記載してみる
実際にUserDataを書いてみる前に公式ドキュメントは👇になります。必要に応じて確認してください。
ではそれぞれ下記のコマンドをUserDataに記載し、起動時に日本語化してもらいましょう。
sudo timedatectl set-timezone Asia/Tokyo
sudo localectl set-locale LANG=ja_JP.UTF-8
▼マネコンからの設定
インスタンス起動の画面の 「高度な詳細」の最下部>「ユーザーデータ-オプション」 の箇所に記載していきます。
▼Terraformで設定する場合は、EC2のセクションに下記記載を追加します。
user_data = <<-EOF
#!/bin/bash
sudo timedatectl set-timezone Asia/Tokyo
sudo localectl set-locale LANG=ja_JP.UTF-8
EOF
EC2の起動が終わったので確認してみます。公式ドキュメントにも記載がありますが、UserDataに記載されたコマンドはcloud-initを介して実行されます。/var/log/cloud-init.logに「finish: modules-final: SUCCESS」があれば正常に完了しているはずです。
※最下行に記載があります。
sh-4.2$ tail -f /var/log/cloud-init.logNov 03 10:31:29 cloud-init[2344]: cc_power_state_change.py[DEBUG]: no power_state provided. doing nothingNov 03 10:31:29 cloud-init[2344]: handlers.py[DEBUG]: finish: modules-final/config-power-state-change: SUCCESS: config
-power-state-change ran successfullyNov 03 10:31:29 cloud-init[2344]: main.py[DEBUG]: Ran 9 modules with 0 failures
Nov 03 10:31:29 cloud-init[2344]: atomic_helper.py[DEBUG]: Atomically writing to file /var/lib/cloud/data/status.json(via temporary file /var/lib/cloud/data/tmpouAyar) - w: [644] 915 bytes/chars
Nov 03 10:31:29 cloud-init[2344]: atomic_helper.py[DEBUG]: Atomically writing to file /var/lib/cloud/data/result.json(via temporary file /var/lib/cloud/data/tmpOQ7Zwz) - w: [644] 400 bytes/chars
Nov 03 10:31:29 cloud-init[2344]: util.py[DEBUG]: Creating symbolic link from '/run/cloud-init/result.json' => '../../
var/lib/cloud/data/result.json'Nov 03 10:31:29 cloud-init[2344]: util.py[DEBUG]: Reading from /proc/uptime (quiet=False)
Nov 03 10:31:29 cloud-init[2344]: util.py[DEBUG]: Read 12 bytes from /proc/uptime
Nov 03 10:31:29 cloud-init[2344]: util.py[DEBUG]: cloud-init mode 'modules' took 0.284 seconds (0.29)Nov 03 10:31:29 cloud-init[2344]: handlers.py[DEBUG]: finish: modules-final: SUCCESS: running modules for final
^C
sh-4.2$
ということでUserDataはうまく実行されてくれたみたいなので本当に設定がうまくされているか確認してみます。
sh-4.2$ timedatectl
Local time: Mon 2025-11-03 19:51:48 JST
Universal time: Mon 2025-11-03 10:51:48 UTC
RTC time: Mon 2025-11-03 10:51:48
Time zone: Asia/Tokyo (JST, +0900)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
sh-4.2$ localectl status
System Locale: LANG=ja_JP.UTF-8
VC Keymap: n/a
X11 Layout: n/a
sh-4.2$
timezoneがAsia/Tokyoに、localeがja_JP.UTF-8になっていることが確認できました。
すでに起動してるインスタンスは?
上述していますが、UserDataは基本的にEC2の起動時にコマンドを実行するのに用います。
が、気になって調べてみたところ一応EC2の初回起動以降、開始されたタイミングでもUserDataを実行するようにできるみたいです。
👆によるとどうやらUserDataの記載を下記に変えればいいみたいです。
Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0
--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"
#cloud-config
cloud_final_modules:
- [scripts-user, always]
--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"
####ここからUserDataを記載<-記載時は削除してください
#!/bin/bash
sudo timedatectl set-timezone Asia/Tokyo
sudo localectl set-locale LANG=ja_JP.UTF-8
####ここまで<-記載時は削除してください
--//--
せっかくなのでこちらも試してみることにします。
セットしたtimezoneとlocaleを下記に再変更してみます。
- timezone ⇒ UTC
- locale ⇒ en_US.UTF-8
ユーザーデータを編集するには対象のEC2が停止している必要があります。
停止後、「アクション」>「インスタンスの設定」>「ユーザーデータを編集」 から編集できます。
編集後、保存を押下し、EC2を再起動してみます。
再起動でもUserDataで設定したコマンドが実行されているようです。
sh-4.2$ timedatectl
Local time: Mon 2025-11-03 11:40:37 UTC
Universal time: Mon 2025-11-03 11:40:37 UTC
RTC time: Mon 2025-11-03 11:40:38
Time zone: UTC (UTC, +0000)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
sh-4.2$ localectl
System Locale: LANG=en_US.UTF-8
VC Keymap: n/a
X11 Layout: n/a
sh-4.2$
logからもUserDataが実行されているのが確認できます。
sh-4.2$ tail -f /var/log/cloud-init.log
Nov 03 11:39:04 cloud-init[2226]: util.py[DEBUG]: Running command ['/var/lib/cloud/instance/scripts/userdata.txt'] with allowed return codes [0] (shell=True, capture=False)
Nov 03 11:39:04 cloud-init[2226]: handlers.py[DEBUG]: finish: modules-final/config-scripts-user: SUCCESS: config-scripts-user ran successfully
Nov 03 11:39:04 cloud-init[2226]: main.py[DEBUG]: Ran 1 modules with 0 failures
Nov 03 11:39:04 cloud-init[2226]: atomic_helper.py[DEBUG]: Atomically writing to file /var/lib/cloud/data/status.json(via temporary file /var/lib/cloud/data/tmpr6Gzob) - w: [644] 577 bytes/chars
Nov 03 11:39:04 cloud-init[2226]: atomic_helper.py[DEBUG]: Atomically writing to file /var/lib/cloud/data/result.json(via temporary file /var/lib/cloud/data/tmplz46Vc) - w: [644] 65 bytes/chars
Nov 03 11:39:04 cloud-init[2226]: util.py[DEBUG]: Creating symbolic link from '/run/cloud-init/result.json' => '../../var/lib/cloud/data/result.json'
Nov 03 11:39:04 cloud-init[2226]: util.py[DEBUG]: Reading from /proc/uptime (quiet=False)
Nov 03 11:39:04 cloud-init[2226]: util.py[DEBUG]: Read 10 bytes from /proc/uptime
Nov 03 11:39:04 cloud-init[2226]: util.py[DEBUG]: cloud-init mode 'modules' took 0.489 seconds (0.48)
Nov 03 11:39:04 cloud-init[2226]: handlers.py[DEBUG]: finish: modules-final: SUCCESS: running modules for final
終わりに
今回はUserDataの機能を試してみました。
一度コマンドを用意してしまえば複数台のEC2に同じ設定を自動で入れられるので新規構築の際に作業負担が減らせると思います。
SSMエージェントがインストール済みの場合は、起動済みのEC2にわざわざUserData記載⇒EC2再起動をせずともSSMのRunCommandでコマンドを流せるので気になる方はそちらもご参照ください。

