旅とプログラミングを少々

趣味に関する記録などをします。さしあたっては2017年JGC修行とプログラミング入門に関しての内容を連ねていきます。

hledger-webへの移行

会計ソフトのデータを壊したのを機に、プライベートホスト可能かつwebインタフェースがある複式帳簿ソフトウェアへ移行した。備忘録として行った事を記録していく。

Ubuntuサーバーを18.04へ

個人のさほど重要でないサーバーなので適当にバージョンを上げる。さくらのVPSUbuntu 16.04をインストール後、/etc/update-manager/release-upgrades を編集してltsじゃなくともアップデート可能に

# パッケージ情報を反映させる

apt update && apt dist-upgrade

do-release-upgrade と再起動をくりかえした後, do-release-upgrade -dで開発途上のバージョンへ

ssh周りを設定

さくらのVPSiptablesの初期設定があるのでiptables -Lで眺めて障害になりそうなものを消す。さくら提供のUbuntu 16.04では/etc/iptables/iptables.rulesでINPUTへのREJECTルールをコメントアウトして-Dオプションで現在設定も変更、慣れたufwで設定しなおす。

ufw default deny incoming

ufw default allow outgoing

# sshをやたらスキャンの多いポートから変える

ufw allow *****/tcp

# すぐやるので先にweb鯖用も許可

ufw allow 'Nginx Full'

ufw enable

systemctl start ufw

ここからはコンソールではなくssh越しに作業をし、id_rsa.pubを~/.ssh/authorized_keysに加えて鍵でのログインが上手くいった事を確認し /etc/sshd_configでパスワードログイン、ルートログインを不可にする。

 自動アップデート関連

sudo apt-get install unattended-upgrades

sudo dpkg-reconfigure -plow unattended-upgrades

# 一応確認

vi /etc/apt/apt.conf.d/50unattended-upgrades

vi /etc/apt/apt.conf.d/20auto-upgrades

 必要に応じて

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "1";

 とか通知やautoremoveも適当に設定。とはいえ開発版の間は自動化しない方が良かったか。

https

let's encryptを利用する。certbotのプラグインがころころ変わっていてまだ開発途上なので普通にwebrootで使う。正式版が出ても変にプラグインスクリプトで設定を書き変えられるより、こちらの方が楽ではないだろうか。

sudo apt-get install nginx letsencrypt

mkdir /var/www/letsencrypt

vi /etc/nginx/sites-enabled/設定ファイル

# 適当に使うドメインのserverに追加

location ~ .well-known/acme-challenge/ {
     root /var/www/letsencrypt;
     default_type text/plain;
}

 その後実行

 sudo certbot certonly --webroot --staging --webroot-path /var/www/letsencrypt -d example.com

 これで(staging版の)証明書をもらったのでnginxの設定を追加してまたサービス再起動

listen 443 ssl default_server;
listen [::]:443 ssl default_server;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

# OCSP stapling しなければ不要だった
# ssl_trusted_certificate /etc/letsencrypt/live/exmaple.com/chain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# 以下好みに応じて。

# こだわりがないならletsencryptの作ったものを使うだけ。

# include /etc/letsencrypt/options-ssl-nginx.conf;

# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

# こだわりがあるなら環境に応じて以下などを設定する

# ssl_session_timeout
# ssl_session_cache

# ssl_protocols
# ssl_ciphers
# ssl_prefer_server_ciphers

後でLet's encryptで配布されているFakeCAを認証局として認めるブラウザで接続確認する。

この時点でも--stagingを外して--break-my-certs付けて本番用証明書と置きかえ、さらに--keep-until-expiring付きでコマンドを適当にcron実行させて自動更新としても良いが、一応先の設定をミスするとLet's Encryptの更新を阻害してしまう可能性もあるので念の為後回しにした方が良い。

http client certificate

帳簿は広く公開したいものでもないので鍵認証を行う。

/etc/ssl/openssl.cnf を/usr/local/ssl/example.com/等適当なディレクトリにコピーしてきて編集

[ CA_default ] # デフォルトまたは[ ca ] で指定したセクション

dir = どこか適当なディレクトリ/CA用ディレクト

 

# SAN証明書にするならreqやcaのx509_extensionsで読まれるセクションに追加。デフォルトだと多分usr_certとv3_req

[ usr_cert ]

subjectAltName=@alt_names

[ v3_req]

subjectAltName=@alt_names

[ alt_names ]

DNS.1 = example.com

DNS.2 = *.example.com

 

# 以下は適当に

 

countryName_default = JP

# 他のdistinguished_nameも値を入れておいた方が楽

 

# CA policy は緩めに

stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional

 

# CAやreqで使うハッシュ方式

default_md  = sha256 # opensslのビルドによってもっと好みのに変える

default_bits = 2048 # mdによって適当な値が違うのでこちらも変え忘れない

まずはreqを作る。さきほどの設定をさらにコピーしてきて

 basicConstraints=CA:FALSE
 nsCertType = server, email, object

 に変更(clientreqconfig.cfgとする)し、

 sudo openssl genrsa -rand /dev/urandom -aes256 -out ./ClientSecret.key 2048

# /dev/urandom で良しとしているが、環境によっては/dev/randomでも十分使えるかもしれない。使えるなら使ってみたい。

# すぐ使うパスフレーズを入力したりする

openssl rsa -text -noout -in ./ClientSecret.key

sudo openssl req -new -config ./clientreqconfig.cnf -sha256 -key ./ClientSecret.key -out ./CSRrequest.csr

# さきほどのパスフレーズを入力したりする

openssl req -text -noout -in ./CSRrequest.csr

 opensslのビルドによって使える暗号化方式が違うのでその辺りは適宜読み変える。

csrを自分で認証する。CA用にもう一度openssl.cnfをコピーして

basicConstrants=CA:TRUE

nsCertType = client, email

と書きかえ(caconfig.cfgとする)、

 CADAYS="-days 3650" DAYS="-days 3650" SSLEAY_CONFIG="-config ./caconfig.cnf" CATOP=適当なディレクトリ/CA用ディレクトリ sudo -E /usr/lib/ssl/misc/CA.sh -newca

 で作成、

openssl req -text -noout -in ./careq.pem
openssl x509 -text -noout -in ./cacert.pem

# 特にここでCA:TRUEでないと困るのでよく確認
openssl rsa -text -noout -in ./private/cakey.pem

 その後署名してclient証明書を作り、配布用にまとめてpkcs12フォーマットのものも作る。

 sudo openssl ca -config clientreqconfig.cnf -md sha256 -cert CAのディレクトリ/cacert.pem -keyfile CAのデイレクトリ/private/cakey.pem -out Clientのディレクトリ/ClientCert.crt -infiles Clientのデイレクトリ/CSRrequest.csr

 

sudo openssl pkcs12 -export -in Clientのディレクトリ/ClientCert.crt -inkey Clientのディレクトリ/ClientSecret.key -certfile CAのディレクトリ/cacert.pem -out ./ClientCertFile.pfx

 これを自分の使いたいブラウザに個人証明書として配布する。(複雑な設定を避けLet's Encryptを使用しない場合は同様にしてnsCertTypeがserverのリクエストを作り、CAで署名する。)

 nginxに以下のような設定を追加する。 ssl_verify_clientをoptionalにし、ssl_client_verify変数を特定のlocationでのみチェックする事で.well-known/acme-challenge/ 以下によるLet's Encryptの更新を邪魔しないようにする。

ssl_verify_client optional;
ssl_client_certificate 先程のCAのディレクトリ/cacert.pem;

location / {
     if ($ssl_client_verify != SUCCESS) {
         return 403;
     }

    # ここに元からあったlocation /の設定

}

sudo nginx -t # 設定を確認

sudo systemctl restart nginx

sudo certbot certonly --webroot --staging --webroot-path /var/www/letsencrypt -d example.com # .well-known/acme-challenge を止めていない事の確認

 証明書を入れたブラウザ、入れていないブラウザでアクセスし、動作確認する。

hledger-webへのプロキシ

hledger-web自体がwebサーバーの機能を持つので、単純に

proxy_pass http://localhost:5000/;

をnginxの設定で指定すれば良い。

proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

 ログを眺める時のためにこの辺りも一応設定しておく。hledger-web --base-url https://example.com/を起動した状態でアクセスすれば確認できる。

hledger-webのサービス化

hledger-webをUnitとしてsystemdに登録し、サーバー起動時に自動的に起こすようにする。

 sudo vi /etc/systemd/system/hledger-web.service

[Unit]
Description=hledger web server

[Service]
ExecStart = /usr/bin/hledger-web -f /ジャーナルファイルへのパス --base-url=https://example.com --serve
Restart = always
Type = simple
User = ubuntu # シェル等のないユーザを作っておきかえた方が本当は良いが、ジャーナルファイルの権限等がちょっと面倒になる。
Group = ubuntu
WorkingDirectory = /var/lock/hledger-web # 現在はロックファイルくらいしか使わない? 上記ユーザが権限を持つところならどこでも良い。

[Install]
WantedBy = multi-user.target

 これでOK。

sudo systemctl daemon-reload

sudo systemctl start hledger-web

sudo systemctl enable hledger-web

 これでssl認証でweb越しに帳簿を編集できるようになった。無骨な画面でとっつきにくいが、複式簿記の帳簿としてはすごく良い。