Apache・NginxおよびSquidによるWebサーバーの構築(LinuC202学習) #1
各種ソフトウェアに関しての概要
Apache
正式にはApache HTTP Server。歴史が長く、今も多く使われるOSSのWebサーバーソフトウェア。
Nginx
現在最も多く利用されているとされるWebサーバーソフトウェア。リバースプロキシとしても機能。
Squid
フォワードプロキシとして動作させることができるソフトウェア。リバースプロキシとしても機能できる。
構築
本稿の作業はすべてrootユーザーで行われる想定。(そのため、sudoは行っていません)
サーバー構成
構成図
サーバーが様々存在するので超簡易的に構成を記載。
- マシンはVagrantテンプレートをもとにVirtualBoxにプロビジョニングされる。
- サーバー・クライアントともにUbuntu。
- クライアントフォワードプロキシとしてSquidが機能。
- 各Webサーバーのうち、Nginxがホストされている
192.168.3.2
の/redirect-source
にアクセスするときリバースプロキシとして機能する。 - Apacheの
192.168.3.1/redirect-target
からコンテンツを取得し、レスポンスする。
Vagrantfile
Vagrant.configure("2") do |config|
config.vm.define "apache-server" do |apache_server|
apache_server.vm.box = "bento/ubuntu-24.04"
apache_server.vm.hostname = "apache-server"
apache_server.vm.network "private_network", ip: "192.168.3.10"
apache_server.vm.provider "virtualbox" do |vb|
vb.name = "apache-server"
vb.memory = 1024
vb.cpus = 1
end
end
config.vm.define "nginx-server" do |nginx_server|
nginx_server.vm.box = "bento/ubuntu-24.04"
nginx_server.vm.hostname = "nginx-server"
nginx_server.vm.network "private_network", ip: "192.168.3.11"
nginx_server.vm.provider "virtualbox" do |vb|
vb.name = "nginx-server"
vb.memory = 1024
vb.cpus = 1
end
end
config.vm.define "squid-server" do |squid_server|
squid_server.vm.box = "bento/ubuntu-24.04"
squid_server.vm.hostname = "squid-server"
squid_server.vm.network "private_network", ip: "192.168.3.12"
squid_server.vm.provider "virtualbox" do |vb|
vb.name = "squid-server"
vb.memory = 1024
vb.cpus = 1
end
end
config.vm.define "web-client" do |web_client|
web_client.vm.box = "bento/ubuntu-24.04"
web_client.vm.hostname = "web-client"
web_client.vm.network "private_network", ip: "192.168.3.13"
web_client.vm.provider "virtualbox" do |vb|
vb.name = "web-client"
vb.memory = 1024
vb.cpus = 1
end
end
config.vm.provision "shell", inline: <<-SHELL
sudo sh -c "echo 'DNS=8.8.8.8' >> /etc/systemd/resolved.conf"
unlink /etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
SHELL
end
Apache設定
インストールとアクセス確認
以下コマンドでインストール~アクセス確認までを一気に実施。
apt update
apt install apache2 -y
systemctl status apache2 # この時点で起動と有効化がされているはず。
systemctl start apache2
systemctl enable apache2
ufw status
ufw allow http
ufw allow https
ufw enable
ufw status
curl http://localhost
Basic認証
Apacheにおける簡易的な認証はBasic認証によって行える。Basic認証用のモジュールはmod_auth_basic
。
a2enmod auth_basic
で有効化する。
a2enmod auth_basic
# 下記ではすでにenableになっている
> Considering dependency authn_core for auth_basic:
> Module authn_core already enabled
> Module auth_basic already enabled
以下コマンドでtestuserユーザーを作成。パスワードはtestuser。
htpasswd -c /etc/apache2/.htpasswd testuser # testuserというユーザー名で/etc/apache2/.htpasswd にユーザー情報を作成
> New password: # パスワード。ここではtestuserと入力
> Re-type new password: # testuserと入力
> Adding password for user testuser
デフォルトで作成されている/etc/apache2/sites-available/000-default.conf
を編集する。
<VirtualHost *:80>
+ <Directory "/var/www/html/basic">
+ AuthType Basic
+ AuthName "Basic Auth Area"
+ AuthUserFile /etc/apache2/.htpasswd # 先ほど作成したユーザー情報が格納されたファイルを指定
+ Require valid-user
+ </Directory>
</VirtualHost>
apache2ctl configtest
コマンドでconfの構文を確認する。問題がなければSyntax OK
と出力される。
apache2ctl configtest
# サーバー名がないと言われているものの、Syntax OKの出力。
> AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.2.1. Set the 'ServerName' directive globally to suppress this message
> Syntax OK
以下コマンドで/var/www/html/basic/index.html
を作成する
mkdir /var/www/html/basic/
echo "Hello, Authorized User!"> /var/www/html/basic/index.html
apache2を再起動。
systemctl restart apache2
/var/www/html/basic/index.html
にcurl。正しいユーザー・パスワードを-u
オプションで指定すれば認証に成功し、htmlコンテンツがレスポンスされる。
curl -u testuser:testuser http://localhost/basic/index.html
> Hello, Authorized User!
# もし認証情報に誤りがあった場合は401番が返される
curl -u testuser:badpassword http://localhost/basic/index.html
> <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
> <html><head>
> <title>401 Unauthorized</title>
> </head><body>
> <h1>Unauthorized</h1>
> <p>This server could not verify that you
> are authorized to access the document
> requested. Either you supplied the wrong
> credentials (e.g., bad password), or your
> browser doesn't understand how to supply
> the credentials required.</p>
> <hr>
> <address>Apache/2.4.58 (Ubuntu) Server at localhost Port 80</address>
> </body></html>
アクセス制限
mod_authz_host
によってIPアドレスによるアクセス制限が可能。
a2enmod authz_host
# 通常時はすでにenabled
> Considering dependency authz_core for authz_host:
> Module authz_core already enabled
> Module authz_host already enabled
mkdir /var/www/html/client-only
echo "hello, Client!"> /var/www/html/client-only/index.html
/etc/apache2/sites-available/000-default.conf
を以下のように編集。
<VirtualHost *:80>
+ <Directory "/var/www/html/client-only"> # 先ほどmkdirしたclient-onlyにIP制限をかける
+ Order Deny,Allow # DenyとAllowが評価される順番。Denyが先に評価される。
+ Deny from all # 全IPアドレスからのアクセスをDeny
+ Allow from 192.168.3.13 # 192.168.3.13からのアクセスをAllow
+ </Directory>
</VirtualHost>
評価順がDeny→Allowなので、allで塞がれた経路があとに評価されるallow {特定のIPアドレス}
によって、そのアドレスのみに穴が開く形となる。
ここまででconfigtestと再起動を行う。
apache2ctl configtest # Syntax OKの出力を確認
systemctl restart apache2
これで準備完了。Webサーバーからのローカルアクセスとクライアントアクセスを比較する。
まずはWebサーバーからのCurl。
root@apache-server:~# curl http://192.168.3.10/client-only/index.html # apache-serverからCurlを実行。
> <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
> <html><head>
> <title>403 Forbidden</title> # 403でアクセス拒否。
> </head><body>
> <h1>Forbidden</h1>
> <p>You don't have permission to access this resource.</p>
> <hr>
> <address>Apache/2.4.58 (Ubuntu) Server at 192.168.3.10 Port 80</address>
> </body></html>
アクセス権限がないということで403番がレスポンスされる。
続いてクライアントからのCurl。
vagrant@web-client:~$ curl http://192.168.3.10/client-only/index.html # クライアントからCurl
hello, Client! # index.htmlのコンテンツをレスポンス
アクセス成功。
リライト(.htaccessの編集によって)
特定のURLにアクセスされた際、URLを書き換えるリライトの実装。
今回はドキュメントディレクトリにリライトの設定が記載された.htaccess
を設置し、実装する。.htaccess
は個々のディレクトリに配置することで、その範囲内で記載の設定を機能させることができる設定ファイルである。
しかし、.conf上で対象のディレクトリで明示的にAllowOverride
をしている必要がある。設定への記載は後述。
ディレクトリとファイルの準備。
mkdir /var/www/html/redirect
mkdir /var/www/html/redirect-target
echo "hello, Redirected User!"> /var/www/html/redirect-target/index.html
モジュールmod_rewrite
を有効化する。
a2enmod rewrite
/var/www/html/redirect
ディレクトリに.htaccess
ファイルを作成、以下のように編集する。
RewriteEngine On # mod_rewriteを有効にする
RewriteRule ^$ /redirect-target [R=301,L] # リライトのルールを記載。
/redirect
に対して「/redirect-target」を置き換える(追記する)。
また、301番でリダイレクトをし、以降のリライト処理を中止する。
つまり、もしドメインがexample.com
の場合、 http://example.com/redirect
にアクセスしたら、http://example.com/redirect-target
にURLが置き換えられたうえで301リダイレクトが行われる。
http://example.com/redirect-target
では更にリダイレクトが発生しhttp://example.com/redirect-target/index.html
が返される格好である。
最後に/etc/apache2/sites-available/000-default.conf
を以下のように編集し、AllowOverrideする。
<VirtualHost *:80>
+ <Directory /var/www/html>
+ AllowOverride All
+ </Directory>
</VirtualHost>
再起動とCurlの実行。Curlに-L
オプションを付けてリダイレクトを許容。リダイレクト先であるhttp://localhost/redirect-target/index.html
のレスポンスが得られる。
systemctl restart apache2
curl -L http://localhost/redirect/
> hello, Redirected User!
TLS設定(OpenSSLによる自己署名証明書の発行)
HTTPS通信を行うためにはサーバー証明書が必要になる。一般的にはLet's Encrypt、Degicertなどの認証局にCSRを渡し、それらCAの署名付きの証明書を受け取り、利用する。
しかし今回はテストということで自己署名証明を使うことでそれらを賄う。もちろん一般に公開するWebサイトでは利用に耐えないので、テスト用、プライベート環境での利用に留めるべきである。
証明書のSANsにはIPアドレスを設定することができるので、今回はそれを用いてSSLを実現する。
秘密鍵を作成。
openssl genpkey -algorithm RSA -out private.key
以下のopenssl.cnf
を作成する。
[ req ]
default_bits = 2048 # 鍵の長さを2048ビット
distinguished_name = req_distinguished_name # ディスティングイッシュネームを設定する。ここでは下記の[ req_distinguished_name ] で規定するとしている。
req_extensions = req_ext # 追加の拡張設定を[ req_ext ] にて規定するとしている
prompt = no # コマンド実行時に対話的なプロンプトは表示せず、このcnfファイル内の設定を使用する
[ req_distinguished_name ] # 証明書に含まれる識別情報
C = JP # CountryのC。日本のJP
ST = Tokyo # StateのST。Tokyo
L = Chiyoda-ku # LocalityのL。千代田区としてChiyoda-ku
O = Example Company # OrganizationのO。一般には企業名などが入るが、Example Companyと仮置き。
CN = example.com # Common NameのCN。ドメイン名を入れる。ここではexample.comと仮置き。
[ req_ext ]
subjectAltName = @alt_names # SANの設定。下の[ alt_names ]の部分で定義。
[ alt_names ]
IP.1 = 192.168.3.10 # サブジェクトの別名としてこのApacheのIPアドレスを設定
IP.2 = 192.168.3.11 # NginxのIPアドレスも設定。(もちろん実運用ではドメイン名を設定することがごく一般的)
先ほど作成した秘密鍵をもとにCSR(証明書署名要求)を作成。
openssl req -new -key private.key -out certificate.csr -config openssl.cnf
CSRをもとに証明書を作成。
openssl x509 -req -days 365 -in certificate.csr -signkey private.key -out selfsigned.crt
これらを/etc/ssl/
配下に移動
cp selfsigned.crt /etc/ssl/certs/
cp private.key /etc/ssl/private/
rm private.key # 証明書は削除しておく
TLS設定(apacheへの証明書インストール)
mod_ssl
を有効化する。
sudo a2enmod ssl
> a2enmod ssl
> Considering dependency mime for ssl: Module mime already enabled
> Considering dependency socache_shmcb for ssl:
> Module socache_shmcb already enabled
> Enabling module ssl.
> See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
> To activate the new configuration, you need to run:
> systemctl restart apache2
すでに存在する/etc/apache2/sites-enabled/default-ssl.conf
を以下のように編集する。
<VirtualHost *:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
+ SSLEngine on
+
+ SSLCertificateFile /etc/ssl/certs/selfsigned.csr # 先ほど設置した証明書
+ SSLCertificateKeyFile /etc/ssl/private/private.key # 先ほど設置した秘密鍵
+ SSLProtocol +TLSv1.2 # TLS1.2以上を使用する(逆に安全ではないSSLやTLS1.0、TLS1.1は使わない)
+ SSLCipherSuite HIGH:!aNULL:!MD5:!3DES # 暗号スイート設定。HIGH:キー長が128bit以上、!aNULL:暗号化なしを除外(!は除外の意)、!MD5/!3DES:安全ではないスイートを除外
</VirtualHost>
先程までとは別の設定ファイルを編集しているが、default-ssl.conf
はデフォルトで設定ファイルとして読み込まれない。
a2ensite
コマンドで有効化してあげる。
a2ensite default-ssl
> Enabling site default-ssl.
> To activate the new configuration, you need to run:
> systemctl reload apache2
ここまでの設定を適用するためにapache2を再起動
systemctl restart apache2
Curlしてみる。curl https://192.168.3.10
では失敗する。自己署名証明書であり、その正当性を確認できないためである。
curl -v https://192.168.3.10
> * Trying 192.168.3.10:443...
> * Connected to 192.168.3.10 (192.168.3.10) port 443
> * ALPN: curl offers h2,http/1.1
> * TLSv1.3 (OUT), TLS handshake, Client hello (1):
> * CAfile: /etc/ssl/certs/ca-certificates.crt
> * CApath: /etc/ssl/certs
> * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11):
> * TLSv1.2 (OUT), TLS alert, unknown CA (560):
> * SSL certificate problem: self-signed certificate
> * Closing connection
> curl: (60) SSL certificate problem: self-signed certificate # 自己署名証明書だということのお叱り
> More details here: https://curl.se/docs/sslcerts.html
>
> curl failed to verify the legitimacy of the server and therefore could not
> establish a secure connection to it. To learn more about this situation and
> how to fix it, please visit the web page mentioned above.
verboseで提示されたdocsを見ると「-k
オプションで無視するか、--cacert
、--with-ca-bundle=
などオプションで証明書を提示してくれ」とのこと。
無視するのは甲斐がないので、--cacert
してみよう。
curl --cacert /etc/ssl/certs/selfsigned.crt https://192.168.3.10
> hello, world!
成功。
次回に続く
続きはTBUです。
Discussion