hledger-webへの移行
会計ソフトのデータを壊したのを機に、プライベートホスト可能かつwebインタフェースがある複式帳簿ソフトウェアへ移行した。備忘録として行った事を記録していく。
Ubuntuサーバーを18.04へ
個人のさほど重要でないサーバーなので適当にバージョンを上げる。さくらのVPSでUbuntu 16.04をインストール後、/etc/update-manager/release-upgrades を編集してltsじゃなくともアップデート可能に
# パッケージ情報を反映させる
apt update && apt dist-upgrade
do-release-upgrade と再起動をくりかえした後, do-release-upgrade -dで開発途上のバージョンへ
ssh周りを設定
さくらのVPSはiptablesの初期設定があるのでiptables -Lで眺めて障害になりそうなものを消す。さくら提供のUbuntu 16.04では/etc/iptables/iptables.rulesでINPUTへのREJECTルールをコメントアウトして-Dオプションで現在設定も変更、慣れたufwで設定しなおす。
ufw default deny incoming
ufw default allow outgoing
# sshをやたらスキャンの多いポートから変える
# すぐやるので先に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;
# こだわりがあるなら環境に応じて以下などを設定する
後で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 ] で指定したセクション
# 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越しに帳簿を編集できるようになった。無骨な画面でとっつきにくいが、複式簿記の帳簿としてはすごく良い。