ブログの画像が消えました

は~(°~°)?????キレそーーwwwwwwwwwwww

※このブログでは、ブログ作成に有名なWxxxPxxxxを利用しています。が、検索避けにWPという略称を利用しています。適宜読み替えてください。

ことの発端は、SynologyNAS鯖(DSM)のメジャーバージョンアップデート

SynologyのOS、DSMが6系から7系にメジャーバージョンのアップデートがありました。
6系は使えなくなるよってことでアップデートしました。
ブログデータの一部が消えました。
あなたさあ…

Synologyは擬似的なコンテナというか、puppetというか、なんというか、直接いじられた設定は基本的に保存されないしない、雛形とそれに対するマネージドな変更点の管理だけを行っている
SynologyのWebUIのような間接的なUIを通しての設定変更は維持されるが、
sshして、vim hoge.confして、ってやったものは基本消える

最たる例はnginx.conf
WebStationにてnginx.conf周りをすべて管理されており、結構ややこしい作りになっている
いや、紐解けば、Let’s Encrypt用の鍵であったり、SynologyのWebUI自体をnginxで受け取ってたり、その上でWebStationようにlistenしてる文があって、homeディレクトリのwwwフォルダをWebStationで見れるようになってたり云々カンヌン
やってることは単純

前に少し話したが、(Let’s Encrypt でSSLワイルドカード証明書を導入する)
ホスト名で分けて、あるWebアクセスは全部Synology鯖で受け取ろう。じゃあallow,denyなどのチューニングが必要だな、
proxy_passやらで親子関係を簡単にしよう、
WebStationの設定画面からではそこまでnginxの設定がいじれないようだぞっと、
じゃあnginx.confをsshで入って編集追記してやろうっと、

こうやってせっかく編集したconfファイル、容赦なく消える
サーバの再起動のタイミングでも、SynologyNASのWebUIからちょっと設定をいじっただけでも……
調べただけでも、結構な不満?やら、特有のテクの紹介が出ている。使いやすいんだが曲者だ。悪くない。

しかし、今はクソ面倒なやつだなあ

WebStation自体の設定が読み込まれ、nginx.conf自体がもとに戻ってしまう
いや、WebStationが保持してる設定自体を書き換えてやればいいじゃんwという考え方もあるが、せっかくSynology様がマネージドでやってくれてるんだぜ?それは嫌だ

閑話休題

ということで(?)NAS鯖をアップデートかけました
DSMのメジャーバージョンに合わせて、パッケージ類もいくつかが更新されました。
WPパッケージが再インストールという挙動となりました。
WPの設定が一部リセットとなりました。

ここまではいい
WPの設定が本当に一部だけ引き継がれ、WPの初期セットアップは終わっていることになっているが、SQLのパスワード類が設定されていない、これによりSQLにつながらないというエラーを吐いていた。
これについては後ろで語ろう

アプデにより画像が消えた原因

Synologyはパッケージをひな形だけ管理し、個々の設定はあまり重要視していない

つまり、「WP上で設定した値」や、「WPに直接アップロードした画像」は、
WPが独自で管理している1ファイルとして存在するため、パッケージマネージャ側は認識しないのだ

そのため、DSM自体のアプデによりWPのパッケージが再インストール。
パッケージマネージャが認識しているファイルのみ移行され、見事、直アップロードした画像が消えてしまったとさ

いや、「WP上で設定した値(SQLのパスワードとか)」もそうだけど、そういうのも管理してくれるっていうのがパッケージマネージャじゃないのかよ
公式提供のパッケージなのに

なんのために他の鯖にWPを、それこそコンテナとか使わずに、
NAS上にWPを立てて利用しているのかがわからなくなっちゃった

対策として外部ディレクトリを作成

泣いても戻らないので、対策
2(3)通りの方法があるかなと

  • WPのディレクトリを変えてしまい、WPのパッケージ雛形への依存度を下げる
    具体的に言うと、シンボリックリンクを貼って、画像ファイルを外に出す
  • 画像保存先を変えて、WP管理をやめる
    • CDNみたいな管理方法にする(データ配信する鯖がNASとは別という意味)
    • NASの外部公開機能を利用する

WPに他のストレージのシンボリックリンクを貼って、そこへ直アップロードできるようにする

最初はこれが一番手っ取り早い上に、WPの直アップロードを気にせず使える
そう思ったので、やった
結論としてはACLの手間の問題でできなかった

※検索避けにWPという略語にしてます

WPのフォルダへ
$ cd /var/service/web_packages/WP/
$ pushd wp-content/uploads
$ ls
2021   wp-statistics
→ここにアップロードされた画像やらが詰め込まれている
→例:2021/08/{日付}-{画像サイズ}.jpg とかとか
$ mkdir web
$ ls
2021   web   wp-statistics
$ pushd /
HDD1にある共有フォルダ「Share」にシンボリックリンクを貼る
$ cd /volume1/Share
$ ln -s /var/service/web_packages/WP/wp-content/uploads/web web
$ ls -l
lrwxr-xr-x 1 root root 9 Aug 26 12:00 web -> /var/service/web_packages/WP/wp-content/uploads/web

ここまでは至っていつもどおりのシンボリックリンク作成手順
この後がSynology特有のもので、ACLをいじらないと通常の共有フォルダ上からアクセスできなかった
1時間いじってだめだったので諦めた
ちなみに、SynologyのACLはsynoacltoolというコマンドを利用する

$ type synoacltool
synoacltool is hashed (/usr/syno/bin/synoacltool)
$ synoacltool -get web
(synoacltool.c, 489)It's Linux mode
'→Linuxの権限になっているので、付与していく必要があるっぽい
$ synoacltool -set-owner web ruth
他の共有できているファイルをsynoacltool -getで取得して、必要そうなものをどんどん追加していく
$ synoacltool -add web group:administrators:allow:rwxpdDaARWc--:fd--

という感じで、ACLを設定

が、Windowsなど、他のマシンからこのシンボリックリンクは利用できませんでした。
ディレクトリがあるということは見えるんだが、それ以上ができませんでした

1時間調べてだめだったって書いた気がするけど、もっと多い時間を使ったような気がする
Synology特有のACLの問題だったので、もっとこだわればできたかもしれないけど、考えうるフラグ立てや、お手上げ
他の方法に切り替えていく
こうなるともうDocker管理でええやんって思う思った

画像保存先を変えて、WP管理をやめる

結局こうなった

CDN形式(NASとは別の場所にデータがあるという意味で言ってます)はやりたくない
ただ、一応、GCPのPCAを持ってる関係上、これが最もコスパが良い方法だ。それだけは言える
自宅鯖マンを除いて

WPをRasPiやらWin鯖やらでやらせない理由が、SQLを動かすコストと、その管理がひどく大変だからだ
初めて初代RasPiを手に入れ、これを使ってWeb鯖を構築していた時、MySQLのプロセスが重く、SQL以外まともにRasPiが使えないなんてことがあった。
それから、WPもそうだが、MediaWikiを標的にした、Botによる過剰アクセスがやってきた。
それがRasPiのSDカードを直撃
大学生が使うような安価なSDカードは一週間のうちに焼け焦げて、使い物にならなくなった

そんな経験もあり、「CPU負荷を切り離すことができて、HDDへ書き込めるもの」そんな要件ができた。SynologyNASが最適だったのだ。
再び僕の家にQueryの権威が振るわれることとなったのだ

閑話休題

結局、NAS上のWebStation管理のフォルダにblog用画像保存フォルダを作成し、LBみたいになってる親機のnginxへproxy_passを放り込む。

ただそれだけ…

ちなみに、
PhotoStationというSynologyのマネージド画像ビュアーがあったはずなんだが、DSM7になってなくなったようだ。
FileStationで手に入る共有URLはgofile.me経由になってしまい、直接画像を受け取りが行えない(共有URLへ飛んで直接そこから見ないと見れないので、imageタグで表示ができない)

崩れるだろうけど、AAで言うとこんな感じになってしまった
[Nginx@RasPi] — location /blog/ proxy_pass —> [WebStation(Nginx)@NAS] package:WP(Apache)へのalias:blog
        └– location /blog_images/ proxy_pass —> [WebStation(Nginx)@NAS] /web/images
ポップ数が多い…

さあ、これで外から見える位置に画像を置けるようになった
(URL作成や埋め込みが非情に面倒くさいのだが)
なくなった画像を探しながら、もう一度取得しながら埋めて回りましょう


WPのSQL類の設定(SynologyNASにおけるwp-config.phpの場所)

最初、これで結構時間を取られた
結論としては、SynologyのWebStationを使うようなパッケージは以下の位置にすべて放り込まれている

※検索避けにWPという略語にしてます

$ ls /var/services/web_packages/
@eaDir   phpMyAdmin WP

なので、Synology Packageで入れたもののwp-config.phpはここ

$ find /var/services/web_packages/ -name wp-config.php -type f 
/var/services/web_packages/WP/wp-config.php

自分がやったような、DSMのアップデートを行って、
 error establishing a database connection
というエラー文が表示されてしまった場合、WPのwp-config.phpがおかしくなっているであろう
そのため、php→MySQL(or MariaDB)の認証に失敗しているだけなのだ
落ち着いて、mysqlコマンドからqueryを叩くと、ちゃんとDBに保管されていた記事などのデータは残っていることが確認できる(怖くなってphpMyAdminでも確認した)

sshして、wp-config.phpを見よう

MyDNSのLet’s Encryptのワイルドカード自動更新を導入した

前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)の続き?
MyDNSが公開しているPHPのscriptを導入して、renewが行えるようにした。

背景

もともとLet’s Encryptでワイルドカード証明書を導入する前はcertbot renewをcronに登録していて放置していた。
そしてDNSのときのと同じくこちらも無料でアラートメールをもらって気づいた
前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)重い腰を上げて導入したワイルドカード証明書関係が更新できていないようだ
そのあたりを調査して、MyDNSの自動更新スクリプトを導入した。というお話
ちなみにアラートメールはこんな感じ

Let’s Encryptからのアラートメールはこんな感じ

JTrimでコピペしたんだけど、jpg圧縮の品質悪いっすね
Affinityもってるんだから、面倒臭がらないで、そっちでするべきだったか

現状

アラートメールを受けて、まずはcronに登録しているコマンドを実施確認
(と、その前にまずはcron確認)

# crontab -l
* * * * * /bin/certbot renew && /bin/systemctl reload nginx
→certbotはrootで動かしているが、他のユーザ管理にしたいね
→cronの時間は念の為マスク

# type certbot
certbot is hashed (/usr/bin/certbot)
# which certbot
/usr/bin/certbot
# ls /bin/certbot -l
-rwxr-xr-x 1 root root 960 Apr  7 10:01 /bin/certbot
# ls /usr/bin/certbot -l
-rwxr-xr-x 1 root root 960 Apr  7 10:01 /usr/bin/certbot
→ cronに登録しているcertbotが/binにたいして、certbotは/usr/binにあった
→ シンボリックリンクでもハードリンクでもない
# sha256sum /bin/certbot
2e92fb3a6ca39f7de974ca3e4161197cc347139da68484398e575ec817600587  /bin/certbot
# sha256sum /usr/bin/certbot
2e92fb3a6ca39f7de974ca3e4161197cc347139da68484398e575ec817600587  /usr/bin/certbot
→どっちとも同じハッシュで問題もなく動くが、/usrに変更
# crontab -e
crontab: installing new crontab
# crontab -l
* * * * * /usr/bin/certbot renew && /bin/systemctl reload nginx
→cronの時間は念の為マスク

certbot確認

# certbot renew
(抜粋)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/meto4d.pgw.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')
Failed to renew certificate meto4d.pgw.jp with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

プラグインエラーが起きているから--manual-auth-hookを使えとのこと

certbot certonly --manual --manual-auth-hook /path/to/http/authenticator.sh --manual-cleanup-hook /path/to/http/cleanup.sh -d secure.example.com

This will run the authenticator.sh script, attempt the validation, and then run the cleanup.sh script. Additionally certbot will pass relevant environment variables to these scripts:

User Guide — Certbot 1.15.0.dev0 documentation https://certbot.eff.org/docs/using.html#pre-and-post-validation-hooks

certbotはshell変数を読み取って認証を取る
--manual-auth-hookを指定することで認証前にスクリプトを実行して、shell変数に代入→--manual-cleanupで変数を削除
ということらしい
そもそもcertbotはワンタイムパスワードを取得して、_acme-challengeのTXTレコードにそのワンタイムパスワードを入力、それを認証局が確認して認証という手順
そのワンタイムパスワード関係をshell変数周りで解決するということ

どうもワイルドカードの場合はAPI先を変更しないといけない関係で、certbot renewだけではだめっぽい
手動で認証を取らないといけないっぽい
うーん、めんどうくさい…

MyDNSのLet’s Encrypt更新スクリプトを導入

ということで、MyDNSが公開していたLet’s Encrypt自動更新スクリプトを導入
スクリプトにPHPはちょっとなあと思っていたが、宗教的な感覚なので、重い腰を上げて導入
MyDNSのDomainInfoにこうある

3-2) Let’s Encryptのワンタイムパスワードについて

Let’s Encryptのサーバー証明書を取得する際に、ワンタイムキーをDNS情報のTXTレコードに書くこと、という説明がありますが、MyDNS.JPでは専用APIと、そのAPIを使うためのスクリプトをGitHUBで公開しています。 ですので、Linuxでご利用の場合にはこちらのスクリプトを導入されることをお勧めいたします。

自宅サーバーやVPSに使える無料のダイナミックDNS (Dynamic DNS) https://www.mydns.jp/members/#domaininfo

GitHUBにて専用APIを叩くPHPスクリプトが置かれている
ご丁寧に導入方法も書いてある
が、導入通りのwgetではなく、git cloneでとってくる
PHP8対応が挟まると更新が必要になるかもしれないしね

専用ディレクトリ(/root/cron/mydns)を作って、そこで作業
上でちょろっと書いたけど、root以外で作業させたいね

# php -v
PHP 8.0.3 (cli) (built: Mar  4 2021 13:26:46) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.3, Copyright (c) Zend Technologies
→PHP8がすでにarchのパッケージに配布されていた

# git clone https://github.com/disco-v8/DirectEdit.git
# ls
DirectEdit
# cd DirectEdit
# ls
README.md  txtdelete.php  txtedit.conf  txtregist.php
# chmod 700 *.php
# chmod 600 *.conf
# vim txtedit.conf
→mydnsのIDやパスワードを入力
→yourdomainはワイルドカード手前のサブドメインまで
→ *.meto4d.pgw.jpであればmeto4d.pgw.jp
# certbot certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook /your/domain/directory/DirectEdit-master/txtregist.php \
--manual-cleanup-hook /your/domain/directory/DirectEdit-master/txtdelete.php \
-d meto4d.pgw.jp -d *.meto4d.pgw.jp \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -m hogehoge@hoge \
--manual-public-ip-logging-ok

Use of --manual-public-ip-logging-ok is deprecated.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Use of --manual-public-ip-logging-ok is deprecated.
Cert not yet due for renewal

You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/meto4d.pgw.jp.conf)

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Renewing an existing certificate for meto4d.pgw.jp and *.meto4d.pgw.jp

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/meto4d.pgw.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/meto4d.pgw.jp/privkey.pem
   Your certificate will expire on 2021-08-01. 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

前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)で登録していたが、certbot certonlyでもrenew動作と同じように更新上書きしてくれる
この記事を書きながら実施する前に、テストで前回と同様のcertbot certonlyでTXTレコードを更新して、云々を実施していたので、証明書が更新済み
それでも更新するかしないかを聞かれている
Use of --manual-public-ip-logging-ok is deprecated.と言われているので、それは後で修正しよう

これでOK
あとはsystemctl reload nginxで読み込んでいる証明書を更新

Cron登録用のshellscriptを作る

上の更新をスクリプトに落とし込んでcronに登録してやる
コード表示用プラグインのせいなんだが、上はshellscriptで下はそれを実施したときのコマンド

#!/bin/bash
if test $# -eq 0 ; then
  INPUT=1
else
  if test $1 -eq 1 || test $1 -eq 2; then
    INPUT=$1
  else
    INPUT=1
  fi
fi

echo $INPUT | /usr/bin/certbot certonly --manual --preferred-challenges=dns --manual-auth-hook /root/cron/mydns/DirectEdit/txtregist.php --manual-cleanup-hook /root/cron/mydns/DirectEdit/txtdelete.php -d meto4d.pgw.jp -d *.meto4d.pgw.jp --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -m hogehoge@hoge
# chmod 700 certbot.mydns.sh
# certbot.mydns.sh 1
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Cert not yet due for renewal

You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/meto4d.pgw.jp.conf)

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): Keeping the existing certificate

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate not yet due for renewal; no action taken.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Saving debug log to /var/log/letsencrypt/letsencrypt.log

ちゃんと動作しているみたいだ

# crontab -l
* * * * * /root/cron/mydns/DirectEdit/certbot.renew.mydns.sh 1; /usr/bin/certbot renew && /bin/systemctl reload nginx

定期更新の時間はmaskしてるせいで毎分実施されているように見えるが実際は違う
とはいえ、範囲で指定している
certbot renewは更新なくskippedでも正常終了で終わる(ということを今知った)
→systemctl reload nginxが勝手に挟まってしまう
これはなんとかしたいね
不用意にnginxが再ロードされてしまう。

まあ、これはv6.meto4d.pgw.jpが6/30に切れるらしいので、その更新を手動で行って、証明書更新があったときの文字列を見る→grepとかで探してあれば更新にしよう
cronはコメントアウトして、もう一度アラートメールを受け取るようにして今日は終了。

余談:更新するPHPの中身

DirectEdit/txtregist.php at master · disco-v8/DirectEdit · GitHub https://github.com/disco-v8/DirectEdit/blob/master/txtregist.php

単純にcertbotからやってくる可能性のある変数を配列に入れて、MyDNSへクエリを飛ばしているだけだった
PythonとかRubyとかもう少し管理しやすいスクリプトに書き換えて、そっちで管理してもいいかもね。

Archlinuxのnetctlやらresolvconfやらの設定小話

resolv.confではない
resolvconfの設定
知らなかったこんなの

背景

うちで使っているDNSサーバはMyDNS
MyDNSさんは非常に優秀で、IPアドレスの通知が一定期間ないとアラートメールが飛んでくる。
無料でアラートメールまでくれるのはすごく嬉しい
ちなみにアラートメールはこんな感じ

MyDNSからのメール画面

このDNS更新ができていないことと、resolvconfは何が関係あるんだってことだけど、
cronに登録したperl script(register_ip.pl)でDNS更新を行っている。
このregister_ip.plでは、DNSを解決して、登録IPと現IPを比較し、違ったら登録という処理を行っている。
特にIPv6というか、AとAAAAを登録しているauto.meto4dドメインを確認したいときは、DNS Resolvのあたりの処理をしっかり行わないとできない。
そこで、登録IPを確認するためにNet::DNS::Resolverを動かして得るのだが、もともとのresolvが動いていないと失敗する。
しかもこのエラー文がNet::DNSモジュールにどうとかこうとかというエラーで、DNS Resolveができなかったというエラーを出してくれないので、数ヶ月前に苦労したことがあった。
なんかネットワークがおかしいと想いつつ、sshで他のマシンにつなげようとしたときにresolv.confがどうもおかしいと、やっと判明した。

普通(?)は/etc/resolv.confを編集
nameserverが192.168.xx.18.8.8.8
192.168.xx.1と8.8.8.8が192.168.xx.18.8.8.8とtypo
これを直して終わり
だがそうじゃなかった、

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8

resolvconf?で管理されているらしい
確かに、/etc/resolv.confを編集した後に再起動すると、また間違ったresolv.confが流されている
resolvconfで変更を行う必要があるらしい
そもそもresolvconfとやらを見るのは始めてだし、ちょっと調べたという雑記


resolvconfとは

いつも大変お世話になっております。
Archlinux wikiから

openresolv には resolvconf ユーティリティが入っています。これは複数の DNS 設定を管理するためのフレームワークです。詳しくは man 8 resolvconf や man 5 resolvconf.conf を見て下さい。

https://wiki.archlinux.jp/index.php/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%90%8D%E5%89%8D%E8%A7%A3%E6%B1%BA#openresolv_.E3.82.92.E4.BD.BF.E3.81.86

そもそも論として、自分が体験していた不具合のように、/etc/resolv.confは影響がでかいconfファイルである。
そのため、openresolvなどで安全に変更するフレームワークとなっている

安全に変更されてへんやんか

resolvconfのconfであるresolvconf.confは/etc/resolvconf.confにある

% cat /etc/resolvconf.conf 
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details

resolv_conf=/etc/resolv.conf
# If you run a local name server, you should uncomment the below line and
# configure your subscribers configuration files below.
#name_servers=127.0.0.1

なんも設定されてねえ
テストしてみる。
resolvconfの設定を読み込んで/etc/resolv.confに適用するには# resolvconf -u

% sudo vim /etc/resolv.conf
→適当に変える
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1
nameserver 8.8.4.4

% sudo resolvconf -u
→適用させる
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8
→元の間違った設定に戻っている

resolvconf自体は/run/resolvconf/interface/nic0を参照してresolv.confを生成しているらしい

% cat /run/resolvconf/interfaces/eth0


nameserver 192.168.xx.18.8.8.8
→なんかわからん改行が多いが、編集する
% sudo vim /run/resolvconf/interfaces/eth0
% cat /run/resolvconf/interfaces/eth0     
nameserver 192.168.xx.1
nameserver 8.8.8.8

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8

% sudo resolvconf -u
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1
nameserver 8.8.8.8
→とりあえずresolvconf経由では/run/resolvconfを見ているらしい

そもそも論として/run/を編集するのはおかしい
実際、再起動すると/run/resolvconf/がリセットされていた

% cat /run/resolvconf/interfaces/eth0
nameserver 192.168.xx.1
nameserver 8.8.8.8

% sudo reboot now

% cat /run/resolvconf/interfaces/eth0
nameserver 192.168.xx.18.8.8.8

resolvconfは/run/resolvconf/を参照して/etc/resolv.confを設定しているようだが、/run/resolvconf/はどこを参照して作られているかがわからない
interfacesで管理しているようなので、nic周りで管理されているようだが、、man見ても、調べてもよくわからない

nicからということは、もしかしたらnetctlで定義したnicのDNSを参照している可能性がある

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1''8.8.8.8')

すっごい怪しい
調べたら正しい設定は以下のようだ

DNS=('192.168.xx.1', '8.8.8.8')
→コンマがない

特に出てこなかったが、netctl→resolvconfで/etc/resolv.confを管理している可能性がある

試しに変更してrebootしてみる

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1','8.8.8.8')

% sudo reboot now

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1,8.8.8.8

どうもそうみたいだ
でもnameserver 192.168.xx.1,8.8.8.8はだめ
安全に変更してくれよ

どうも単純な構文解析しかしてないようだ

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1','8.8.8.8')
↓
% grep -i nameserver /etc/resolv.conf
nameserver 192.168.xx.1,8.8.8.8

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1' '8.8.8.8')
↓
% grep -i nameserver /etc/resolv.conf
nameserver 192.168.xx.1
nameserver 8.8.8.8

なるほどなあ

まとめ

netctl のDNSは’シングルクォート’で挟んで、間にスペースが必要
間にコロン,やらが入っているとそのまま代入される
スペースがあることで始めてnameserverが分割される
resolvconfは安全に変更するフレームワーク(疎通確認はちゃんと行わない)

これでやっと再起動してもネットワーク不通問題はなくなったでしょう
たぶん