Cloudflare からの HTTP リクエストヘッダを可視化する



# はじめに

Web サイトに Cloudflare の Proxy を適用すると、元々の HTTP リクエストに対してヘッダが追加されます。
そうしたヘッダ情報を可視化することで、理解を深めたり、トラブルシューティングに役立てることができます。

> [How does Cloudflare handle HTTP Request headers?](https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-#)

# Origin サーバー準備

## CentOS 8 + Apache + PHP を準備

確認したバージョンです。

```shell
$ cat /etc/redhat-release 
CentOS Linux release 8.4.2105
```

Apache + PHP をインストールします。

```shell
sudo dnf install -y httpd php
sudo systemctl --now enable httpd
sudo systemctl --now enable php-fpm
```

## PHP 稼働設定

html 内で php が動くように設定します。

```shell
lineNum=`sudo grep "security.limit_extensions" -n /etc/php-fpm.d/www.conf | cut -d ":" -f 1`
echo $lineNum

sudo sed -i -e "${lineNum}a \security.limit_extensions = .php .php3 .php4 .php5 .php7 .html" /etc/php-fpm.d/www.conf
cat /etc/php-fpm.d/www.conf| grep security.limit_extensions
```

```shell
sudo sed -i -e s/phar/phar\|html/g /etc/httpd/conf.d/php.conf
cat /etc/httpd/conf.d/php.conf | grep phar
```

設定変更を反映するために、サービスを再起動します。

```shell
sudo systemctl restart httpd
sudo systemctl restart php-fpm
```

## 全ての HTTP リクエストヘッダを返す HTML を作成

以下のように HTML ファイルを作成します。

```shell
sudo chown -R $USER:$USER /var/www
cat << 'EOS' > /var/www/html/index.html
<?php
  echo php_uname('n');
  echo " <br />\n";
  echo " <br />\n";
  $headers = apache_request_headers();
  foreach ($headers as $header => $value) {
    echo "$header: $value <br />\n";
  }
?>
EOS
```

## 稼働確認

以下のようなレスポンスが確認できます。

```shell
curl localhost
```

```shell
Accept: */* <br />
User-Agent: curl/7.61.1 <br />
Host: localhost <br />
```

# Cloudflare Proxy なし

以下のように Proxy Status が OFF の状態で確認します。

![image-20210615120727950](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210615120727950.png)

![image-20210614142841413](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210614142841413.png)

`curl -v` のコマンドで以下のようにヘッダ情報が確認できます。

```shell
% curl -v khayama.ml        
*   Trying 34.xx.xx.xx...
* TCP_NODELAY set
* Connected to khayama.ml (34.xx.xx.xx) port 80 (#0) 
```

## HTTP リクエストヘッダ (Client --> Origin)

```shell
> GET / HTTP/1.1
> Host: khayama.ml
> User-Agent: curl/7.64.1
> Accept: */*
>
```

## HTTP レスポンスヘッダ (Client <-- Origin)

```shell
< HTTP/1.1 200 OK
< Date: Tue, 15 Jun 2021 02:45:11 GMT
< Server: Apache/2.4.37 (centos)
< X-Powered-By: PHP/7.2.24
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
<
```

# Cloudflare Proxy あり

以下のように Proxy Status が ON の状態で確認します。

![image-20210615121005010](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210615121005010.png)

![image-20210614142645675](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210614142653294.png)

以下のコマンドでプライベートモードにてページを確認できます。

```shell
open -a "Google Chrome" --args --incognito "http://khayama.ml"             
```

## HTTP リクエストヘッダ (Cloudflare --> Origin)

Cloudflare によって `Cf-XXX` のヘッダ等が追加されていることがわかります。
Cloudflare の他の機能を有効化することで、他のヘッダ情報が追加されることがあります。

```shell
% curl khayama.ml                
Cf-Request-Id: 0aaf42842e000023771f8e8000000001 <br />
Cdn-Loop: cloudflare <br />
True-Client-Ip: 116.xx.xx.xx <br />
Cf-Connecting-Ip: 116.xx.xx.xx <br />
Accept: */* <br />
User-Agent: curl/7.64.1 <br />
Cf-Visitor: {"scheme":"http"} <br />
X-Forwarded-Proto: http <br />
Cf-Ray: 65f8a04d1c492377-NRT <br />
X-Forwarded-For: 116.xx.xx.xx <br />
Cf-Ipcountry: JP <br />
Accept-Encoding: gzip <br />
Connection: Keep-Alive <br />
Host: khayama.ml <br />
```

## HTTP レスポンスヘッダ (Client <-- Cloudflare)

エンドユーザー視点でも Cloudflare から応答があったということが確認できます。

```shell
% curl -I khayama.ml                                    
HTTP/1.1 200 OK
Date: Tue, 15 Jun 2021 03:22:23 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/7.2.24
CF-Cache-Status: DYNAMIC
cf-request-id: 0aaf4a1d0100000df94d2a2000000001
Server: cloudflare
CF-RAY: 65f8ac74cb670df9-NRT
```

# さいごに

Cloudflare を扱うエンジニアはこういった環境は持っておきたいところです。
Origin サーバーすら準備したくないという人は、Cloudflare Workers を活用して同様の環境を作ることができますので、参考にしてみてください。

> [Logging headers · Cloudflare Workers docs](https://developers.cloudflare.com/workers/examples/logging-headers)

# 参考リンク

- [PHP - Cent OS 8のApacheで.htmlファイル内のPHPを実行したい｜teratail](https://teratail.com/questions/235760)
- [Vagrant+CentOS7+シェルスクリプトでちゃちゃっとPHPテスト環境構築 - walkingmask’s development log](https://walkingmask.hatenablog.com/entry/2016/07/08/115025)
- [PHP: apache_request_headers - Manual](https://www.php.net/manual/en/function.apache-request-headers.php)

# 参考 : Cloudflare Origin Certificates をオリジンにインストールする

- [Origin CA certificates · Cloudflare SSL/TLS docs](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/)

以下の画面から `Create Certificates` し、証明書ファイルをダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/677bc11d-4ff7-1f93-42a0-6cfaf64d29f4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/63b66f3c-833e-d234-94d8-1b58e0edc406.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/ac85ac72-e20f-ec73-0bed-baf7339ca1d9.png)


ダウンロードした証明書の中身をオリジンサーバの `/etc/cloudflare` に配置します。

```shell:
export DOMAIN=example.com

sudo mkdir -p /etc/cloudflare
sudo vi /etc/cloudflare/${DOMAIN}.pem
sudo vi /etc/cloudflare/${DOMAIN}.key
```

その後 `ssl.conf` を修正し、サービスを再起動すれば反映されます。

```shell:
sudo dnf install -y mod_ssl
sudo vi /etc/httpd/conf.d/ssl.conf
```

```conf:/etc/httpd/conf.d/ssl.conf
SSLCertificateFile /etc/cloudflare/${DOMAIN}.pem
SSLCertificateKeyFile /etc/cloudflare/${DOMAIN}.key
```

```shell:
sudo systemctl restart httpd
```

# 参考：9443 ポートで動かす
SE Linux の許可リストにない 9443 ポートで動かすには、以下の追加設定が必要です。

- [apache - httpd Server not started: (13)Permission denied: make_sock: could not bind to address [::]:88 - Stack Overflow](https://stackoverflow.com/questions/17079670/httpd-server-not-started-13permission-denied-make-sock-could-not-bind-to-ad)

```conf:/etc/httpd/conf.d/ssl.conf
Listen 9443 https

<VirtualHost _default_:9443>
...
</VirtualHost>
```

```shell:
sudo yum -y install policycoreutils-python-utils
sudo semanage port -a -t http_port_t -p tcp 9443
sudo systemctl restart httpd
```