~ To be, or not to be, or to take a lunch anyway. ~ null-i.net |
Linux/CentOS Stream8でサーバ構築/Webサーバ編 | |
Webサーバ関連(2022-03-11) 前回の メール編 に引き続き、CentOS Stream8での作業となります。*1 wgetコマンドのインストール†指定したURLからコンテンツをゲットするためのコマンドです。 $ dnf install wget Webサーバにアクセスできるかを確認したり、どこかからファイルをダウンロードする時などに使えます。 Apache httpd のインストール†言わずと知れたWebサーバの老舗。 $ dnf install httpd それから/etc/httpd配下にあるconfigを設定します。 conf/httpd.conf Listen 80 # 動作確認用に、とりあえず起動 # Listen 127.0.0.1:8080 # 後述のプロキシ(squid)起動後はこちら ...(中略)... ServerName サーバ名 # ここに限らず全体的に「cgi-bin」は狙われやすいので # 自分の使うWikiやCGIツール上の制約がなければ # 「mv cgi-bin cgi-bon」とかで置き換えてしまった方が無難だと思う ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" ...(中略)... <IfModule mime_module> ...(中略)... AddHandler cgi-script .php # うちのサイトではCGIとしてphpを使っています # 他に必要なCGI関連の設定は以下を参照 # https://httpd.apache.org/docs/2.2/ja/howto/cgi.html ... </IfModule> ... # 以下を追記、ゆるいセキュリティ対応 LimitRequestBody 102400 # 初期値は無制限、これは100Kまでに制限する例 LimitRequestFields 50 # 初期値は100、もっとずっと減らして良い ServerTokens Prod # 初期値はFull、応答ヘッダの情報は最小限にしたい。 TraceEnable Off # 初期値はOn、TRACEメソッドを許可する理由は特に無いので。 # あと、うちの環境だとプロキシ(squid)を使うので # LogFormat "%{%y%m%d/%H:%M:%S}t %{X-Forwarded-For}i ... # のように転送前の情報が分かるように、ログにX-Forwarded-Forを追加しています
conf.modules.d/00-mpm.conf LoadModule mpm_prefork_module modules/mod_mpm_prefork.so # この行を有効にする # LoadModule mpm_event_module modules/mod_mpm_event.so # こっちはコメントアウト PHPはスレッドセーフではありません、そしてパッケージからいれた httpdの初期値はスレッド起動(MPM)でした。 Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP. Webサーバで大量のアクセスをさばく場合はプロセス(prefork)ではなくスレッド(mpm)にするべきでしょうけれど、そこまでする必要は無いので素直にprefork起動に変えました。 あと、この時点ではhttpsに未対応です。うちの環境ではSSL/TLS接続はリバースプロキシ(squid)側で受けつけます。 $ firewall-cmd --add-service=http --zone=public --permanent $ firewall-cmd --add-service=https --zone=public --permanent $ firewall-cmd --reload $ firewall-cmd --list-all
$ systemctl enable httpd $ systemctl start httpd 最近のブラウザだとデフォルトでhttps(=443)に繋ぎそうなので、http(=80)の方になるように気をつけつつ動作確認します。 余談:phpでどれをインストールするか†WebサイトでCGIを使う場合は php も入れることが多いと思います。 $ dnf info php Name : php Version : 7.2.24 ところが、Remiを指定して探すと $ dnf --enablerepo=remi-safe search php (以下、抜粋) php.x86_64 : PHP scripting language for creating dynamic web sites php72.x86_64 : Package that installs PHP 7.2 php73.x86_64 : Package that installs PHP 7.3 php74.x86_64 : Package that installs PHP 7.4 (以下、省略) のような感じで新しいバージョンがいっぱい出て来るので、場合によっては 余談:Digest認証を使う例†こんな風に httpd.confを設定することで、アクセス時にパスワード認証を要求できます。 <Directory "指定ディレクトリ"> AuthType Digest AuthName "realm_name" AuthUserFile /etc/httpd/htdigestファイルを置いたPATH Require user user_name </Directory> $ htdigest [-c] htdigest realm_name user_name (-c を指定すると新規作成になります) 作成された htdigest ファイルを上記AuthUserFileで指定したPATHに置く なんでこれをメモしたかといえば、 余談:Listen loccalhost:8080 とした場合に失敗する件†squidを起動した後に httpd.conf で Listen hocalhost:8080 した場合、httpdの起動に失敗しました。 Address already in use: AH00072: make_sock: could not bind to address 127.0.0.1:8080 これはどうやら /etc/hosts で localhostとしてIPv4(127.0.0.1)とIPv6(::1)の二つあるときに、両方で bindを試みて失敗するようです。 squid のインストール†リバースプロキシとして使うためにインストールします。 Webブラウサ <--> squid <--> apache-httpd というように通信の仲介をするのが プロキシ(リバースプロキシ)のお仕事です
$ dnf install squid それから squid.confを設定します。 # http_access deny all # 前半のこれはコメントアウト。 # 自分でルールを追記した後にあらためてこれを書きます # 以下、https://wiki.squid-cache.org/ConfigExamples/Reverse/BasicAccelerator あたりを参考に http_port 80 accel defaultsite=localhost https_port 443 accel tls-cert=証明書 tls-key=秘密鍵 defaultsite=localhost protocol=HTTPS # letsencrypt の場合はそれぞれ # cert=/etc/letsencrypt/live/ドメイン名/fullchain.pem # tls-key=/etc/letsencrypt/live/ドメイン名/privkey.pem cache deny all # キャッシュはしないで毎回Webサーバへ取りにいく httpd_suppress_version_string on # エラーページでsquidの情報を隠す # なお、error_directory で自前のエラーページを作成した方がもっと情報を隠せます # ログ書式は特に時刻がデフォルトだと秒なので、変える事を推奨 # logformat httplog 任意のフォーマット # ログ書式 # (フォーマット例:%tl %>a [%>Hs] %Ss %>st %<st [%>rm %>ru ] [%{User-Agent}>h] [%{Referer}>h]) # access_log daemon:ログのPATH httplog # 書式と保存場所を指定 # logfile_rotate 30 # ログのローテーション日数 # ---このlogfile_rotateを踏まえて、cronとかでローテーションをかける--- # 例: 0 0 * * * /usr/sbin/squid -k rotate #----------------------- ## 今回 squidを使っている理由と言っても過言では無い部分 ## 指定した正規表現にかかったアクセスはTCPリセットで強制断する # acl bad_url urlpath_regex URL指定の正規表現 # http_access deny bad_url # deny_info TCP_RESET bad_url # ## 逆にホワイトリスト方式で絞る案。こっちで書いた方が楽かも? # acl good_url urlpath_regex URL指定の正規表現 # http_access deny !good_url #----------------------- # 自分のサイトのドメイン名へのアクセスのみを許可する # 不正アクセスで片っ端から漁るときは「IPアドレス直打ち」で来るので、それらを拒絶する acl web_client dstdomain ドメイン名(うちのサイトの場合はnull-i.net www.null-i.netなど) http_access allow web_client # httpd に(localhost:8080 でListenさせて)転送する cache_peer 127.0.0.1 parent 8080 0 no-digest no-query originserver login=PASS name=my_accel cache_peer_access my_accel allow web_client http_access deny all # すべてのルールに漏れたものは最後に deny # おまじない1。UDPポートでグローバルIPへLISTENされるのを防ぐ。 # 本来は ICPや DNSの連携に使うらしいけど、うちでは使わない想定なので。 udp_incoming_address 127.0.0.1 # おまじない2。以下のようなエラーが出る場合に回避する。 ## comm_udp_sendto FD x, (family=2) xx.xx.xx.xx:53: (22) Invalid argument ## idnsSendQuery FD x: sendto: (22) Invalid argument udp_outgoing_address 自分のIP 以前は cache_peer に no-digest は付けていなかったのですが、ログに「/squid-internal-periodic/store_digest」が頻発するようになってしまったので今回から追加しました。*4 $ systemctl start squid $ systemctl enable squid 特に acl 部分の書き方は慣れだと思います。 余談:URLを日本語に戻す†ブラウザ上でURLへ「index.html?ぬるいねっと」と入力すると、 $ echo %E3%81%AC | perl -MURI::Escape -pe 'print uri_unescape $_' $ echo %E3%81%AC | perl -e 'while(<STDIN>){ s/%([0-9a-fA-F]{2})/pack("H2",$1)/ge; printf("%s\n", $_); }'
$ echo %25E3%2581%25AC | perl -MURI::Escape -pe 's/%25/%/g; print uri_unescape $_' $ echo %25E3%2581%25AC | perl -e 'while(<STDIN>){ s/%25/%/g; s/%([0-9a-fA-F]{2})/pack("H2",$1)/ge; printf("%s\n", $_); }'
以上、Webサーバの設定でした。 |
|