Shellの基礎知識(実践編)

【RHEL系Linux】Apache+Let's Encrypt 自動構築スクリプト|バーチャルホスト対応・完全自動化ツール

開発用途のApache構成に毎回手間を感じていませんか?

このスクリプトは、RHEL系LinuxにおけるApache(httpd)のインストールから設定変更、プロセスチューニング、バーチャルホストの設定までを一括で自動化します。

特に、複数プロジェクトをホストする前提でバーチャルホストの雛形も用意されており、再実行しても冪等性を保ちつつ、構築作業のブレをなくします。

この一連の処理により、Webサーバーの標準構築を高速・安定化し、構築担当者のミスを排除する環境を実現できます。

今後、Web開発プロジェクトのスケーラビリティを見越した設計にも対応可能です。

運用自動化ツール

🟡 運用自動化ツール
📌 面倒な作業を一括効率化!シェルスクリプトで実現する運用自動化術
├─ 基本共通
| ├─【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ログ監視の実装例

スクリプトの役割と想定ユースケース

ApacheとLet's EncryptによるHTTPS環境を、完全に自動化されたシェルスクリプトで構築します。このスクリプトは、インフラ構築作業の手間を削減し、SSL証明書に関する典型的なエラーを回避する仕組みを持っています。RHEL系Linux(AlmaLinuxやRocky Linuxなど)を対象に設計されており、サーバーの初期セットアップからSSL通信の有効化までを一貫して処理します。構成は実行順に明確に分かれており、汎用性と再現性の両立を重視しています。

ApacheとLet's Encryptの構築を一括で自動化

ApacheのインストールからSSL証明書の取得、HTTPSリダイレクトの設定までを、1回のスクリプト実行で完了できる構成です。スクリプトは以下の2つに分かれており、それぞれが役割を持って動作します。

スクリプト名主な処理内容
init_rhel_devhost.shfirewalldやSELinuxの初期設定、ロケール・タイムゾーンの適用、必要パッケージの導入
install_apache_host.shApacheとmod_sslの導入、confの編集、Let's Encryptによる証明書取得、VirtualHost設定

sh install_apache_host.sh -d www.example.com -e your@email.com

firewalldでのポート開放(22, 80, 443, 5000-5003)や、httpd.confへのServerName挿入、mod_sslの導入も全て内包しており、スクリプトを追う必要はありません。

証明書取得とSSL設定のエラーを防ぐ仕組み

Let's Encryptのcertbotを用いた証明書取得は、VirtualHostが存在しない場合やApache構文エラーがある場合に失敗します。この問題を回避するため、スクリプトでは以下のような処理を実装しています。

  • 証明書取得前に一時的なVirtualHost(*:80)をhttpd.confに自動挿入
  • Apache再起動と構文チェック(httpd -t)を行い、問題がなければcertbotを実行
  • 取得完了後はVirtualHostを自動削除し、元のconf構造に復元

これにより、以下のようなcertbotエラーを根本から排除しています。

PluginError: Unable to find a virtual host listening on port 80

さらに、証明書が正しく取得されたかをファイルサイズで検証し、空のままリンクだけが生成された状態も除外します。

[ ! -s /etc/letsencrypt/live/${DOMAIN}/fullchain.pem ]

また、Let's Encryptには「同一FQDNに対して7日間で5回まで」というレート制限があります。これに引っかかった場合でも、ログに出力される時間をもとに次回取得可能時刻を読み取り、運用者に的確な対応判断ができるよう配慮されています。

このように、certbotが失敗する典型的なケースを事前に吸収する構造により、実行する側はスクリプトの内部ロジックを把握していなくても問題なくHTTPS環境を構築できます。

スクリプト全体の構造と設計の工夫

本構築ツールは、ApacheおよびLet's Encryptの導入を完全自動化することを目的に設計されています。そのために、スクリプトは「初期環境の整備」と「Webサーバー構築」に明確に役割分担された2部構成になっています。さらに、証明書取得時のトラブルを回避するため、VirtualHostの一時追加と復元処理も組み込まれており、再現性と安全性の両立が実現されています。

init_rhel_devhost.shが担う初期環境の整備

このスクリプトは、RHEL系Linux(例:AlmaLinux)における開発サーバーの初期環境を、自動で最適化する役割を担います。初期状態のRHEL系OSでは、SELinuxやfirewalldなどの制約により通信制限が多く、手作業での調整が煩雑になりがちです。本スクリプトは、以下の処理をすべて自動で行います。

  • SELinuxの無効化と反映設定
  • ロケール(ja_JP.UTF-8)とタイムゾーン(Asia/Tokyo)の設定
  • firewalldの起動とポート開放(22, 80, 443, 5000-5003)※個人開発で利用する前提
  • chronydの起動とNTP同期の確認
  • sysctlやulimitのパラメータ最適化

さらに、cron定期ジョブスケジュールも /etc/cron.d に自動配置され、今後の保守・運用を見据えた土台構築が完了します。

sh init_rhel_devhost.sh

この1行を実行するだけで、開発用途に必要なRHEL系サーバーの初期構成が完成します。

RHEL系Linux環境の初期セットアップも自動化したい方は、以下の記事も参考にしてください。SELinux無効化からfirewalld設定、パッケージ導入までを一括で処理するスクリプトを紹介しています。

▶︎【RHEL系Linux】開発サーバー初期設定スクリプトの完全自動化

install_apache_host.shによるWeb構築の自動化

このスクリプトは、ApacheとLet's Encryptの連携によるHTTPSサーバー構築を自動化する役割を担います。httpdやmod_sslの導入に加え、不要なconfファイルの無効化、MPMのeventモード化、ファイルディスクリプタ制限の拡張など、現場で必要とされる最適化が盛り込まれています。 処理の主な構成は以下のとおりです。

処理内容対象設定
Apacheインストールhttpd, mod_ssl
conf設定ServerName, VirtualHost, MPM
不要confの空ファイル化welcome.conf, userdir.conf, autoindex.conf
起動設定systemctl enable + daemon-reload

このスクリプトの中で自動的にcertbotを実行し、取得した証明書をそのままhttpd.confに反映することで、ApacheのHTTPS化が完了します。

sh install_apache_host.sh -d www.example.com -e your@email.com

また、証明書の自動更新にも対応しており、certbot-renew.timerが有効化されるため、更新忘れによる障害も防げます。

certbot対応のためのVirtualHost一時追加処理

certbotはApacheモードで実行する場合、conf内に `*:80` のVirtualHostが存在していることを前提に動作します。しかし、構築の初期段階ではまだ `*:443` のVirtualHostすら存在しないため、証明書取得時に以下のようなエラーが発生する可能性があります。

Unable to find a virtual host listening on port 80

この問題を根本的に回避するため、install_apache_host.shでは一時的に以下のVirtualHostをhttpd.confへ自動追加します。

# === BEGIN TEMP VHOST FOR CERTBOT ===
<VirtualHost *:80>
    ServerName www.example.com
    DocumentRoot /var/www/html
</VirtualHost>
# === END TEMP VHOST FOR CERTBOT ===

証明書取得後にはこのブロックを sed により確実に削除し、構文エラーを残さないようにしています。また、削除後はhttpdを再起動し、構成を明確に1本化することでconfの肥大化を防止しています。これは商用サーバーでもそのまま運用可能な設計となっており、構築後の保守性も高く保たれます。

自動構築スクリプトによる各種設定内容

ApacheとSSL証明書の導入においては、単なるパッケージのインストールだけでなく、設定ファイルの編集や構文チェック、各種サービスとの連携など多くの調整が必要です。本スクリプトは、そうした作業をすべて網羅し、自動的に整備される構成になっています。ここでは、各種設定処理の具体的な中身について整理します。

Apacheインストールとconfの動的編集

Apache(httpd)とmod_sslをインストールしたうえで、httpd.confの内容を実行時に動的に編集しています。特にServerNameの有効化、MPMモードの変更、open file limitの上限設定など、開発・運用で必須となる設定はすべて組み込まれています。

以下がスクリプト実行時に自動で行われる主な処理です。

設定項目処理内容
ServerNamelocalhost:80 を httpd.conf に挿入
MPM設定prefork, worker のうち worker を有効化
limits.confLimitNOFILE=65535 を systemd 設定に追加
conf.d の整備welcome.conf, userdir.conf, autoindex.conf を空ファイル化

また、プロセスの再起動や自動起動設定も反映されるため、再起動後も設定が維持されます。

systemctl daemon-reload
systemctl enable httpd

SSL証明書の存在チェックとconf反映処理

Let's Encryptの証明書はcertbotにより取得されますが、certbot実行後に証明書ファイルが確実に存在しているかどうかをスクリプト内でチェックしています。空リンクや途中失敗による未発行のままconfが有効化されることを防ぐため、証明書ファイルが存在かつ非空であることを条件に処理を継続します。

[ ! -s /etc/letsencrypt/live/${DOMAIN}/fullchain.pem ]

証明書が正しく取得された場合は、自動的にhttpd.confへ以下のVirtualHostブロックが挿入されます。

<VirtualHost *:443>
    ServerName ${DOMAIN}
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/${DOMAIN}/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/${DOMAIN}/privkey.pem
</VirtualHost>

このように、証明書ファイルの有無と正当性を条件としてconf反映を行うことで、Apache起動時の構文エラーを防ぎ、安定したHTTPS構成を確保します。

firewalldポート設定と安全性の担保

firewalldの設定では、初期セットアップ時に22, 80, 443, 5000〜5003までのポートを一括で開放します。ただし、再構築スクリプト(install_apache_host.sh)でも明示的にポート設定を行うため、途中でfirewalldが初期化された場合でもHTTPSポートが閉じられる心配はありません。 スクリプトでは以下のように、ポートの開放状態を確認したうえで必要に応じて追加しています。

if ! firewall-cmd --list-ports | grep -q '443/tcp'; then
    firewall-cmd --permanent --add-port=443/tcp
    changed=1
fi

必要なポートをすべて追加したあと、1回だけ firewall-cmd --reload を実行することで、設定の上書きによる削除や競合を防ぎます。 このように、スクリプトはセキュリティ設定にも配慮されており、最小限のポート開放で安全な通信環境を整えます。

※本スクリプトはAlmaLinux環境で実際に検証を行った上で構築されていますが、AlmaLinuxやRocky LinuxはOSSのため、バージョンアップに伴いApache関連の設定ファイル構造や記述フォーマットが変更される可能性があります。その場合、sed等による設定項目の自動置換処理が正常に動作しないことがあります。スクリプトのご利用前には対象サーバーのApacheバージョンと設定ファイルの構造をご確認ください。anently と Location: https://~ のレスポンスが得られれば、構築成功と判断できます。

利用手順と再現可能な運用方法

このスクリプトは、再現性の高いApache+SSL構成を一括で自動化しますが、その前提としていくつかの重要な値が環境依存であり、適切な設定と引数指定が必要です。スクリプトは高い汎用性を備えていますが、何も考えずに実行すると目的と異なる構成が出来上がる恐れもあります。実行前に必ず以下の内容を確認し、自身の環境に合わせて調整してください。

前提となる実行環境

Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。

実行環境

BASE_DIR(任意のディレクトリ)

  • scripts
    • bin(実行スクリプト格納領域)
      • <<各種実行スクリプト>>.sh (実行ファイル)
    • com(共通スクリプト格納領域)
      • logger.shrc(共通ログ出力ファイル)
      • utils.shrc(共通関数定義ファイル)
    • etc(設定ファイル等の格納領域)
      • infraMessage.conf(メッセージ定義ファイル)
    • log(スクリプト実行ログの格納領域)
      • スクリプト名.log 
    • tmp(テンポラリ領域)
    • rep(レポート出力領域)

Apacheサーバー自動構築スクリプト

本セクションでは、Apache + Let's Encrypt の導入を完全自動化する install_apache_host.sh スクリプトの内部構成とその処理内容について解説します。証明書の取得からVirtualHost設定の反映、firewalldのポート開放まで、すべての工程が1本のスクリプトに統合されており、環境構築における人的ミスや設定漏れを極限まで排除できるよう設計されています。

以降に、実際のスクリプト全文を掲載します。必要に応じて自環境に合わせたパラメータ修正を行ってください。

#!/bin/sh
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# ver.1.0.0 2025.07.19
#
# Usage:
#     sh install_apache_host.sh [-d domain] [-e email] [-m mode]
#
# Description:
#    Web Layer構築コマンド及び設定コマンド
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付        更新者       変更内容
# 1.0  〇〇〇〇〇  2025/07/19  Bepro       新規作成
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# ------------------------------------------------------------------
# 初期処理
# ------------------------------------------------------------------
. "$(dirname "$0")/../com/logger.shrc"
. "$(dirname "$0")/../com/utils.shrc"
setLANG     utf-8

# ========================================
# 定数定義
# ========================================
readonly JOB_OK=0
readonly JOB_WR=1
readonly JOB_ER=2

# ------------------------------------------------------------------
# variables (変数の宣言領域)
# ------------------------------------------------------------------
scope="var"

DOMAIN=""
EMAIL=""
date=$(date "+%Y-%m-%d")
hostname=`hostname -s`
rc=${JOB_OK}
conf_dir="/etc/httpd/conf/"
conf_d_dir="/etc/httpd/conf.d/"
conf_module_d_dir="/etc/httpd/conf.modules.d/"
httpd_conf="httpd.conf"
mpm_conf="mpm.conf"
target_mpm="LoadModule mpm_prefork_module modules\/mod_mpm_prefork\.so"
untarget_mpm="LoadModule mpm_worker_module modules\/mod_mpm_worker\.so"
limits_conf_dir="/etc/systemd/system/httpd.service.d/"
IF01_MSG="モジュールのインストールに成功しました。"
IF02_MSG="処理に成功しました。"
WR01_MSG="モジュールが既に導入されています。処理を中止します。"
WR02_MSG="処理に失敗しました。"
ER01_MSG="モジュールのインストールに失敗しました。"
ER02_MSG="処理に失敗しました。"

# ----------------------------------------------------------
# VirtualHost設定 Java連携時の接続子
# ----------------------------------------------------------
VHOST1="app1"
VHOST2="app2"

# ----------------------------------------------------------
# functions (関数を記述する領域)
# ----------------------------------------------------------
scope="func"

# ----------------------------------------------------------
# Executes the processing at the end..
# ----------------------------------------------------------
# return N/A
# ----------------------------------------------------------
terminate() {
  :
}

# ----------------------------------------------------------
# devider.
# ----------------------------------------------------------
# return N/A
# ----------------------------------------------------------
line (){
  echo -e "\\n    ------------"
  echo -e "    ▼ ${1}"
}

# ----------------------------------------------------------
# how to use.
# ----------------------------------------------------------
# return   N/A
# ----------------------------------------------------------
usage() {

  cat <<EOUSAGE
    -----------------------------------------------------------------
    Usage: $0 -d <domain> -e <email>

       Options:
         -d domain     : Specify the target domain (e.g., example.com)
         -e email      : Specify the contact email for Let's Encrypt

    -----------------------------------------------------------------
EOUSAGE
}

# ----------------------------------------------------------
# 引数チェック
# ----------------------------------------------------------
# param 1  protocol : Please enter the communication protocol [ https | http ].
# return   N/A
# ----------------------------------------------------------
checkArgs() {

logOut "引数:[ ${1} ${2} ]"
  if [ $# -lt 2 ]; then
    logOut "DEBUG" "引数が正しくありません。[ $@ ]"
    exitLog ${JOB_ER}
  fi
 
}

#====================================================
# 関数名:erase
# 説明  :HTTPDとLet's Encrypt関連を含むすべてのアンインストール処理
#====================================================
erase() {

    if isProcessAlive "httpd"; then
        logOut "DEBUG" "HTTPDのプロセスを停止します。"
        systemctl stop httpd
    fi

    logOut "DEBUG" "HTTPDをアンインストールします。"
    dnf -y remove $(rpm -qa | grep -E '^httpd|mod_ssl')
    if [ $? -ne 0 ]; then
        rc=`expr ${rc} + ${JOB_ER}` 
        return ${rc}   
    fi

    if [ -d /etc/httpd ]; then
        logOut "DEBUG" "/etc/httpd 配下の設定ファイルを削除します。"
        find /etc/httpd -type f -exec rm -f {} \;
    fi

    if [ -d /etc/systemd/system/httpd.service.d ]; then
        logOut "DEBUG" "/etc/systemd/system/httpd.service.d を削除します。"
        rm -f /etc/systemd/system/httpd.service.d/override.conf
        rm -rf /etc/systemd/system/httpd.service.d
    fi

    #===========================
    # systemd キャッシュを完全リセット
    #===========================
    logOut "DEBUG" "systemd キャッシュを完全リセットします。"
    systemctl stop httpd 2>/dev/null
    systemctl disable httpd 2>/dev/null
    systemctl reset-failed httpd 2>/dev/null
    systemctl daemon-reexec
    systemctl daemon-reload

    #===========================
    # Let's Encrypt の削除処理
    #===========================
    if command -v certbot >/dev/null 2>&1; then
        logOut "DEBUG" "Let's Encrypt (certbot) が導入されているため、関連リソースを削除します。"
        removeLetsEncryptCert
    else
        logOut "DEBUG" "certbot が導入されていないため、Let's Encrypt の削除処理はスキップします。"
    fi
}

# ----------------------------------------------------------
# Edit the settings in the config file.
# ----------------------------------------------------------
# return N/A
# ----------------------------------------------------------
editHttpdConf (){

  sed -i -e "s/#ServerName www\.example\.com:80/ServerName localhost:80\nServerTokens Prod/" "${conf_dir}${httpd_conf}"
  sleep 1
}


# ----------------------------------------------------------
# Edit the settings in the icc config file.
# ----------------------------------------------------------
# return N/A
# ----------------------------------------------------------
editConfHttp2Https (){

  sed -i -e "s/.*Header edit Location ^http https/#&/g" "${conf_dir}${httpd_conf}"
  sleep 1
}

# ----------------------------------------------------------
# Edit the settings in the limits.conf.
# ----------------------------------------------------------
# return N/A
# ----------------------------------------------------------
editLimitsConf () {
    # prefork, worker, event のうち使用するMPMをコメント化
    sed -i -E 's|^[[:space:]]*#*LoadModule mpm_prefork_module.*|#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so|' "${conf_module_d_dir}00-mpm.conf"
    sed -i -E 's|^[[:space:]]*#*LoadModule mpm_worker_module.*|#LoadModule mpm_worker_module modules/mod_mpm_worker.so|' "${conf_module_d_dir}00-mpm.conf"
    #sed -i -E 's|^[[:space:]]*#*LoadModule mpm_event_module.*|#LoadModule mpm_event_module modules/mod_mpm_event.so|' "${conf_module_d_dir}00-mpm.conf"

}

#====================================================
# 関数名:installLetsEncryptCert
# 説明  :Let's Encrypt を用いたSSL証明書の取得とApacheへの組み込み
#====================================================
installLetsEncryptCert() {
    local DOMAIN="$1"
    local EMAIL="$2"
    local conf_file="/etc/httpd/conf/httpd.conf"
    local temp_marker="# === BEGIN TEMP VHOST FOR CERTBOT ==="
    local cert_path="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"

    if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then
        logOut "ERROR" "ドメイン名とメールアドレスは必須です。" >&2
        return 1
    fi

    # certbotのインストール
    if ! command -v certbot >/dev/null 2>&1; then
        logOut "INFO" "certbot をインストールします。"
        dnf install -y epel-release
        dnf install -y certbot python3-certbot-apache
    fi

    # ポート80と443を確認して未開放なら追加、reloadは1回だけ
    local changed=0
    if ! firewall-cmd --list-ports | grep -q '80/tcp'; then
        logOut "INFO" "ポート80を一時的に開放します。"
        firewall-cmd --permanent --add-port=80/tcp
        changed=1
    fi
    if ! firewall-cmd --list-ports | grep -q '443/tcp'; then
        logOut "INFO" "ポート443を一時的に開放します。"
        firewall-cmd --permanent --add-port=443/tcp
        changed=1
    fi
    if [ "$changed" -eq 1 ]; then
        firewall-cmd --reload
    fi

    # certbotが要求する仮のVirtualHost(*:80)を追加
    logOut "INFO" "Apache に一時的な VirtualHost を追加します(port 80)"
    cat << EOF >> "$conf_file"
${temp_marker}
<VirtualHost *:80>
    ServerName ${DOMAIN}
    DocumentRoot /var/www/html
</VirtualHost>
# === END TEMP VHOST FOR CERTBOT ===
EOF

    # Apache構文チェックと再起動
    systemctl restart httpd
    if ! httpd -t; then
        logOut "ERROR" "Apache 設定にエラーがあります(VirtualHost追加後)"
        return 1
    fi

    # certbotで証明書取得
    logOut "INFO" "Let's Encrypt で証明書を取得します:$DOMAIN"
    if ! certbot --apache -n --agree-tos --email "$EMAIL" -d "$DOMAIN"; then
        logOut "ERROR" "certbot による証明書取得に失敗しました。"
        return 1
    fi

    # 証明書の存在確認
    if [ ! -s "$cert_path" ]; then
        logOut "ERROR" "証明書ファイルが存在しないか空です:$cert_path"
        return 1
    fi

    # 仮VirtualHostの削除
    logOut "INFO" "一時的に追加した VirtualHost を削除します"
    sed -i "/${temp_marker}/,/^# === END TEMP VHOST FOR CERTBOT ===/d" "$conf_file"

    systemctl restart httpd

    # certbotの自動更新有効化
    logOut "INFO" "証明書の自動更新を有効化します。"
    systemctl enable certbot-renew.timer
}

#====================================================
# 関数名:removeHttpdAndLetsEncrypt
# 説明  :Apache(httpd)とLet's Encrypt証明書、関連設定・パッケージを完全に削除
#====================================================
removeLetsEncryptCert() {
    # Apache関連パッケージを削除
    logOut "INFO" "Apache (httpd) を削除します。"
    dnf remove -y httpd httpd-tools mod_ssl

    # certbot と関連パッケージを削除
    logOut "INFO" "certbot と関連パッケージを削除します。"
    dnf remove -y certbot python3-certbot-apache

    # Let's Encrypt の証明書・キャッシュ・ログを削除
    logOut "INFO" "Let's Encrypt の証明書と設定を削除します。"
    rm -rf /etc/letsencrypt
    rm -rf /var/lib/letsencrypt
    rm -rf /var/log/letsencrypt

    # Apacheの conf.d ディレクトリにあるバーチャルホスト設定を削除
    logOut "INFO" "Apache 設定から残っているバーチャルホスト設定を削除します。"
    rm -f /etc/httpd/conf.d/*.conf

    # certbot の自動更新タイマー(systemd)を無効化して削除
    logOut "INFO" "certbot 関連の systemd タイマーを無効化・削除します。"
    systemctl disable --now certbot-renew.timer 2>/dev/null
    systemctl stop certbot-renew.timer 2>/dev/null
    rm -f /etc/systemd/system/timers.target.wants/certbot-renew.timer

    # ファイアウォールのポート開放を元に戻す
   # logOut "INFO" "ファイアウォール設定をクリーンアップします(ポート80/443削除)"
   # firewall-cmd --remove-port=80/tcp --permanent
   # firewall-cmd --remove-port=443/tcp --permanent
   # firewall-cmd --reload

    logOut "INFO" "削除が完了しました。"
}

# ------------------------------------------------------------------
# pre-process (事前処理ロジックを記述する領域)
# ------------------------------------------------------------------
scope="pre"

#setLogMode ${LOG_MODE:-overwrite}
startLog

trap "terminate" 1 2 3 15

checkArgs $@

# Get the value from the argument.
while getopts d:e:m: OPT; do
    case $OPT in
        d) DOMAIN="$OPTARG" ;;
        e) EMAIL="$OPTARG" ;;
        m) MODE="$OPTARG" ;;
        *) echo "Usage: $0 [-d domain] [-e email] [-m mode]" >&2; exit 1 ;;
    esac
done
# ------------------------------------------------------------------
# main-process (メインロジックを記述する領域)
# ------------------------------------------------------------------
scope="main"

if [ "${MODE}" == "erase" ]; then
  if ! erase ; then
    logOut "INFO" "HTTPD設定の消去${WR02_MSG} 既に削除されています。 [ Httpd ]"
    exitLog ${ERROR}
  fi
    logOut "INFO" "HTTPD設定の消去${IF02_MSG} [ Httpd ]"
fi
sleep 3

if [ -n "${DOMAIN}" ]; then
	line "httpdの導入状況を確認します。"
	if isModuleInstall "httpd"; then
	  logOut "WARN" "${WR01_MSG}"
	   exitLog ${JOB_ER}
	fi
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 1.OS標準のhttpdのインストール
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "1.OS標準のhttpdのインストールを行ないます。"
	dnf install -y httpd mod_ssl
	if [ $? -eq 0 ]; then

	  logOut "INFO" "${IF01_MSG} [ Apache(httpd) ]"
	  line "既存の設定ファイルを退避します。"
	  cp -p "${conf_dir}${httpd_conf}" "${conf_dir}${httpd_conf}.${date}"

	  if [ -f "${conf_dir}${httpd_conf}.${date}" ]; then
	    logOut "INFO" "ファイルの退避${IF02_MSG} [ ${conf_dir}${httpd_conf}.${date} ]"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 2.httpd.confファイルのServerNameのコメントアウトを外して編集
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	    line "2.httpd.confファイルのServerNameのコメントアウトを外して編集します。"
	    if ! editHttpdConf ; then
	      logOut "ERROR" "ファイルの編集${ER02_MSG} [ ${conf_dir}${httpd_conf} ]"
	      rc=`expr ${rc} + ${JOB_ER}`
	      exitLog ${rc}
	    fi
	    sleep 1
	    logOut "INFO" "ファイルの編集${IF02_MSG} [ ${conf_dir}${httpd_conf}"
	    echo -e `cat ${conf_dir}${httpd_conf} | grep -v '^\s*#' | grep 'ServerName'`
	    echo -e `cat ${conf_dir}${httpd_conf} | grep -v '^\s*#' | grep 'ServerTokens'`
	  else
	    logOUt "ERROR" "ファイル退避${ER02_MSG} [ ${conf_dir}${httpd_conf} ]"
	    rc=`expr ${rc} + ${JOB_ER}`
	    exitLog ${rc}
	  fi
	else
	  logOut "ERROR" "${ER01_MSG} [ Apache(httpd) ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 3.httpd上の不要な設定ファイルを無効
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "3.httpd上の不要な設定ファイルを無効にします。"
	:>${conf_d_dir}welcome.conf 
	:>${conf_d_dir}userdir.conf 
	:>${conf_d_dir}autoindex.conf
	sleep 1
	ls -l ${conf_d_dir}
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 4.httpdの動作モードをevent
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "4.httpdの動作モードをeventに変更するための設定変更を行います。"
	if ! editLimitsConf; then
	  logOut "ERROR" "ファイルの編集${ER02_MSG} [ ${conf_d_dir}${mpm_conf} ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 5.新たにmpm.confファイルを作成
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "5.新たにmpm.confファイルを作成して設定を記述します。"
cat << EOS > "${conf_d_dir}${mpm_conf}"
KeepAlive Off
<IfModule worker.c>
  StartServers             4
  ServerLimit             20
  MaxRequestWorkers      500
  MinSpareThreads         25
  MaxSpareThreads         75
  ThreadsPerChild         25
  MaxConnectionsPerChild   0
</IfModule>
EOS
	sleep 1
	if [ ! -f "${conf_d_dir}${mpm_conf}" ]; then
	  logOut "ERROR" "ファイルの編集に${ER02_MSG} [ ${conf_d_dir}${mpm_conf} ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	logOut "INFO" "ファイルの編集${IF02_MSG} ${conf_d_dir}${mpm_conf}"
	cat "${conf_d_dir}${mpm_conf}"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 6.httpdのopen file limitの上限値緩和
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "6.httpdのopen file limitの上限値緩和のための設定ファイルを作成します。"
	mkdir -p ${limits_conf_dir}
cat << EOS > "${limits_conf_dir}limits.conf"
[Service]
LimitNOFILE=65535
EOS
	sleep 1
	if [ ! -f "${limits_conf_dir}limits.conf" ]; then
	  logOut "ERROR" "ファイルの編集${ER02_MSG} [ ${limits_conf_dir}limits.conf ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	logOut "INFO" "ファイルの編集${IF02_MSG} ${limits_conf_dir}limits.conf"
	cat "${limits_conf_dir}limits.conf"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 7.httpdの自動起動設定および起動
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "7.httpdの自動起動設定および起動を行います。"
	systemctl daemon-reload
	systemctl enable httpd
	sleep 1
	if [ $? -ne 0 ]; then
	  logOut "WARNING" "自動起動設定${WR03_MSG} [ httpd ]"
	  rc=`expr ${rc} + ${JOB_WR}`
	fi
	logOut "INFO" "自動起動設定${IF02_MSG} [ Apacht(httpd) ]"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 8.設定値反映確認のため、Apache/httpdのプロセスIDを取得
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "8.設定値反映確認のため、Apache/httpdのプロセスIDを取得します。"
	systemctl status httpd
	sleep 1

	#起動確認の為、一回起動する
	systemctl start httpd
	sleep 1
	if ! isProcessAlive "httpd"; then
	  logOut "ERROR" "Apache(httpd)の起動${ER02_MSG} [ httpd ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	logOut "INFO" "Apache(httpd)の起動${IF02_MSG} [ Apacht(httpd) ]"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# Let's Encrypt を用いたSSL証明書の取得
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
  line "9.Let's Encrypt を用いたSSL証明書の取得"
  logOut "INFO" "Let's Encrypt を用いたSSL証明書の取得とApacheへの組み込み"
  installLetsEncryptCert "$DOMAIN" "$EMAIL"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 10.Apache/httpd用のopen file limitが更新確認
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "10.Apache/httpd用のopen file limitが更新されたことを確認します。"
	logOut "INFO" "ファイルの編集${IF02_MSG} [ Apacht(httpd) ]"
	echo `cat /proc/$(ps -ef | grep httpd | head -n 1 | awk '{print $2}')/limits | grep 'Max open files'`
	echo "目視による確認を行ってください。"
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 11.アプリケーション連携のため、設定ファイル「httpd.conf」を編集
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "11.アプリケーション連携のため、設定ファイル「httpd.conf」を編集します。"
var=$(cat << EOS
<VirtualHost *:80>
    ServerName ${DOMAIN}
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

<VirtualHost *:443>
    ServerName ${DOMAIN}

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/${DOMAIN}/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/${DOMAIN}/privkey.pem

    <Location /${VHOST1}/>
        ProxyPass ajp://localhost:8009/${VHOST1}/
    </Location>

    <Location /${VHOST2}/>
        ProxyPass ajp://localhost:8009/${VHOST2}/
    </Location>
</VirtualHost>
EOS
)
	echo  "${var}" >> "${conf_dir}${httpd_conf}"
	sleep 1

	editConfHttp2Https

  matched_count=$(grep -cE 'VirtualHost[[:space:]]+\*:443' "${conf_dir}${httpd_conf}")
  if [ "$matched_count" -eq 0 ]; then
      logOut "ERROR" "ファイルの編集${ER02_MSG} [ ${conf_dir}${httpd_conf} ]"
      rc=$((rc + JOB_ER))
      exitLog ${rc}
  fi

	logOut "INFO" "ファイルの編集${IF02_MSG} [ ${conf_dir}${httpd_conf} ]"
        tail ${conf_dir}${httpd_conf}

	# 確認用のHTMLファイルの作成
cat <<- EOS > /var/www/html/index.html
  <html>
  <head>
  <title>sample page</title>
  </head>
  <body>
  "このページは${hostname}で表示されたテストページです"
  </body>
  </html>
EOS
	sleep 1
	if [ $? -ne 0 ]; then
	  logOut "ERROR" "${ER02_MSG} [ /var/www/html/index.html ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	logOut "INFO" "htmlファイルの作成${IF02_MSG} [ /var/www/html/index.html ]"
        cat /var/www/html/index.html
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	# 12.サービスを再起動
	#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	line "12.サービスを再起動します。"
	systemctl restart httpd
	sleep 1
	if [ $? -ne 0 ]; then
	  logOut "ERROR" "Apache(httpd)の再起動${ER02_MSG} [ httpd ]"
	  rc=`expr ${rc} + ${JOB_ER}`
	  exitLog ${rc}
	fi
	logOut "INFO" "Apache(httpd)の再起動${IF02_MSG} [ Apacht(httpd) ]"
	systemctl status httpd

	line "Apacheへアクセステスト"
	curl http://localhost
	sleep 1
fi

# ----------------------------------------------------------
# post-process (事後処理ロジックを記述する領域)
# ----------------------------------------------------------
scope="post"

exitLog ${rc}

環境ごとに変更すべき項目と引数の指定

スクリプトではドメイン名とメールアドレスを外部引数で指定する仕様になっています。これはLet's Encryptの証明書取得に必要なため、必ず適切な値を与える必要があります。

sh install_apache_host.sh -d www.example.com -e user@example.com

スクリプトを実行する際は、少なくとも -d(ドメイン名)および -e(メールアドレス)の2つの引数を指定する必要があります。これらの値が省略された場合、スクリプトは処理を開始せず終了します。

また、ホスト名やポート開放処理など一部の情報はスクリプト内部で自動的に取得・判定されるよう設計されています。そのため、基本的には引数さえ正しく指定すれば、環境ごとの個別修正を行わずにそのまま実行可能です。 

種別項目処理内容変更の必要性
引数指定DOMAINSSL証明書対象のFQDNを明示必須
引数指定EMAILLet's Encrypt登録メールアドレス必須
自動取得hostname`hostname -s` により自動取得不要
条件付き処理ポート80,443firewalldに未登録なら開放通常は不要

解放ポートは init_rhel_devhost.sh 内で firewall-cmd によって設定されています。特に5000番台のポートは開発用途に応じて変更すべきケースもあるため、事前に明確にしておく必要があります。

構築スクリプトの削除モードについて

ApacheやLet's Encrypt関連の構成を完全に削除したい場合は、`install_apache_host.sh` に `-m erase` オプションをつけることで、削除専用の処理が実行されます。

sh install_apache_host.sh -m erase

このモードでは以下の操作が行われます。

  • httpd, mod_ssl, certbot のアンインストール
  • /etc/httpd ディレクトリと systemd 関連設定の削除
  • Let's Encrypt の証明書・ログ・キャッシュの完全削除
  • Apache の conf.d に残る VirtualHost 設定ファイルの削除
  • certbot-renew.timer の無効化と削除

再構築したい場合や構成に問題が生じた場合は、一度 erase モードで全削除を行ってから再構築することでクリーンな状態を維持できます。

実行パターンに応じた使い分け

このスクリプトは、初回の導入、構成のやり直し、完全削除のみという3つの使い分けができるように設計されています。用途に応じて、以下の実行パターンを選択してください。

目的実行コマンド引数説明
初回導入-d www.example.com -e user@example.com構築のみを実行します。事前にApacheが入っていないことが前提です。
再導入(削除→構築)-d www.example.com -e user@example.com -m eraseApacheおよびLet's Encrypt関連の構成をすべて削除したあと、直ちに再構築を行います。
完全削除のみ-m erase_only構築は行わず、Apacheと証明書、conf、systemd設定をすべて削除します。

再導入は構成をクリーンに戻したうえで安全に再構築したい場合に便利です。一方で、confファイルを残したい、または構成の復元を伴わない単純削除が目的であれば -m erase_only による実行が適しています。

et's Encryptのスクリプト再実行時の注意点

同じ構成を何度も繰り返し適用したい場合でも、Let's Encryptの仕様により証明書の発行には回数制限(Rate Limit)が存在します。

スクリプトはそのまま再実行できますが、証明書が取得できない場合には `certbot` のログを確認し、レート制限の対象時間を見極める必要があります。 また、スクリプトはconfを追記・上書きする形式ではなく、既存の httpd.conf を前提に一時的なVirtualHostを挿入→削除する構成です。

そのため、独自に編集したconfがある場合は上書きされないように注意してください。必要に応じてバックアップを取り、構成の整合性を維持してください。

よく読まれている記事

1

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか? 無料で使えるだけでなく、高い柔軟 ...

2

Linux環境でよく目にする「Vim」という名前。サーバーにログインしたら突然Vimが開いてしまい、「どうやって入力するの?」「保存や終了ができない!」と困った経験をした人も多いのではないでしょうか。 ...

3

ネットワーク技術は現代のITインフラにおいて不可欠な要素となっています。しかし、ネットワークを深く理解するためには、その基本となる「プロトコル」と「レイヤ」の概念をしっかり把握することが重要です。 こ ...

4

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

5

Javaは世界中で広く使われているプログラミング言語であり、特に業務システムやWebアプリケーションの開発において欠かせない存在です。本記事では、初心者向けにJavaの基礎知識を網羅し、環境構築から基 ...

-Shellの基礎知識(実践編)