さくらの 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

DragonflyBSD 5.0 + letsencrypt インストールログ

以前書いた記事 の ライブラリが消えていたので書き直し

環境

DragonflyBSD 5.0

ログ

とりあえず standalone で取る場合。

$ sudo pkg install py27-certbot
$ sudo certbot certonly --standalone -d ドメイン名

すると以下のような場所にいろいろできる

$ sudo ls /usr/local/etc/letsencrypt/live/ドメイン名/
README      cert.pem    chain.pem   fullchain.pem   privkey.pem

更新については自動でやってくれないようなので自分で cron に設定するなりして頑張る

ConditionalOnClass を使うライブラリを書いたときにハマったことメモ

概要

Spring Boot の機能として auto configuration を作る Spring Boot ライブラリを作成する場合に、特定のライブラリが読まれているときのみ動く設定などを使いたい場合がある。そういう場合に ConditionalOnClass アノテーションを使うだろうと思う。(そもそも AutoConfiguration を作りたいと思うモチベーションについては割愛)

AutoConfiguration やその作り方については下記記事を参照

以下、自分が ConditionalOnClass アノテーションを利用したときにハマったこと。

実際にハマったこと

ConditonalOnClass はコードを見ると TYPE と METHOD につけることが可能。

https://github.com/spring-projects/spring-boot/blob/v1.5.6.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java#L32

基本的には ConditionalOnClass アノテーションは Confuguration アノテーションが書かれているクラスやその中で利用する想定とする。そして実際に ConditionalOnClass がついている場合全体を通した場合下記のように挙動が変わる。

  • Configuration Class についていてクラスパスに指定クラスが存在しない場合、そのクラスを Bean として生成しない。
  • メソッドについていてクラスパスに指定クラスが存在しない場合、そのメソッドを実行しない。

差が分からないように見えるが、前者の場合は "生成" されるためそのクラス内で利用している import 対象のクラスがクラスパスに存在しないと生成に失敗する。

これは通常開発時はビルド時にエラーとして失敗するものだが、今回の場合はクラスパスに存在するかしないかで制御するライブラリ側のコードなので compileOnly とするため、このライブラリ利用側のアプリではクラスパスに存在しない場合がある。

利用側アプリではそのライブラリを追加して及び使用したクラスをクラスパスに追加しないときにランタイムで Configuration クラスの生成に失敗するのでアプリのビルドは成功するが起動することができない。

例えば下記のようにそのクラスが存在しなければその Bean 生成はしないというような意図で書いたコードである。(AutoConfiguration 用の spring.factories などの説明は割愛)

@Configuraion
public class MyConfiguration {
   @Bean
   @ConditionalOnClass(MyClassService.class)
   public MyClassService myClassService() {
      return new MyClassService();
   }
}

この場合、 MyConfiguration クラスは普通にインスタンス化しようとするためこのライブラリの利用者は実行時にエラーになる。

解決案

ある指定クラスが存在する場合のみ Bean としたい場合はクラス全体につけるのが良い。当然そのクラスにあるメソッドは指定クラスがないと使われないのでメソッド側に ConditionalOnClass アノテーションを付ける必要はない。

@Configuraion
@ConditionalOnClass(MyClassService.class)
public class MyConfiguration {
   @Bean
   public MyClassService myClassService() {
      return new MyClassService();
   }
}

実際のコードの例としては DataSource あたりが参考になるのではないかと思う。このコードでは各ライブラリ依存部分を中で更に別クラスを書いて ConditionalOnClass を使っている。

https://github.com/spring-projects/spring-boot/blob/35d062f50df674a9564834d14df603db536cc5f5/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration.java