tohokuaikiのチラシの裏

技術的ネタとか。

Let's Encryptがまたまたこけてた。

ブログの記事にするのは3回目。

2020-01-14 certbotがまたこけてた - tohokuaikiのチラシの裏
2019-12-09 Debian10でCertbotがこける - tohokuaikiのチラシの裏

なんか、こういうのがあってあんまりクリティカルかつあまりメンテナンスをしないサーバーではLet's Encryptを入れてないんだけど。

エラー内容

こんな感じ

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxx.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for xxxxx.org
Cleaning up challenges
Attempting to renew cert (xxxx.org) from /etc/letsencrypt/renewal/xxxx.org.conf produced an unexpected error: Missing command line flag or config entry for this setting:
Input the webroot for xxxx.org:. Skipping.

なんか、webrootが無いって言われる。なんで今更…

ということで、対応

/etc/letsencrypt/renewal/xxxx.org.conf に

[[webroot_map]]
xxxx.org = /var/www/xxxx.org/htdocs

というのを入れてDocumentRootを指定すると上手くいった。

Google AnalyticsのデータをAPI経由で取り出すとか

Google AnalyticsのデータをAPI経由で取り出すとかできるらしい。しかも随分と昔から…Version4ってどんだけ昔からだったんだという…

これに従ってやっていきます。

Google Cloud Platformでプロジェクトを作る

最近のGoogleはみんなGoogle Cloud Platformですわー。

f:id:tohokuaiki:20200114181217p:plain

アカウントの追加

でこのプロジェクトを操作できるアカウントを追加する。

f:id:tohokuaiki:20200114181604p:plain

ときて

f:id:tohokuaiki:20200114181703p:plain

サービス アカウント名とサービス アカウントの説明を入力して作成。

f:id:tohokuaiki:20200114181855p:plain

で、このアカウントにロールを付与。とりあえずオーナー入れておけばいいんじゃないのっていう。

f:id:tohokuaiki:20200114181943p:plain

で、キーの作成→JSONでキーファイルがダウンロードされる。

f:id:tohokuaiki:20200114182035p:plain

これでアカウント追加完了。

Google Analyticsの管理画面で先ほど作成したアカウントに権限を与える

GoogleAnalyticsの管理画面に行き、ビューを選び「管理」の所から「ユーザー管理を表示」を選択。

f:id:tohokuaiki:20200114182451p:plain

右上の「+」から先ほど作ったアカウントのメールアドレスを入れる。権限は、「表示と分析」だけでいいでしょう。

f:id:tohokuaiki:20200114182634p:plain

PHPのライブラリをインストールして、サンプルを動かす

ファイルの設置

PHPが使えるサーバーに入って、コマンドラインからcomposerを使ってGoogleが提供してるPHPライブラリを

composer require google/apiclient:^2.0

とインストールする。

既にGoogleがサンプルを用意してくれてるので、ここから取得。HelloAnalytics.phpというファイルが得られるのでサーバーに送る。

アカウントのセットアップ

先ほどの「キーを作成」で取得したjsonファイルを service-account-credentials.json としてHelloAnalytics.phpと同じところにアップする。

HelloAnalytics.phpの44行目当たりにある、

<?php
function getReport($analytics) {

  // Replace with your view ID, for example XXXX.
  $VIEW_ID = "<REPLACE_WITH_VIEW_ID>";

の<REPLACE_WITH_VIEW_ID>を取得する。https://ga-dev-tools.appspot.com/account-explorer/?hl=ja に移動してIDを取得する。

この作業をしたら、HelloAnalytics.phpを動かす。

$ php HelloAnalytics.php
PHP Fatal error:  Uncaught Google_Service_Exception: {
  "error": {
    "code": 403,
    "message": "Analytics Reporting API has not been used in project 32xxxxxxx8237 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/analyticsreporting.googleapis.com/overview?project=329609518237 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "errors": [
      {
        "message": "Analytics Reporting API has not been used in project 32xxxxxxx8237 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/analyticsreporting.googleapis.com/overview?project=329609518237 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
        "domain": "usageLimits",
        "reason": "accessNotConfigured",
        "extendedHelp": "https://console.developers.google.com"
      }
    ],
    "status": "PERMISSION_DENIED"
  }
}

…と、エラーが出る。

URLが表示されるので、アクセスすると

f:id:tohokuaiki:20200114184136p:plain

とでるので、「有効にする」を押す。

…と、ここまでで動くようになったけど、なんかデータ取れなかった。

なんか、サンプルのHelloAnalytics.phpがおかしい

このgetReportが

<?php
function getReport($analytics) {

  // Replace with your view ID, for example XXXX.
  $VIEW_ID = "12345678";

  // Create the DateRange object.
  $dateRange = new Google_Service_AnalyticsReporting_DateRange();
  $dateRange->setStartDate("7daysAgo");
  $dateRange->setEndDate("today");

  // Create the Metrics object.
  $sessions = new Google_Service_AnalyticsReporting_Metric();
  $sessions->setExpression("ga:sessions");
  $sessions->setAlias("sessions");

  // Create the ReportRequest object.
  $request = new Google_Service_AnalyticsReporting_ReportRequest();
  $request->setViewId($VIEW_ID);
  $request->setDateRanges($dateRange);
  $request->setMetrics(array($sessions));

  $body = new Google_Service_AnalyticsReporting_GetReportsRequest();
  $body->setReportRequests( array( $request) );
  return $analytics->reports->batchGet( $body );
}

ってなってるけど、この記事を見ると $dimentionと$orderbyを入れているし…

<?php
function getReport($analytics) {

  // Replace with your view ID, for example XXXX.
  $VIEW_ID = "88097852";
//  $VIEW_ID = "52492899";

  // Create the DateRange object.
  $dateRange = new Google_Service_AnalyticsReporting_DateRange();
  $dateRange->setStartDate("7daysAgo");
  $dateRange->setEndDate("today");

  // Create the Metrics object.
  $sessions = new Google_Service_AnalyticsReporting_Metric();
  $sessions->setExpression("ga:sessions");
  $sessions->setAlias("sessions");

  $dimention = new Google_Service_AnalyticsReporting_Dimension();
  $dimention->setName( 'ga:landingPagePath' );

  $orderby = new Google_Service_AnalyticsReporting_OrderBy();
  $orderby->setFieldName( "ga:sessions" );
  $orderby->setOrderType( "VALUE" );
  $orderby->setSortOrder( "DESCENDING" );

  // Create the ReportRequest object.
  $request = new Google_Service_AnalyticsReporting_ReportRequest();
  $request->setViewId($VIEW_ID);
  $request->setDateRanges($dateRange);
  $request->setMetrics(array($sessions));

  $request->setDimensions( array( $dimention ) );
  $request->setOrderBys( $orderby );    

  $body = new Google_Service_AnalyticsReporting_GetReportsRequest();
  $body->setReportRequests( array( $request) );
  return $analytics->reports->batchGet( $body );
}

これでPHP実行するとパスごとのセッション数が取得できた。

certbotがまたこけてた

certbot renewすると

The requested apache plugin does not appear to be installed. Skipping.

とエラー出して更新してくれない。

ログ /var/log/letsencrypt/letsencrypt.log を見ると

020-01-12 09:32:53,247:WARNING:certbot.renewal:Attempting to renew cert (www.example.jp) from /etc/letsencrypt/renewal/www.example.jp.conf produced an unexpected error: The requested apache plugin does not appear to be installed. Skipping.
2020-01-12 09:32:53,286:DEBUG:certbot.renewal:Traceback was:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 452, in handle_renewal_request
    main.renew_cert(lineage_config, plugins, renewal_candidate)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1187, in renew_cert
    installer, auth = plug_sel.choose_configurator_plugins(config, plugins, "certonly")
  File "/usr/lib/python3/dist-packages/certbot/plugins/selection.py", line 237, in choose_configurator_plugins
    diagnose_configurator_problem("authenticator", req_auth, plugins)
  File "/usr/lib/python3/dist-packages/certbot/plugins/selection.py", line 341, in diagnose_configurator_problem
    raise errors.PluginSelectionError(msg)
certbot.errors.PluginSelectionError: The requested apache plugin does not appear to be installed

2020-01-12 09:32:53,286:ERROR:certbot.renewal:All renewal attempts failed. The following certs could not be renewed:
2020-01-12 09:32:53,287:ERROR:certbot.renewal:  /etc/letsencrypt/live/www.example.jp/fullchain.pem (failure)
2020-01-12 09:32:53,287:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/bin/certbot", line 11, in <module>
    load_entry_point('certbot==0.31.0', 'console_scripts', 'certbot')()
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1365, in main
    return config.func(config, plugins)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1272, in renew
    renewal.handle_renewal_request(config)
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 477, in handle_renewal_request
    len(renew_failures), len(parse_failures)))
certbot.errors.Error: 1 renew failure(s), 0 parse failure(s)

ってなってる。

Apacheのモジュールが必要って、何やねん…って思ったけど、 にあった通り、

apt install python3-certbot-apache

したら直った。

WordPressでの子テーマにおける正しいCSSの読み込み方

なんかイマイチな呼び出し方

子テーマ、便利ですよね。

で、ちょっと上書きしたいCSSを定義したいなーって思って「子テーマ CSS WordPress」あたりで検索するとこんな感じで出てきます。
このエントリで否定する例なので出してしまって申し訳ないのですが…

でも、これを例えばpenmanというテーマの子テーマを作って、子テーマのfunctions.phpに書いてやると、

<?php
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
    wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));

<link rel='stylesheet' id='parent-style-css'  href='https://example.jp/wp-content/themes/penman/style.css?ver=5.3.2' type='text/css' media='all' />
<link rel='stylesheet' id='child-style-css'  href='https://example.jp/wp-content/themes/penman-child/style.css?ver=5.3.2' type='text/css' media='all' />
<link rel='stylesheet' id='penman-style-css'  href='https://example.jp/wp-content/themes/penman-child/style.css?ver=5.3.2' type='text/css' media='all' />

って、子テーマのCSSを2回読んでしまうんです。

何がイマイチかっていうと…

それくらいいじゃんっていう感じなのですが、CSSをアップデートしてキャッシュ対策をしたい場合

<?php
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
    wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'), '20200109');

とかしますよね。でも、出てくるHTMLは

<link rel='stylesheet' id='parent-style-css'  href='https://example.jp/wp-content/themes/penman/style.css?ver=5.3.2' type='text/css' media='all' />
<link rel='stylesheet' id='child-style-css'  href='https://example.jp/wp-content/themes/penman-child/style.css?ver=20200109' type='text/css' media='all' />
<link rel='stylesheet' id='penman-style-css'  href='https://example.jp/wp-content/themes/penman-child/style.css?ver=5.3.2' type='text/css' media='all' />

って、「それ、古いCSSのキャッシュで上書きしちゃってるじゃん!!!」って感じなんですよね。バージョンをアップしてもひたすら意味ないです。

ということで、正しい子テーマのCSS読み方は

<?php
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'parent-penman-style', get_template_directory_uri() . '/style.css' , array(), '20200109-p');
    wp_enqueue_style( 'penman-style', get_stylesheet_directory_uri() . '/style.css', array('parent-penman-style'), '2020010p-c');

ってします。このwp_enqueue_styleの2行は前後どっちでもいいですが、2行目の依存関係が分かりやすいようにしています。

解説

1行目のwp_enqueue_styleで親テーマのCSSを読みこみます。この時、名称は親テーマのCSS名称と同じにしてはいけません。

2行目のwp_enqueue_styleで子テーマのCSSを読みこみます。この時、名称は親テーマのCSS名称と同じにします。更に、依存性で1行目の親テーマのCSSを先に指定することで親テーマのCSSの後でロードされます。

問題があるとすると

親テーマを更新した際に、この子テーマのfunctions.phpのバージョン設定「20200109-p」を新しい文字にしないといけない所ですね。

まあ、面倒なら、親テーマのstyle.cssのタイムスタンプかmd5でも付けちゃえばいいのでは。

Debian10でCertbotがこける

先月、サーバーをdebian10に変更した。

しばらく何の問題も無かったが、Certbotがこけているのに気が付いた。これはどう考えてもPythonが悪い。しかし、今気づいてよかった。

# /usr/local/bin/certbot-auto
Upgrading certbot-auto 0.31.0 to 1.0.0...
Replacing certbot-auto...
Error: couldn't get currently installed version for /opt/eff.org/certbot/venv/bin/letsencrypt:
Traceback (most recent call last):
  File "/opt/eff.org/certbot/venv/bin/letsencrypt", line 7, in <module>
    from certbot.main import main
  File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 5, in <module>
    import logging.handlers
  File "/usr/lib/python2.7/logging/__init__.py", line 26, in <module>
    import sys, os, time, cStringIO, traceback, warnings, weakref, collections
  File "/usr/lib/python2.7/weakref.py", line 14, in <module>
    from _weakref import (
ImportError: cannot import name _remove_dead_weakref

そもそも最近までDebian7だったのでもう思い当たる節がありまくり。

パッケージインストールでは無かったと思うのが、debian10にはパッケージがあるようだ。ということで

# apt install certbot

で、何か入ったっぽい。

…が、which certbox-autoしても /usr/local/bin/certbot-auto という以前入れたのしか出ない。

当然これを実行しても同じエラーが出る… ということで、検索

# find / -type f -name "certbot-auto"

…何も出ない。

おそらく、/usr/local/bin/certbot-autoがあったままだと正常にcertbot-autoがインストールされないのでは…と思い、これを削除(rm /usr/local/bin/certbot-auto)して再インストール。とりあえず動いた…。SSL更新できないみたいなエラー出てるけど、エラーメッセージ出てるだけ相当マシ。