【C】接続元IPアドレスの JSON を返すだけの Apache モジュールを作ってみる

こんにちは。
普段まだまだ業務でも使う機会の多い Apache ですが、そういえばモジュール周りってどういう風に実装されているんだろうと調べてみた備忘録です。
雛型自体は apxs コマンドで自動的に生成されるそうなので、接続元 IP アドレスの JSON を返すだけの API みたいなよく分からない Apache モジュールを作ってみます。

※ PHP だったら下記2行で終わるんですけどね。

<?php
        $json = ['remote_ip' => $_SERVER["REMOTE_ADDR"]];
        echo json_encode($json);

環境構築

はい、勿論Apacheのモジュールなんで、Apacheの本体と、apxsコマンドを使うので開発ツールを導入します。
ただそれだけ~。

yum groupinstall "Development tools"
yum install httpd httpd-devel

apxsコマンドで雛型を作ります。
cd /usr/local/src
apxs -g -n info
cd info/

下記みたいなディレクトリとファイルが生成されるんで、mod_info.c に処理を書いていきます。
[root@test-server1-1 src]# tree
.
└── info
    ├── Makefile
    ├── mod_info.c
    └── modules.mk

1 directory, 3 files

コード

はい、雛型に1行加えただけです…

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

/* The sample content handler */
static int info_handler(request_rec *r)
{
    if (strcmp(r->handler, "info")) {
        return DECLINED;
    }
    r->content_type = "text/html";

    if (!r->header_only) {
        /* 接続元IPを表示する */
        ap_rprintf(r,"{\"client_ip\":\"%s\"}\n",r->connection->client_ip);
    }
    return OK;
}

static void info_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(info_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA info_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    info_register_hooks  /* register hooks                      */
};

接続元 IP は構造体のポインタ r , connection のメンバである client_ip に格納されているので、ap_rprintf 関数でこれを表示させます。
/**
*Output data to the client in a printf format
*
*@Parameters
*      r      The current request
*      fmt      The format string
*      ...      The arguments to use to fill out the format string
*
*@Returns
*      The number of bytes sent
*/
int ap_rprintf( request_rec * 	r,
                const char *    fmt,
                                ... 
)

コンパイル

こちらも apxs コマンドでモジュールのコンパイルと Apache へのモジュールのロード設定まで自動で完了します。

# ディレクトリ移動&コンパイル
cd /usr/local/src/info
apxs -c -i -a mod_info.c

# Apache設定追加
cat >> /etc/httpd/conf/httpd.conf << EOF
<Location "/info">
    SetHandler info
</Location>
EOF

# Apache起動
systemctl start httpd

curl で叩いたら json が返ってきますね。OKです。

keisuke@DESKTOP-MOGIJIA:~$ curl http://192.168.33.10/info
{"client_ip":"192.168.33.1"}

【bash】アクセスログ集計【チラ裏】

完全にチラ裏ですね。よく忘れるので…

# アクセスの多いIPアドレスの上位10件を表示
tail -n 10000 fingerease.work_access.log | awk '{print $1}' | cut -f2 | cut -d: -f2 | sort -n | uniq -c | sort -rn | head

# 分単位のアクセス数を表示
tail -n 10000 fingerease.work_access.log | awk '{print $4}' | awk -F":" '{print $1" "$2":"$3}' | sort | uniq -c

【JDK】Remote host closed connection during handshakeのエラー【apache】

Remote host closed connection during handshake ってエラーがでて四苦八苦した備忘録です。

背景

サーバにて表題のエラーがでて困ったの。

結論

IBM JDK は TLSv1.0 で通信するそうな。
根本的な要因は Apache の設定で TLSv1.1 / TLSv1.2 以外のプロトコルを許可していなかったため。

↓ Apache のパラメータを下記のように書き換え

# TLSv1.0 含め許可
====================================
SSLProtocol ALL -SSLv2 -SSLv3
====================================

# Apache リロード
systemctl reload httpd

下記サイトで許可している SSLProtocol を確認できます。
https://www.cman.jp/network/support/ssl.html

【シェルスクリプト】apacheのrotatelogsとシェルスクリプトでログ管理をする【運用】

お疲れ様です。
rotatelogsでapacheのログを出力している環境でログを管理する必要があったので、忘備録として残しておきます。

背景

CustomLog "|/usr/local/apache2/bin/rotatelogs /usr/local/apache2/logs/access_log.%Y%m%d%H 14400 540" combined  env=!no_log
ErrorLog "|/usr/local/apache2/bin/rotatelogs /usr/local/apache2/logs/error_log.%Y%m%d 86400 540"

apacheに標準でついてくるrotatelogsでログが世代管理されている前提でですね、
2週間経過したログは削除、1日経過したログは圧縮するスクリプトを作ってcronに登録してみます。

スクリプトの作成

vi /usr/local/bin/apache_accesslog_compress.sh
====================================================================
#!/bin/sh
#ディレクトリを移動する
cd /usr/local/apache2/logs
#14日経過したログを削除する
find ./ -name 'access_log.*' -mtime +13 -daystart -exec rm {} \;
#1日経過したログを圧縮する
find ./ -name 'access_log.*' -mtime +0 -daystart  -exec gzip {} \;
====================================================================

findコマンドの-daystartは
コマンドを実行した日の00:00を-mtimeの基準とするオプションです。

cronへの登録

crontab -e
=======================================================
00 04 * * * /usr/local/bin/apache_accesslog_compress.sh
=======================================================

Let’s Encrypt で証明書を取得する

こんにちは。
急に寒くなってきましたね。
ところで Let’s Encrypt でサイトを SSL化しました。
その際の備忘録になります。

certbotのインストール

epel から certbot のパッケージを落とします。

yum install epel-release
yum install certbot

証明書の取得

certbot certonly --webroot \
-w 【ドキュメントルート】 \
-d 【ドメイン名】 \
-m 【メールアドレス】 \
--agree-tos -n

※ 下記ディレクトリに証明書が生成されます。

# サーバ証明書
/etc/letsencrypt/live/【ドメイン名】/cert.pem
# 秘密鍵
/etc/letsencrypt/live/【ドメイン名】/privkey.pem
# 中間証明書
/etc/letsencrypt/live/【ドメイン名】/chain.pem

あとは、WEBサーバに設定すればOK

<VirtualHost *:443>
   ServerAdmin n41210guitar@gmail.com
   ServerName fingerease.work
   DocumentRoot "/var/www/vhosts/fingerease.work/public_html"
   DirectoryIndex wordpress index.php index.html index.xml
   <Directory /var/www/vhosts/fingerease.work/public_html>
           Options FollowSymLinks
           AllowOverride all
   </Directory>
   
   SSLEngine on
   SSLProtocol             all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
   SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
   SSLHonorCipherOrder     off

   SSLCertificateFile /etc/letsencrypt/live/fingerease.work/cert.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/fingerease.work/privkey.pem
   SSLCertificateChainFile /etc/letsencrypt/live/fingerease.work/chain.pem

   CustomLog "/var/log/httpd/fingerease.work-ssl-access_log" combined
   ErrorLog  "/var/log/httpd/fingerease.work-ssl-error_log"
</VirtualHost>