letsencrypt の certbot renew を apache plugin から nginx(webroot) に切り替える

環境

内容

もともと apache がサポートされていたため apache を利用して letsencrypt を利用していたが nginx を使うように変更したため nginx で直接 https 処理を行うように変更したい。

$ vim /etc/letsencrypt/renewal/example.com.conf

下記のようになっているはず

# Options used in the renewal process
[renewalparams]
authenticator = apache
installer = apache
account = ......

これを下記のように書き換える

# Options used in the renewal process
[renewalparams]
authenticator = webroot
installer = None
account = ......
[[webroot_map]]
example.com = /path/to/webroot

このあとそのまま certbot renew をするとよい。 また cron で自動で確認するようになっていると思うので /etc/cron.d/certbot の内容の一部を下記のように書き換える。reload でもいいかもしれないが自分の環境では特に気にすることもないためそのまま restart している。

.... && certbot -q renew
↓
.... && certbot -q renew --post-hook "service nginx restart"

--post-hook か --renew-hook がいいかは1年ぐらい運用したけど毎回失敗しててよくわからなかった。

BSD + ansible で sysrc を用いて利用可能にする

BSD 系では rc.conf に *_enable="YES" のような形で設定しないと init script 等で起動しない挙動をするようにするのが一般的な様子?(詳しくは未調査)

ansible でこのあたりを編集するのはつらいのでコマンドを用いて設定できるようにするには sysrc を使うと便利。 sysrc はどうやらデフォルトで入ってなさそう(少なくとも DragonflyBSD においては)なのでこれをインストールするタスクも入れる必要がある。 (汎用的に使うには role に設定して dependences にいれておいたほうが便利そう)

- name: install sysrc
  package:
    name: sysrc
    state: present

- name: enable openvpn
  command: sysrc -ni openvpn_enable="YES"
  register: openvpn_enable_rc
  changed_when: (openvpn_enable_rc.stdout == "NO -> YES") or (openvpn_enable_rc.stdout == " -> YES") 

上記の動作確認は DragonflyBSD で行ったがこの sysrc は存在してもしなくて return code は 0 を返すため設定に成功したかどうかわからず そのままでは changed 設定ができない。苦肉の策として標準出力を用いている。

sysrc の 実行例

以下はもとに設定がない場合。

n をつけない場合

$ sysrc openvpn_enable="YES" 
openvpn_enable:  -> YES

n をつけた場合

$ sysrc -n openvpn_enable="YES" 
 -> YES

i をつけない場合

$ sysrc openvpn_enable
sysrc: unknown variable 'openvpn_enable'

i をつける場合何もかえらない。そのキーが存在しない場合に sysrc: unknown variable 'openvpn_enable' といったメッセージを出す場合があるので前述の ansible task では 念のためつけている。(影響があるのは 設定する場合と -x で削除する場合)

$ sysrc -i openvpn_enable

e は以下のように ダブルクオーテーションの挙動がなにかおかしいので使ってない。

$ sysrc -e openvpn_enable="YES"
openvpn_enable=" -> YES

さくらの VPS 上の DragonflyBSD で ipv6 ネットワーク設定をする

環境

  • さくら のVPS
  • DragonFly v5.0.2-RELEASE

準備

さくら VPS のコントロールパネルで IPv6 アドレスとゲートウェイを確認する。 自分の場合は特に申請してなくてもついていたのでデフォルトで付いている様子。(契約タイミングやデータセンターによるかもしれない) -この IPv6 アドレスは サフィックスIPv4 アドレスが付いているパターンのものらしい [1]. - 追記)と思ったけど よーく見るとコンパネの記載にあるのは ドットではなくコロンのため、単純に同じ数字を用いた ipv6 アドレスという可能性のほうが高そう。

設定

vtnet0 インタフェースを用いる場合

/etc/rc.conf

# IPv6
ipv6_enable="YES"
ipv6_network_interfaces="vtnet0" # あってもなくてもいい
ipv6_defaultrouter="fe80::1%vtnet0"
ipv6_ifconfig_vtnet0="inet6 (コントロールパネルに表示されるIPv6アドレス) prefixlen 64"

他の設定については /etc/defaults/rc.conf を確認。

簡単に各項目を説明。

key default description
ipv6_enable NO ipv6 を使う場合に YES ( FreeBSD 9 以降?では 使うべきではないらしい が DragonflyBSD では関係ない様子)
ipv6_network_interfaces auto auto の場合は ifconfig -l の結果が入る。自分の場合は 別の設定名で インタフェースが必要なのでそれを使うという意図で明示している。
ipv6_defaultrouter NO コンパネで確認する ゲートウェイを入れる。 そのままだとなぜか通じないのでインタフェース名を入れると動く。( netstat -f inet6 -rn などを見ると %lo などがついている場合があったので)
ipv6_ifconfig_vtnet0 - ifconfig で設定する内容 ipv6_ifconfig プレフィックス の設定はipv6_network_interfaces の値に入っている場合に使われる様子

設定後は ssh で繋いでる場合は 下記の様にするとおそらく良い [2]。 ipv6 設定を反映するためには /etc/rc.d/network_ipv6 を使ったほうが良さそうな気がしてとりあえず入れているがきちんと検証してない。

$ sudo /etc/rc.d/netif restart && sudo /etc/rc.d/routing restart && sudo /etc/rc.d/network_ipv6 restart

つながっているかどうかは 外から ping6 を実行するなどして確認 [3]。

発生した問題

ping6 や sshipv6 アドレスを直接指定して動かした場合に動作せず、サーバ側のコンソールで下記のようなエラーが出る現象があった。

nd6_storelladdr: sdl_alen == 0
nd6_storelladdr: sdl_alen == 0
nd6_storelladdr: sdl_alen == 0

このエラーが出ている部分はこのあたり。 impossible と書いてあるけど…

/usr/src/sys/netinet6/nd6.c

2091     if (sdl->sdl_alen == 0) {
2092         /* this should be impossible, but we bark here for debugging */
2093         kprintf("nd6_storelladdr: sdl_alen == 0\n");
2094         m_freem(m);
2095         return (0);
2096     }

自分の場合の原因は、ipv6 アドレスの設定部分だった様子。 記事によっては ifconfig_vtnet0_ipv6 のような ifconfig プレフィックスになっている場合があるが、 少なくとも自分の環境ではこれでは動作せず、上記のような謎エラーが表示される。

ipv6 を prefix とするような設定にするとたぶん大丈夫。 このあたりは /etc/network.subr 内 network6_interface_setup 関数で呼ばれている様子なので詳しい挙動を見たい場合はこのあたりを参考に。

参考文献

2017年 まとめ

技術編

  • http client に詳しくなった
  • mockito をまともに使い始めた
  • spring framework をまともに使い始めた
  • spring boot をまともに使い始めた
  • gradle をまともに使い始めた
  • ansible をまともに使い始めた
  • Raspberry Pi を手に入れた

ゲーム編

漫画編

4 桁行かないぐらいだけど書ききれないので割愛

コーヒー編

  • コーヒーに凝り始めた
  • 機器
    • twinbird の サイフォンコーヒーメーカーを買った
    • マキネッタ(モカエキスプレス)を買った(壊れた)
    • デロンギエスプレッソマシンを買った
    • 有田焼セラミックフィルターを買った
    • HARIO のウォーターブリューコーヒーメーカーを買った
  • SCAJ 2017 に行った
  • コーヒー豆を買った(合計推定 10 kg )

その他

  • ネパールに行った
  • 国内の旅行に何回か行った
  • 壊れたエアコンで暑さに耐えきれずに引っ越しをした

wp-comments-post.php への投稿が 405 Method Not Allowed になる問題

確認環境

問題

wordpress の記事のコメント投稿が 405 Method Not Allowed になる

確認される現象

記事詳細ページのコメント欄へコメントできない

原因

条件1 : nginx の設定

nginx の location ディレクティブで .php を指定して fastcgi に引き渡している。

https://codex.wordpress.org/Nginx#General_WordPress_rules

upstream php {
        server unix:/tmp/php-cgi.socket;
        server 127.0.0.1:9000;
}
...
server {
        ...
        location ~ \.php$ {
                ...
                fastcgi_pass php;
                ...
        }

条件2: iThemes Security の「コメントスパム」設定が有効

iThemes Security で該当項目を有効にしていると 生成される nginx.conf で以下のような 設定が出力される。

        # コメントスパムを削減 - セキュリティ > 設定 > WordPress の微調整 > コメントスパム
        location = /wp-comments-post.php {
                limit_except POST { deny all; }
                if ($http_user_agent ~ "^$") { return 403; }
                valid_referers server_names jetpack.wordpress.com/jetpack-comment/;
                if ($invalid_referer) { return 403; }
}

上記より

nginx の location ディレクティブは最長一致の設定が用いられる[1]。 そのため条件1で設定した .php の location よりも 条件2の /wp-comments-post.php が優先されるはず。そして 条件2の設定では fastcgi_pass がないためそのまま静的ファイルとして処理される。 nginx は静的ファイルの場合は POST は許可されないため 405 になる[2]。

解決方法

このままだとコメントスパム対応部分が弱いとも考えられるので コメントスパム部分は別のプラグインに任せるか、上記設定を参考にして自分で fastcgi_pass をする設定を追加するなどすればよい気もする。

(余談) iThemes Security が出力する設定を変更することはできないため、対象 location ディレクティブに fastcgi_pass を設定できない。 そして自分は location ディレクティブに fastcgi_pass を記載することなく設定する方法がわからない、というのと wordpress を運用しようとしている人の nginx 力はそんなに高くないと思っているため 技巧を凝らした nginx 設定するのはあんまりよくない気もする。ので「コメントスパムを off にする」ぐらいしか思いつかない。

参考 URL

Spring Boot で Gzip を使ってレスポンスを返す

概要

nginx などの web server では静的ファイルなどを gzip で返すとパフォーマンスがよくなるよーという記事は良くみる。 これを Spring Boot で行うにはどうすればいいか。(アプリケーションから gzip で返す必要性が発生するのかというのは別の話)

設定

https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

server.compression.enabled=false # If response compression is enabled.
server.compression.excluded-user-agents= # List of user-agents to exclude from compression.
server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript # Comma-separated list of MIME types that should be compressed.
server.compression.min-response-size=2048 # Minimum response size that is required for compression to be performed.

server.compression.enabled を true にする。とりあえず有効にするのはここまで。

細かい確認

Spring Boot 1.5 と 2.0 ともに下記バージョンのよう。

  • jetty 9.4.7.v20170914
  • tomcat 8.5.23
  • undertow 1.4.21.Final

それぞれどう違うのかというのを確認しようとして関係の図を書いた。 Spring Boot 1.5 と 2.0 では少し実装が違ったけど 1.5 まとめて疲れたのでここまで。

要するにどれも 標準の java.util.zip.Deflater を使っている。 Deflater は中で(native で) zlib 呼んでるらしい。

f:id:nise_nabe:20171222004016p:plain

bsd 向けに ansible でユーザ作成

環境

  • DragonFlyBSD v5.0.0

ansible でユーザ作成をする方法

一般的な方法

BSD 的な方法

コマンドの useradd , groupadd 的なものがないと動かないので動かない。

代わりに pw を使う方法を検討。user, group ともに pw でよいらしい。普通に使うと二度目の実行時などすでに存在している場合にエラーになるので存在チェックのタスクを追加する。

  1. pw show によって存在してるかどうかを確認
  2. 存在する場合は 正常終了、しない場合は異常終了。
  3. そのままだと必ず changed になり結果のノイズになるので changed にならないように
  4. pw useradd または pw groupadd で追加

下記は prometheus のユーザを作成したときの例です。

使用モジュール

- name: check prometheus system group via pw
  command: pw show group  "{{ prometheus_group }}"
  register: prometheus_group_check
  changed_when: False

- name: check prometheus system user via pw
  command: pw show user  "{{ prometheus_user }}"
  register: prometheus_user_check
  changed_when: False

- name: create prometheus system group via pw
  command: pw groupadd -n "{{ prometheus_group }}"
  when: prometheus_group_check.rc != 0

- name: create prometheus system user via pw
  command: pw useradd -n "{{ prometheus_user }}" -g "{{ prometheus_group }}" -s /sbin/nlogin
  when: prometheus_user_check.rc != 0