
開発サーバーを毎回手作業で構築していませんか?
SELinuxの無効化やタイムゾーンの設定、パッケージの導入など、初期構築には意外と多くの工程があります。そしてそのすべてが、設定ミスや手順漏れによって後々のトラブルにつながるリスクを抱えています。
本記事では、RHEL系Linuxを対象とした開発サーバー初期設定スクリプト init_rhel_devhost.sh の構成と設計意図を解説します。root権限で一括実行するだけで、すべての初期設定が自動で反映されるよう設計されており、再実行時にも常に同じ状態が保たれる冪等な構造が特徴です。
安全かつ高速にサーバーを立ち上げたいなら、初期構築の自動化は避けて通れません。このスクリプトがなぜ必要で、どのような仕組みで構成されているのかを整理していきます。
運用自動化ツール
🟡 運用自動化ツール
📌 面倒な作業を一括効率化!シェルスクリプトで実現する運用自動化術
├─ 基本共通
| ├─【Shellの基礎知識】簡単なログ出力ロジックを作ってみました。
| ├─【Shellの基礎知識】シェルスクリプトの作成を時短!テンプレートで効率化する方法
| ├─【Shellの基礎知識】共通関数定義クラスの完全ガイド!設計から実践まで徹底解説
├─ 開発環境構築
| ├─【RHEL系Linux】開発サーバー初期設定スクリプトの完全自動化
| ├─【RHEL系Linux】Apache+Let's Encrypt 自動構築スクリプト|バーチャルホスト対応
| ├─【RHEL系Linux】Tomcatを自動インストール・設定するスクリプトの作成と活用法
| └─【RHEL系Linux】PostgreSQLを自動インストールするシェルスクリプトの使い方
└─ 運用・保守
├─【RHEL系Linux】任意サービスを簡単制御!汎用サービススクリプトの活用術
├─【RHEL系Linux】ファイルやログを自動圧縮する汎用スクリプトの実装と活用法
├─【RHEL系Linux】リソース(CPU・MEM)監視スクリプトで使用率・異常を検知する仕組み
├─【RHEL系Linux】中間ファイル連携を完全制御するファイル転送スクリプト
├─【RHEL系Linux】信頼性を重視した完了保証型ディレクトリ転送スクリプトの設計と実装
├─【RHEL系Linux】ディスク使用率を自動監視するシェルスクリプトの実装
└─【RHEL系Linux】サーバーの障害検知と自動通知|systemdログ監視の実装例
初期設定スクリプトの概要と目的
RHEL系Linuxで開発サーバーを立ち上げる際には、セキュリティポリシーの調整、ネットワークや言語環境の整備、各種ユーティリティの導入といった初期設定が必要になります。
これらの設定はどれも漏れが許されず、サーバーの安定稼働に直結する重要な工程です。 初期構築を人手で行う場合、手順の属人化や設定のバラつき、入力ミスといった運用上のリスクが伴います。
本スクリプトは、それらの問題を解消するために設計された完全自動化型の初期設定スクリプトです。処理の流れ、エラーハンドリング、ログ出力、そして再実行時の冪等性までを考慮しており、構築作業の再現性と安全性を両立します。
初期設定スクリプトの導入背景
このスクリプトは、私たちが構築・運用しているプロダクトを安定的に展開するために必要不可欠な要素として作成しました。
プロダクトを実行する開発用サーバーを複数用意する中で、すべてのマシンに対して同じ初期設定を迅速かつ確実に適用する必要がありました。ただし、サーバーの台数は限られており、Ansibleのような構成管理ツールを導入するにはやや規模が小さく、オーバースペックとなる状況でした。
そのため、rootで一発実行できる初期設定スクリプトという形で、必要最小限かつ高信頼の自動化を実現する方針を選びました。構築ミスの排除と環境統一のために、このスクリプトはプロダクト運用を支える基盤ツールとして位置づけられています。
構築ミスを減らす自動化の意義
本スクリプトは、以下の自動化処理を網羅しています。
| カテゴリ | 自動化される内容 |
|---|---|
| セキュリティ | SELinux、SSHログイン制限、firewalld設定、IPv6無効化 |
| 環境設定 | ロケール、タイムゾーン、ホスト名 |
| パッケージ | dnfによる更新・キャッシュ・必要ツール導入 |
| カーネル | limits.conf、ulimit、sysctlによるパラメータ最適化 |
これらを1つのスクリプトに統合することで、作業者は迷うことなく正しい初期状態を即座に構築できます。実行ログが標準出力とファイルの両方に出力されるため、構築後の確認やトラブル対応にも有効です。
実行対象や権限の前提条件
このスクリプトはroot権限での実行を前提としています。設定対象には `/etc` 配下のシステムファイルが含まれるため、一般ユーザーでは操作できません。 また、スクリプトは以下のようなパス構成を前提としています。
/root/projects/scripts/bin/init_rhel_devhost.sh
/root/projects/scripts/com/logger.shrc
/root/projects/scripts/com/utils.shrc
実行に際しては、ファイルの配置だけでなく、ログディレクトリの書き込み権限やdnfによるインターネット接続も必要になります。環境に応じた事前準備を整えたうえで、実行を行ってください。
設定される主要項目の分類と処理内容
このスクリプトでは、開発サーバーに必要な初期設定を一括で実行する設計になっています。処理内容はカテゴリごとに整理されており、セキュリティの強化、環境設定の最適化、開発ツールの導入といった多岐にわたる作業が順序立てて自動適用されます。
設定項目
- SELinux 無効化
- タイムゾーン設定(Asia/Tokyo)
- ロケール設定(ja_JP.UTF-8)
- ホスト名設定
- ファイアウォール設定
- rootログインを禁止設定
- IPv6 を無効化設定 パッケージのアップデート
- パッケージメタデータの事前キャッシュ
- 必要パッケージのインストール
- chronyd の設定
- limits.conf 設定
- ファイルディスクリプタ
- 上限緩和
- sysctl 設定
- crond 設定
3つの分類に沿って処理内容を解説します。
セキュリティ関連(SELinux、SSH、firewalld、IPv6)
このカテゴリでは、サーバーの基本的な防御状態を構築するための設定を行います。対象はSELinuxの制御、SSHによるrootログインの禁止、ファイアウォールの有効化とポート制限、そしてIPv6の無効化です。これらは初期構築時に必ず適用すべきセキュリティ項目であり、本スクリプトではそれらを確実に反映します。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | SELinux無効化 | SELINUX=disabled | /etc/selinux/config |
| 2 | ファイアウォール設定 | 22, 80, 443, 5000-5003 を開放 | firewalld 有効化済 |
| 3 | SSH設定変更 | PermitRootLogin no | /etc/ssh/sshd_config |
| 4 | IPv6無効化 | disable_ipv6 = 1(all, default) | /etc/sysctl.conf に追記 |
環境設定(タイムゾーン、ロケール、ホスト名)
タイムゾーンやロケール、ホスト名といった設定は、ログの可読性や運用時の識別に関わる重要な要素です。本スクリプトでは、国内開発環境に適した構成となるよう、すべてのサーバーに同一の設定を適用します。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | タイムゾーン設定 | Asia/Tokyo に変更 | timedatectl により反映 |
| 2 | ロケール設定 | LANG=ja_JP.UTF-8 | glibc-langpack-ja を導入 |
| 3 | ホスト名変更 | dev01 に固定 | hostnamectl により変更 |
開発ツール・パッケージの導入
サーバー構築直後に必要なユーティリティを一括で導入します。dnfを使ってパッケージを更新し、依存性解決のためのキャッシュを生成したうえで、vimやgitなどの開発ツールを導入します。これにより、サーバー起動直後から開発や運用作業に着手できる状態が整います。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | パッケージ更新 | 全パッケージを最新化 | dnf により更新 |
| 2 | dnfキャッシュ | makecache --refresh を実行 | 依存関係の解決高速化 |
| 3 | 開発ツール導入 | vim, curl, git, rsync など | dnf install により一括導入 |
カーネル・リソース制御の最適化設定
本スクリプトでは、初期構築直後のサーバーに対して、プロセス制限やネットワークバッファなどのカーネル・リソースパラメータを調整しています。これにより、突発的な高負荷時にもプロセスが異常終了しにくくなり、同時接続やソケット通信の安定性が向上します。 このセクションでは、制限の緩和とチューニングを対象とした3つの処理内容について説明します。
limits.conf による上限変更
まず、`/etc/security/limits.conf` に対してnofile制限(オープン可能なファイルディスクリプタ数)を拡張します。これはWebサーバーやデーモンプロセスが同時に多数のファイルやソケットを開くケースに備えるための設定です。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | プロセス数上限変更 | nofile soft/hard = 65535 | /etc/security/limits.conf |
この設定により、ユーザー単位の同時ファイル数が大幅に拡張され、特に大量ログ生成や多接続処理に強い構成となります。
ulimit の永続化設定
`ulimit -n` はセッション単位でファイルディスクリプタの上限を変更できますが、再起動で元に戻るため永続化が必要です。本スクリプトでは `/etc/sysconfig/init` に追記を行い、恒久的にulimitが適用されるようにしています。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | ulimit設定 | ulimit -n 65535 | /etc/sysconfig/init に追記 |
この設定により、システムの再起動後も一貫して同じリソース上限が適用され、安定した動作を継続できます。
sysctl.conf によるパフォーマンス調整
ネットワーク性能やソケットの同時接続性を向上させるため、`/etc/sysctl.conf` に複数のカーネルパラメータを一括で追加します。主にTCPキューの深さやポート範囲、タイムアウト関連のチューニングです。
| No | 設定項目 | 初期設定値 | 備考 |
|---|---|---|---|
| 1 | カーネルパラメータ設定 | 下記7項目を /etc/sysctl.conf に追記 | 再起動不要。sysctl -p で即時反映 |
以下は実際に追加される設定値です。
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.ip_local_reserved_ports = 23364,27017
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_intvl = 30
これらの設定は、アプリケーションの大量接続時のリスクを軽減し、タイムアウトのバランスを調整することに貢献します。
※このスクリプトはすべての処理において冪等性が確保されており、再実行しても設定結果にばらつきが生じることはありません。
スクリプト全体の実行設計と再実行時の挙動
このスクリプトは、一度実行するだけで開発サーバーに必要な初期設定をすべて完了させる構成になっています。途中停止や設定競合を避けるために、ログ管理・処理分岐・再実行時の冪等性を考慮した制御設計が組み込まれています。
また、設定内容に依存せず複数回の実行にも耐えられる構造になっており、再構築や環境復元の場面でも高い信頼性を保つことができます。
前提となる実行環境
Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。
実行環境
BASE_DIR(任意のディレクトリ)
- scripts
- bin(実行スクリプト格納領域)
- <<各種実行スクリプト>>.sh (実行ファイル)
- com(共通スクリプト格納領域)
- logger.shrc(共通ログ出力ファイル)
- utils.shrc(共通関数定義ファイル)
- etc(設定ファイル等の格納領域)
- infraMessage.conf(メッセージ定義ファイル)
- log(スクリプト実行ログの格納領域)
- スクリプト名.log
- tmp(テンポラリ領域)
- rep(レポート出力領域)
- bin(実行スクリプト格納領域)
RHEL系サーバー初期構成自動化スクリプト
以下は、RHEL系Linuxで開発サーバーを構築するための初期設定スクリプトです。root権限で一度実行するだけで、必要な設定をすべて自動で適用できます。環境に応じてホスト名やポート番号などを変更してご利用ください。
#!/bin/bash
# ------------------------------------------------------------------
# RHEL系Linux開発サーバー初期設定スクリプト v2.0
#
# Usage:
# sh init_rhel_devhost.sh
#
# Description:
# Com(共通) Layer構築コマンド及び設定コマンド
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付 更新者 変更内容
# 1.0 〇〇〇〇〇 2025/07/19 Bepro 新規作成
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# ------------------------------------------------------------------
# 初期処理
# ------------------------------------------------------------------
. "$(dirname "$0")/../com/logger.shrc"
. "$(dirname "$0")/../com/utils.shrc"
startLog # ログ出力を初期化
startTimer # 実行時間計測用タイマー開始
setLANG utf-8
# ====== グローバル変数の設定 ======
BASE_PATH="/home/bepro/projects/scripts" # ベースディレクトリ(全体のルートパス)
LOG_PATH="${BASE_PATH}/log" # ログファイルの保存先ディレクトリ
LOG_LEVEL="INFO" # ログレベル(DEBUG, INFO, WARNING, ERROR)
DEFAULT_LOG_MODE="CONSOLE" # ログ出力先(CONSOLEまたはFILE)
ETC_PATH="${BASE_PATH}/etc" # 設定ファイルを保存するディレクトリ
JOB_OK=0 # 正常終了コード
# ------------------------------------------------------------------
# variables
# ------------------------------------------------------------------
hostname="dev01"
date=$(date "+%Y-%m-%d")
hostname_short=$(hostname -s)
rc=${JOB_OK}
limits_conf="/etc/security/limits.conf"
init_conf="/etc/sysconfig/init"
sysctl_conf="/etc/sysctl.conf"
dailyjobs="/etc/cron.d/dailyjobs"
hosts="/etc/hosts"
selinux_conf="/etc/selinux/config"
# ------------------------------------------------------------------
# functions
# ------------------------------------------------------------------
line () {
echo ""
echo " ------------"
echo " ▼ ${1}"
}
terminate() { :; }
edit_limits_conf () {
sed -i -e "/# End of file/i * soft nofile 65535\n* hard nofile 65535" "$limits_conf"
sleep 1
}
disable_selinux () {
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' "$selinux_conf"
}
# ------------------------------------------------------------------
# pre-process
# ------------------------------------------------------------------
setLogMode ${LOG_MODE:-overwrite}
startLog
trap "terminate" 0 1 2 3 15
# ------------------------------------------------------------------
# main-process
# ------------------------------------------------------------------
# 1. SELinux 無効化
line "1. SELinux を無効化します"
disable_selinux
if [ $? -ne 0 ]; then
logOut "ERROR" "1. SELinux を無効化に失敗しました。"
exitLog 2
fi
# 2. タイムゾーン設定(Asia/Tokyo)
line "2. タイムゾーンを Asia/Tokyo に設定します"
timedatectl set-timezone Asia/Tokyo
timedatectl status
if [ $? -ne 0 ]; then
logOut "ERROR" "2. タイムゾーン設定に失敗しました"
exitLog 2
fi
# 3. ロケール設定(ja_JP.UTF-8)
line "3. ロケールを ja_JP.UTF-8 に設定します"
dnf -y install glibc-langpack-ja
localectl set-locale LANG=ja_JP.UTF-8
localectl status
if [ $? -ne 0 ]; then
logOut "ERROR" "3. ロケール設定に失敗しました"
exitLog 2
fi
# 4. ホスト名設定
line "4. ホスト名を ${hostname} に設定します"
hostnamectl set-hostname "${hostname}"
hostnamectl status
if [ $? -ne 0 ]; then
logOut "ERROR" "4. ホスト名設定に失敗しました"
exitLog 2
fi
# 5. ファイアウォール設定
line "5. firewalld を起動し、必要なポートを解放します"
systemctl enable firewalld --now
firewall-cmd --permanent --add-port=22/tcp
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=5000-5003/tcp
firewall-cmd --reload
firewall-cmd --list-all
# 6. rootログインを禁止設定
line "6. rootログインを禁止します"
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart sshd
if [ $? -ne 0 ]; then
logOut "ERROR" "6. rootログインを禁止設定に失敗しました"
exitLog 2
fi
# 7. IPv6 を無効化設定
line "7. IPv6 を無効化します"
cat << EOS >> /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
EOS
sysctl -p
# 8. パッケージのアップデート
line "8. パッケージのアップデート"
dnf -y update
if [ $? -ne 0 ]; then
logOut "dnf update 失敗"
rc=$((rc + JOB_ER))
exitLog $rc
fi
# 9. パッケージメタデータの事前キャッシュ
line "9. パッケージメタデータを事前にキャッシュします"
dnf makecache --refresh
if [ $? -ne 0 ]; then
logOut "ERROR" "9. パッケージメタデータの事前キャッシュに失敗しました"
exitLog 2
fi
# 10. 必要パッケージのインストール
line "10. 開発用パッケージのインストール"
dnf -y install vim unzip tcpdump net-tools bind-utils curl git rsync lsof zstd
if [ $? -ne 0 ]; then
logOut "ERROR" "10. 必要パッケージのインストール設定に失敗しました"
exitLog 2
fi
# 11. chronyd の設定
line "11. chronyd の再起動"
systemctl restart chronyd
if ! isProcessAlive "chronyd"; then
logOut "chronyd 起動失敗"
rc=$((rc + JOB_ER))
exitLog $rc
fi
line "11.1 chronyd 状態確認"
systemctl --no-pager status chronyd
line "11.2 chrony 同期状態確認"
chronyc sources
line "11.3 chronyd 自動起動設定"
systemctl enable chronyd
# 12. limits.conf 設定
line "12. プロセス数上限設定"
edit_limits_conf
logOut "limits.conf 編集完了"
if [ $? -ne 0 ]; then
logOut "ERROR" "12. limits.conf 設定に失敗しました"
exitLog 2
fi
# 13. ファイルディスクリプタ上限緩和
line "13. ulimit -n を設定"
if ! grep -q "ulimit -n 65535" "$init_conf"; then
echo "ulimit -n 65535" >> "$init_conf"
logOut "ulimit 設定追記 [$init_conf]"
else
logOut "ulimit は既に設定済み [$init_conf]"
fi
# 14. sysctl 設定
line "14. sysctl カーネルパラメータ設定"
if ! grep -q "net.core.somaxconn" "$sysctl_conf"; then
cat << EOS >> "$sysctl_conf"
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.ip_local_reserved_ports = 23364,27017
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_tw_reuse = 1
EOS
fi
sysctl -p
# 15. crond 設定
line "15. crond 定期ジョブ設定"
cat << EOS > "$dailyjobs"
# Daily/Weekly/Monthly cron jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
02 15 * * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.daily
22 15 * * 0 root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.weekly
42 15 1 * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.monthly
EOS
# ------------------------------------------------------------------
# post-process
# ------------------------------------------------------------------
endTimer # タイマーを終了
exitLog $rc
このスクリプトを実行するには、共通関数ファイルである logger.shrc および utils.shrc が同一ディレクトリ内の com フォルダに配置されている必要があります。
これらのスクリプトには、ログ出力処理や汎用ユーティリティ関数が含まれており、本体スクリプトの全処理を正しく機能させるために必須です。
処理の実行順序とエラーハンドリング
スクリプトは1番から順に処理を進める直列実行型で、各セクションには処理開始と終了のログ出力が設けられています。失敗した処理が発生した場合には、即座にログを出力し、エラーコードとともにスクリプトを終了します。
startLog
logOut "ERROR" "設定失敗内容"
exitLog 2
このように明示的に終了ポイントを設けることで、エラーの位置を特定しやすく、修正にも時間がかかりません。
冪等性の確保(何度実行しても一貫する構造)
本スクリプトは、再実行した場合でも常に同じ設定結果が得られるように設計されています。たとえば、設定ファイルへの追記はすでに記述があるかどうかを検出したうえで行われ、無駄な追記や重複が発生しないよう制御されています。
if ! grep -q "ulimit -n 65535" "$init_conf"; then
echo "ulimit -n 65535" >> "$init_conf"
fi
この構造により、複数回のスクリプト実行やCI環境での再デプロイ時にも、予測可能かつ安全に動作します。
ログ出力とデバッグ性の確保
各処理ステップでは、ログ出力関数を通じて標準出力およびログファイルへの記録が行われます。ログレベルは `INFO` を標準とし、必要に応じて `DEBUG` に変更可能です。ログの出力先も `CONSOLE` と `FILE` を切り替えられる柔軟な設計です。
LOG_MODE="overwrite"
DEFAULT_LOG_MODE="CONSOLE"
logOut "INFO" "ファイアウォール設定を開始します"
実行結果を可視化することで、構築作業の透明性が高まり、トラブル時の原因調査や運用レポートにも活用できます。