昨日、14時過ぎに階段で滑って骨折してしまいました。
自力で病院に行こうとしましたが、痛くて歩行が困難だったので #7119 で相談して救急車を読んでもらいました。
レントゲンとCTを撮ったあと、痛み止めを処方してもらいました。
特にギブス等で固定できる部分ではないので、痛み止めの飲み薬と張り薬を使い、サポーターを巻いて安静にしているしかないとの事でした。
完治には一ヶ月くらいかかるので、しばらくは不自由な生活が続きそうです。
「はてなダイアリー」が終了するので、インポート機能を使って、過去の記事を「はてなブログ」にインポートしました。
ところが、「はてなダイアリー」と「はてなブログ」でカテゴリーが統一されていなかったため、カテゴリーがカオスになってしまいました。
また、初期には「はてなダイアリー」を日記モードで書いていたため、タイトルが無い記事も多数存在していました。
これらを「はてなブログ」の Web 画面上から変更することは(僕には)苦痛だったので、 一括して変更するために、記事(entry)のタイトルとカテゴリーを読み書きするツールを Python で作成し、 テキストエディタで編集して変更しました。
まず、get-tc.py というスクリプトでタイトルとカテゴリーを読み出しました。
python get-tc.py --api-key=<APIキー> <ルートエントリーポイント> <出力ファイル名>
APIキーと、ルートエントリーポイントは、はてなブログの設定画面から取得できます。
ファイルの中身は yaml 形式で、記事(entry)の配列になっており、ひとつの記事は以下の用になっています。
- categories: - カテゴリ1 - カテゴリ2 entry_id: エントリID link: 記事のURL published: 最初に書いた日付 summary: 記事のサマリー title: 記事のタイトル
テキストエディタでこのファイルを書き換えました。 なお、タイトルとカテゴリ以外の項目は変更しても反映しないようにしました。
編集が終わったら、以下のコマンドで更新しました。
python update-tc.py --api-key=<APIキー> <ルートエントリーポイント> <入力ファイル名>
なお、エディタは vim をつかって次のような使い捨ての vimscript を作成し読み込んでから編集しました。
nnoremap q# o- C#<ESC> nnoremap qB o- bash<ESC> nnoremap qC o- C<ESC> nnoremap qD o- Docker<ESC> nnoremap qJ o- JavaScript<ESC> nnoremap qP o- Python<ESC> nnoremap qR o- Ruby<ESC> nnoremap qS o- SSL<ESC> nnoremap qd o- 読書・マンガ・アニメ・映画<ESC> nnoremap qi o- IT<ESC> nnoremap qk o- 購入<ESC> nnoremap ql o- 生活・健康・旅行<ESC> nnoremap qm o- MS Office・Googleドキュメント<ESC> nnoremap qn o- ニュース・時代<ESC> nnoremap qt o- 投資・経済<ESC> nnoremap q/ /^- categories<CR>
普段はデスクトップもノートPCもUbuntuマシンを使っているのですが、たまに Windows マシンが必要になります。
今までは5年ほど前に買った Dell のノートブックを騙しだまし使っていました、性能はそれ程問題ではなかたのですが、ハードウエア的に色々壊れてきたので、 あたらしく Windows PC を購入することにしました。
予算も限られている上、普段US配列のキーボードをつかっているので日本語キーボードは嫌だったので、中国メーカ製のノートPCを購入してみました。
一応、初期不良等が不安だったので、で評判が良さそうな物を検索して Amazon で購入しました。
上記のリンクの価格は 33,991円 ですがタイムセールで5000円引きだったので 3万円以下で買えました。
CPU は Celeron N4100 というショボい中ではマシな方という評価のものです、メモリは 4GB 、ストレージは メーカーのサイト では 64GB eMMC となっていましたが 128GB の SSD です。
色々インストールした後ですが、一応 CrystalDiskMark ストレージの速度を計ってみました、早くはないですがeMMCではなくSSD といえる程度の速度は出ているようです。
起動時に Windows のセットアップ画面から始まる真っ当なタイプです。余計なものも入っていないようです。
なお、キーボードに貼って日本語キーボード化するシールもついていましたが、今回はUS配列のまま使っています。
Office は Office 2019 を使ってみたかったののあって、 ウチダの学割|Microsoft Office学割|内田洋行 で購入しました (僕は放送大学の学生です)。18,144円でした。
今日は小ネタを
Twitter の自動更新 ブックマークレット (Bookmarklet) です。ツイッターの Web ページの 「新しいツイート○件を見る」 が表示されていたらクリックして、広告は非表示にします。
同様の機能をもった機能拡張もありますが、機能拡張用よりはブックマークレットのほうが安全性は高いし、起動していないときの負荷も少ないです。
ローカルネットで開発する時に使用するワイルドカード SSL 証明書の取得方法の記事を書いたので、いくつかの言語で簡単な https サーバープログラムを記述しようと思います。 最近の言語は標準ライブラリや定番のライブラリが充実しているので簡単に https サーバーを書くことができます。
なお、折角 https サーバーで配信するのですから、加速度センサーを使うサンプルコンテンツにしようと思います。
以下のように Android からアクセスするとスマホを回転させても頭が上でありつづけます。
残念ながら iOS デバイスでは動作しません。 PC では API は使えるようですが物理的に加速度センサーがほぼ付いていないので使えません。 Accelerometer | MDN
とりあえず簡単のために index.html に JavaScript も CSS も書いてしまいました。
( index.html
は public
という名前のフォルダーに入れました。 )
<!DOCTYPE html> <html lang="ja"> <head> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta charset="UTF-8"> <title>Stick figure</title> <style> #stick-figure { width: 50%; margin: 0 auto; transform: rotate(0rad); transform-origin: center; } #message { color: red; font-size: 2rem; } </style> </head> <body> <svg viewBox="0 0 200 200" id="stick-figure"> <g stroke="green" fill="none" stroke-width="5"> <circle cx="100" cy="30" r="20" /> <line x1="100" y1="50" x2="100" y2="110" /> <polyline points="80,190 100,110 120,190" /> <polyline points="40,75 100,65 160,75" /> </g> </svg> <p id="message"></p> <script> const main = () => { const stickFigure = document.getElementById('stick-figure'); const message = document.getElementById('message'); if (!('Accelerometer' in window)) { message.innerHTML = 'no Accelerometer'; return; } navigator.permissions.query({ name: 'accelerometer' }).then(result => { if (result.state !== 'granted') { message.innerHTML = result.state; return; } const acc = new Accelerometer({ frequency: 60 }); acc.addEventListener('reading', e => { const { x, y } = acc; const rad = -Math.atan2(y, x) + Math.PI / 2.0; stickFigure.style.transform = `rotate(${rad}rad)`; }); acc.start(); }); }; main(); </script> </body> </html>
標準のモジュールだけで完結したかったので WEBrick を使いました。 WEBrick モジュールだけで完結するので、リファレンス等が分かりやすかったです。 ( この辺は大クラス主義のおかげかもしれません。 ) 証明書と中間認証局は別ファイルにしないといけないようです。
#!/usr/bin/env ruby require 'webrick' require 'webrick/https' port = (ENV['PORT'] || 8443).to_i puts "port=#{port}" httpd = WEBrick::HTTPServer.new({ DocumentRoot: './public', BindAddress: '0.0.0.0', Port: port, Logger: WEBrick::Log.new(nil, level=WEBrick::BasicLog::WARN), SSLEnable: true, SSLCertificate: OpenSSL::X509::Certificate.new(File.open('./certs/cert.pem').read), SSLExtraChainCert: [OpenSSL::X509::Certificate.new(File.open('./certs/chain.pem').read)], SSLPrivateKey: OpenSSL::PKey::RSA.new(File.open('./certs/privkey.pem').read) }) Signal.trap('INT') { httpd.shutdown } httpd.start()
ssl.wrap_socket
というのは Python 3.2 以上では非推奨で Python 3.7 からは禁止だそうです。
まずはじめに ssl context というのを作らなくてはいけないのですが、ドキュメントではクライアント側とサーバー側両方の解説があるので初心者にはわかりにくかったです。
しかもサーバー側を作る時に ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
とするのはチョッとした罠です。
あと、SimpleHTTPRequestHandler
がカレントディレクトリからコンテンツを配信すること前提のようなので chdir するという汚いサンプルになってしまいました。
#!/usr/bin/env python3 from http import server import ssl import os if __name__ == '__main__': address = ('0.0.0.0', 8443) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain('certs/fullchain.pem', 'certs/privkey.pem') os.chdir('public') httpd = server.HTTPServer(address, server.SimpleHTTPRequestHandler) httpd.socket = context.wrap_socket(httpd.socket) try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close()
手抜きして express を使ってしましました。そのおかげで少ない行数で済んでいます。
#!/usr/bin/env node const fs = require('fs') const express = require('express') const https = require('https') const app = express() const port = Number(process.env.PORT || 8443) const options = { cert: fs.readFileSync('./certs/fullchain.pem'), key: fs.readFileSync('./certs/privkey.pem') } app.use(express.static('public')) server = https .createServer(options, app) .listen(port, () => console.log(`start port=${port}`))
プログラム言語ではありませんが、 Docker (alpine + lighttpd) でもやってみました。 lighttpd では鍵ファイルと証明書ファイルを連結する必要があるので起動時にやっています。
Dockerfile
FROM alpine:3.8 RUN apk --update add lighttpd && rm -rf /var/cache/apk/* COPY ./public /var/www/localhost/htdocs RUN cd /etc/lighttpd &&\ sed -e '/^server.modules = (/a"mod_openssl",' \ -e '/^# server\.port/aserver.port = 443' \ -e '/^# ssl.engine/assl.engine = "enable"' \ -e '/^# ssl.pemfile/assl.pemfile = "/etc/ssl/certs/server.pem"' \ -e '/^# ssl.pemfile/assl.ca-file = "/etc/ssl/certs/chain.pem"'\ --in-place \ lighttpd.conf &&\ echo -e '#/bin/sh\n'\ 'cat /certs/privkey.pem /certs/cert.pem > /etc/ssl/certs/server.pem\n'\ 'cat /certs/chain.pem >/etc/ssl/certs/chain.pem\n'\ 'chmod 600 /etc/ssl/certs/*.pem\n'\ 'lighttpd -f /etc/lighttpd/lighttpd.conf\n'\ 'sleep 1\n'\ 'tail -f /var/log/lighttpd/error.log -f /var/log/lighttpd/access.log\n' > /start.sh &&\ chmod +x /start.sh EXPOSE 443 CMD "/start.sh"
起動
$ docker build . -t <タグ名> $ docker run --rm -it -p 443:443 -v "$(pwd)/certs:/certs:ro" --name <コンテナ名> <タグ名>
なお、以上のスクリプトは HiroshiOkada/https-example: https 静的サーバーサンプル に置きました。
PPA を追加して certbot をインストールしました。
$ sudo apt-get install software-properties-common $ sudo add-apt-repository ppa:certbot/certbot $ sudo apt update $ sudo apt install certbot
証明書を要求するために次のようなコマンドを入力しました。
sudo certbot certonly --manual --preferred-challenges=dns-01 --server=https://acme-v02.api.letsencrypt.org/directory --agree-tos -m okadahiroshi@mibox.jp -d '*.local.toycode.com'
すると以下のように表示されます。途中で Are you OK with your IP being logged? 「あなたのIPアドレスを記録しますがよろしいですか?」と聞かれるので y
と答えました。
Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator manual, Installer None Obtaining a new certificate Performing the following challenges: dns-01 challenge for local.toycode.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOTE: The IP of this machine will be publicly logged as having requested this certificate. If you're running certbot in manual mode on a machine that is not your server, please ensure you're okay with that. Are you OK with your IP being logged? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please deploy a DNS TXT record under the name _acme-challenge.local.toycode.com with the following value: 1QjY1MdTuF1gjGmJexopl7N9DosUTaSyGz7gDCGlck0 Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue
ここで、DNS の TXT フィールドに貼り付ける認証用の文字列 が表示されました。
ここでもう一つ別なターミナルを開いて zone ファイル /etc/nsd/local.toycode.com.zone
に TXT フィールドを加えました。
もちろん serial も増やしました。
$TTL 1m local.toycode.com. IN SOA ns-local.toycode.com. postmaster.toycode.com. ( 2 ; serial 5m ; refresh 2m ; retry 6h ; expire 1m ; minimum ) @ IN NS ns-local.toycode.com. ns-local IN A 35.199.184.64 _acme-challenge.local.toycode.com. IN TXT "1QjY1MdTuF1gjGmJexopl7N9DosUTaSyGz7gDCGlck0" a192-168-1-1 IN A 192.168.1.1 a192-168-1-2 IN A 192.168.1.2 以下略
/etc/nsd/local.toycode.com.zone
を編集し終わったら、$ sudo nsd-control reload
で zone ファイルを読み込ませました。
そして、$ dig txt _acme-challenge.local.toycode.com +noedns +short
で "1QjY1MdTuF1gjGmJexopl7N9DosUTaSyGz7gDCGlck0"
が返ってくることを確認しました。
zone ファイルの更新が終わったので、もとのターミナルに戻って、enter キーを押しました。すると
Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/local.toycode.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/local.toycode.com/privkey.pem Your cert will expire on 2019-04-15. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
と表示され、/etc/letsencrypt/live/local.toycode.com/fullchain.pem
にドメインの証明書と中間認証局の証明書の連結されたものが、
/etc/letsencrypt/live/local.toycode.com/privkey.pem
に秘密鍵ファイルが保存されました。(実際にはこれらはシンボリックリンクで実体は別な場所に保管されています。)
なお上には表示されていませんが。/etc/letsencrypt/live/local.toycode.com/
ディレクトリには
ファイル名 | 内容 |
---|---|
cert.pem | ドメインの証明書 |
chain.pem | 中間認証局の証明書 |
fullchain.pem | ドメインの証明書と中間認証局の証明書の連結されたもの |
privkey.pem | 秘密鍵 |
の4個のファイルが保存されていました。
以上でワイルドカード証明書の取得ができました。
今回はマシンのリソースも少ないので DNSコンテンツサーバ(権威DNSサーバ) として軽量だと言われている NSD https://unbound.jp/nsd4/ https://www.nlnetlabs.nl/projects/nsd/ を使ってみました。
インストール自体は apt で簡単にインストールできます。
$ sudo apt update $ sudo apt upgrade $ sudo apt install nsd
今回 DNS をセットアップ中に自分自身の名前解決等ができないとエラー等がこったり反応が悪くなるので /etc/hosts
に以下のエントリーを追記しました。
35.199.184.64 ns-local.toycode.com 127.0.1.1 ns-local
/etc/nsd/nsd.conf
を次のようにしました。
server: do-ip4: yes do-ip6: no port: 53 username: nsd zonesdir: "/etc/nsd" pidfile: "/run/nsd/nsd.pid" logfile: "/var/log/nsd.log" zone: name: "local.toycode.com" zonefile: "local.toycode.com.zone"
/etc/nsd/local.toycode.com.zone
を作成し、次のようにしました。
$TTL 1m local.toycode.com. IN SOA ns-local.toycode.com. postmaster.toycode.com. ( 1 ; serial 5m ; refresh 2m ; retry 6h ; expire 1m ; minimum ) @ IN NS ns-local.toycode.com. ns-local IN A 35.199.184.64 a127-0-0-1 IN A 127.0.0.1 a192-168-1-1 IN A 192.168.1.1 a192-168-1-2 IN A 192.168.1.2 a192-168-1-3 IN A 192.168.1.3 a192-168-1-4 IN A 192.168.1.4 a192-168-1-5 IN A 192.168.1.5 a192-168-1-6 IN A 192.168.1.6 a192-168-1-7 IN A 192.168.1.7 a192-168-1-8 IN A 192.168.1.8 a192-168-1-9 IN A 192.168.1.9 a192-168-1-10 IN A 192.168.1.10 a192-168-1-11 IN A 192.168.1.11 a192-168-1-12 IN A 192.168.1.12 a192-168-1-13 IN A 192.168.1.13 以下略
TTL は後で修正が早く反映されるように極端に短い値にしています。ある程度たったら大きな値 (1dとか) に書き換える予定です。シリアルは後でスクリプト等で修正するかもしれないので、一般的な日付をベースにしたものにしていません。
使いそうなアドレスは全て登録しました、僕がよく利用するネットワークは 192.168.1.0/24 192.168.2.0/24 192.168.100.0/24 192.168.101.0/24 なので すべて登録しました。
NSD は BIND とちがって $GENERATE
が無いので一々記述する必要があります。スクリプト言語等で生成しても良いでしょう。ぼくは vim を使っているので
良く使うアドレスは個別にわかりやすい名前を割り当てても良いとおもいます。
:for net in [1,2,100,101] | for host in range(1,254) | put='a192-168-' . net . '-' . host . ' IN A 192.168.' . net . '.' . host | endfor | endfor
で生成しました。
また port 53 がバッティングして NSD が起動できなかったので、systemd-resolved.service を止めました。そして resolve.conf
を手動で書き換えて 8.8.8.8 を参照するようにしました。
$ sudo systemctl disable systemd-resolved.service $ sudo service systemd-resolved stop $ sudo rm /etc/resolv.conf $ echo nameserver 8.8.8.8 | sudo tee /etc/resolv.conf
この辺はちょっとハマりました、以上の設定で動いていますが正当なやり方かどうかはわかりません。
参考: dns - How to disable systemd-resolved in Ubuntu? - Ask Ubuntu
nsd の起動は $ sudo nsd-control start
zone ファイルの再読込は(シリアルを増やして) $ sudo nsd-control reload
です。
zone ファイルの編集が終わって読み込んだら以下のようなコマンドで手元のコンピュータで 名前が引けるか確認しました。
$ dig A a192-168-1-1.local.toycode.com +short
$ nslookup -type=A a192-168-1-1.local.toycode.com
$ getent hosts a192-168-1-3.local.toycode.com