Route53+DNS-01のLet'sEncryptを自動更新する
ググると日本語の記事も結構出てくるんですが、どれも私の環境ではうまく動かなかったので自分なりにやりました。
前提
certbot-external-authは下記でインストール
https://github.com/EnigmaBridge/certbot-external-auth
上のURLを参考に
pip install certbot pip install certbot-external-auth
でインストールできる。
コード
renew.sh
#!/bin/sh certbot certonly \ -d sub1.example.com \ -d sub2.example.com \ --email test@example.com \ --agree-tos \ --preferred-challenges dns \ --keep-until-expiring \ --text \ --configurator certbot-external-auth:out \ --certbot-external-auth:out-public-ip-logging-ok \ --certbot-external-auth:out-handler /path/to/hook.sh # apacheなら systemctl restart httpd # nginxなら # systemctl restart nginx
hook.sh
#!/bin/sh set -e cmd="$1" shift case "$cmd" in perform) HOSTED_ZONE_ID="/hostedzone/YOUR_HOSTED_ZONE_ID" FILENAME=`date "+%Y%m%d%H%M%S"`.json DIR=/path/to/json_dir/ # 環境変数チェック if [ -z "$domain" ] || [ -z "$validation" ]; then echo "Undefined environment variable" exit 1 fi # 設定用jsonファイルを書き出し cat <<EOT > $DIR$FILENAME { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "_acme-challenge.$domain", "Type": "TXT", "TTL": 60, "ResourceRecords": [ { "Value": "\"$validation\"" } ] } } ] } EOT # jsonファイルをアップロードしてTXTレコードを追加 aws route53 change-resource-record-sets --hosted-zone-id "$HOSTED_ZONE_ID" --change-batch file://$DIR$FILENAME # DNS反映待ち sleep 60 ;; *) ;; esac
使い方
renew.shをcronに登録して毎月1回実行すれば更新されるはず。
説明
certbot-external-authってやつがDNS-01のチャレンジを行うときに色々なタイミングでフックしてくれます。
そのフックを利用してチャレンジ前にTXTレコードを書き換えて認証してもらうって流れです。
どのタイミングでフックされるかや、どういう環境変数を渡してくれるかは下記を参考にしてください。
github.com
hook.shの方はどのフックタイミングかを見極めてperformのときにTXTレコードを書き換えます。
hosted_zone_idはRoute53にアクセスしてHosted zonesを見ればわかります。
awsコマンドでRoute53の変更を行うにはjsonを使うので、設定用jsonを書き出します。
書き出したjsonをawsコマンドでアップロードします。
チェレンジ前にDNSの設定が反映されてる必要があるのでTTLの60秒待ちます。
その後はcertbotが勝手にやってくれます。
最後にWebサーバーを再起動すれば新しい証明書になります。
注意点
本番でやる想定なので「--keep-until-expiring」というオプションをつけてます。
これは証明書の更新が必要ない場合は発行しないというオプションです。
証明書の有効期限にかかわらず発行させる場合は「--force-renewal」というオプションをつけます。
このオプションをつけて実行する場合Let's Encryptのレート制限に引っかからないように注意しましょう。
Rate Limits - Let's Encrypt - Free SSL/TLS Certificates
法律の刑罰を比較出来るサービスを作った
きっかけはなんかの過労死ニュースで見た、企業への罰金が50万だったという記事。
もちろん損害賠償があるんだけど法律的には罰金50万で済むということに衝撃を受けた。
それと同時期に漫画村とかで著作権違反のことが話題になってたときに調べたら、こちらは10年以下の懲役または1000万円以下の罰金だそうな。
つまり間違って人が死んじゃうより違法アップロードとかしたほうがめちゃくちゃ罪が重いということ。
どういう経緯があってこういう法律になったのかはわからないけど、直感的にはおかしくないか?これを比較出来るサービスを作ったら面白くないか?
ということで作りました。
ヘッドレスChrome+Selenium+Pythonでファイルダウンロード
業務に必要なレポートを毎日ダウンロードして加工して別レポート作成する、
みたいな作業を自動化して欲しいとのことでSeleniumでサクッと作ろうと思ったんですが、ヘッドレスChromeだとデフォルトではファイルダウンロードができなくて半日費やしました。
その時の解決方法のメモ。
環境
CentOS7.2
Python2.7.5 (小学生に笑われるやつ)
Selenium
Google Chrome 66.0.3359.117
現象
vaaaaaanquish.hatenablog.com
上記の記事を参考にさせてもらって普通にページの取得とかはできたんですが、ダウンロードボタンを押しても何も起こりませんでした。
正確に言うと、処理の時間としてはダウンロードしてるのとほぼ同じ時間かかっているものの実際のファイルはどこにも無い、かつエラーも出てないという現象でした。
CentOSで使ってたソースをMacに持ってきてヘッドレスじゃないChrome+Seleniumだと普通にダウンロード出来たのでヘッドレスChrome特有の問題かなと当たりをつけました
結論 & 解決
調べてみるとヘッドレスChromeではセキュリティのためデフォルトでファイルのダウンロードが出来ないようになってるみたいでした
stackoverflow.com
上記のstackoverflowに載ってる解決方法とほぼ同じなんですが以下の様にすることでファイルをダウンロード出来ました。
以下の例はヘッドレスChromeでChromeをダウンロードしてます。
# -*- coding: utf-8 -*- from selenium import webdriver from time import sleep chromeOptions = webdriver.ChromeOptions() chromeOptions.add_argument('--headless') chromeOptions.add_argument('--window-size=1280,1024') driver = webdriver.Chrome(chrome_options=chromeOptions) # ヘッドレスChromeでファイルダウンロードするにはここが必要だった driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command') driver.execute("send_command", { 'cmd': 'Page.setDownloadBehavior', 'params': { 'behavior': 'allow', 'downloadPath': './' # ダウンロード先 } }) # ヘッドレスChromeでChromeをダウンロードしてみる driver.get('https://www.google.co.jp/chrome/index.html') sleep(3) # Chromeをダウンロードボタンをクリック driver.find_element_by_css_selector('#marquee > a').click() sleep(1) # 同意してインストールボタンをクリック driver.find_element_by_css_selector('#eula-accept').click() sleep(15) driver.close()
ヘッドレスChromeでファイルダウンロードできた!
ちなみにChrome62から追加されたっぽい?機能なのでそれ未満はダメかもです
AMP対応するまでに失敗したこと
自社サービスをAMP対応したので、その最中に失敗した事のメモです。
AMPとは
失敗したこと
- レスポンシブで縦幅固定の枠に画像を表示したいなら amp-img は使わない
- サードパーディで専用のコンポーネントがある場合がある
- #development=1 は完璧ではない
- AMPページへのリンクはPCページに置かないといけない
レスポンシブで縦幅固定の枠に画像を表示したいなら amp-img は使わない
AMPページで画像を表示したい場合amp-imgという専用のタグを使います。
画像をレスポンシブで表示したい場合は「layout="responsive"」を指定します。
このlayoutを設定しちゃうとwidthとかheightとかガン無視して表示されちゃいます。
この状態でCSSをいじってもどうにもなりませんでした。
解決策はamp-imgを使わずに CSSでbackgroun-imageを使うことです。
HTML
<div class="responsive-imge"></div>
.responsive-imge { width: 100%; height: 200px; position: relative; box-sizing: border-box; background-size: cover; background-repeat: no-repeat; background-position-x: 50%; background-position-y: 50%; background-image:url(https://ampbyexample.com/img/amp.jpg); }
こんな感じです。よくある手法ですね。
ただAMP対応しよとすると、画像はamp-imgを使わなきゃ駄目って記述が散見されるので、てっきりCSSで指定は出来ないもんだと思いこんでました。
サードパーディで専用のコンポーネントがある場合がある
これはリファレンスちゃんと読めって結論に至るんですが・・・。
下記のページにはAMP専用のタグとコンポーネントが羅列されてます
Accelerated Mobile Pages Project
YoutubeやInstagram見たいな大きい所以外にも色々使えるコンポーネントがあります。
規約で保存が禁止されてるサードパーティAPIが多いので、javascriptを使えないAMPではこういうコンポーネントを使わないと表示できません。
これを知るまでは頑張ってサーバーでAPI取得してcron回して作ってました。
#development=1 は完璧ではない
チュートリアルでAMPのページを確認するときはChromeでURLに「#development=1」を付けてDeveloperToolsを使って確認しろと書いてあります。
ここで出たエラーを修正すればOKだよ見たいな書き方してますが、このモードは完璧ではないです。(今後解消されるかも)
このモードで修正してOKが出ても、実際に配信するとエラーが出ることがあります。
ちゃんとしたバリデーションは下記の2つのツールを使って検証する必要があります。
https://validator.ampproject.org/
構造化データ テストツール
前者はAMP記法として正しいかをチェックしてくれます。
後者は構造化データが正しいかをチェックしてくれます。
<script type="application/ld+json"> ~~~ </script>
こんな感じで構造化データをマークアップしてるやつです。
この2つのツールでOKをもらわないとエラーと認識されて掲載されません。
AMPページへのリンクはPCページに置かないといけない
<link rel="amphtml" href="http://amphtml/index.html">
こんなやつです。
これに一番ハマりました。
書いてある通りなんですが、AMPページへのリンクはPCで見るページに設置しないとGoogleには認識してもらえません。
レスポンシブサイトとかですと問題ないですが、PCとスマホとかでテンプレートを切り分けてる場合は注意が必要です。
僕が確認した限りではリファレンスにはPCページに設置してね見たいな記述は無いです。
モバイルで見たときに早く表示するためのものなのに何故!と思いましたね。
これからAMP対応しようと思う方の参考になれば。
PHPでベースラインJPEGをプログレッシブJPEGに変換する
上記の記事を見るまでそもそもベースラインjpegとプログレッシブjpegの2つがあること自体知らなかった・・・。
とにかくプログレッシブjpegのほうが有利なようなのでPHPでベースラインjpegをプログレッシブjpegに変換してみます。
ほぼここに書いてある通りなんですが
// 画像のインスタンスを作成します $image = imagecreatefromjpeg('path/to/test.jpg'); // インターレースを有効にします imageinterlace($image, true); // 画像を保存します imagejpeg($image, 'path/to/progressive_test.jpg'); imagedestroy($image);
PAKUTASOさんのこの画像で試してみます。
元々の画像(ベースラインjpeg)
https://tty-i.com/assets/img/ISHIIMG_7059.jpg
変換後の画像(プログレッシブjpeg)
https://tty-i.com/assets/img/progressive_ISHIIMG_7059.jpg
元々の画像は上から徐々に読み込まれてるのに対し、変換後の画像はすぐに全体が読み込まれ徐々にキレイになっていきます。