それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Postfixが ssh ログインして、メールをリレー配送する設定を入れる。

動機: ssh 経由でsendmail を使えると気づいたので応用してみた。

Dockerや仮想マシンを起動でメール設定が億劫だし、postfixのsmartリレーを設定が面倒。Gmail送信するとgoogle アカウントの規制が多い。何度もパスワードを保存設定をするのが面倒だった。sendmailssh 経由で使えることに気づいたとき、メール送信テストで、メールサーバーをいくつ起動しようが、ssh ログインでどっかのPostfixに集約したらいいじゃないかと気づいた。

ローカル postfixsshさせ、SSHで別サーバーからメール送信させたい。

得られるメリット

メール送信は格段に便利になる。

1つのPostfixSSH経由で使い回す。

VPS として使ってるサーバーはpotfix導入済みですね。この vps をポート開放やリレー設定をせずに使いたい。テストサーバーのPostfixのメール送信は、SSH経由でVPSPostfixを利用すればいい。 VPSはポート25から手軽にメールを送信できるのだから、新規でインストールするPostfixVPSSSH sendmail でメールを送信すればいいじゃないか。

root@vps:~# apt list postfix* --installed
Listing... Done
postfix/focal-updates,now 3.4.13-0ubuntu1 amd64 [installed]

Dccker のインスタンスを増やしたり、仮想マシンを増やしているとメール設定と配送テストが億劫になる。億劫だからといって全く設定しないと使えないサービスもある。なので、HostAはすべてのメールを HostB 経由でで送ればいいわけである。 しかし、メールのリレーだとかPostfixのあれこれは覚えたくないのである。そこで、もっとかんたんな方法がないか模索したわけである。

設定と覚えることがシンプル

postfixのことは殆ど知らなくていいのである。ssh接続先に sendmailが動く環境さえあればいい。

パスワードを平文保存しなくていい。

postfix にパスワードを平文保存するための、dockerfileの設定をどうするかと、などを考えなくていい。不要になれば 公開鍵のアクセス許可を抹消すればいい。

ポート開放などに悩まなくていい。

メール送信のサブミッションポートだとかOP25Bとか考えなくていい。22番へ接続してsendmailを起動、メールを配送するだけなのだから。

設定の概要

テストをするにあたり、次のような構成を考えた。

HostA ( postfix) ---ssh----> HostB (postfix  sendmail)-smtp--> gmail smtp など

ssh 関連の設定がちゃんとできるなら使えるはずだ。

  • HostA ( postfix をインストールしたが、自身は外部へ送信しない。
  • HostB ( postfix をインストール・設定済サーバ、smart-replay で外部へ送信する)

HostA Postfixは メール送信を ssh HostB sendmail -i で丸投げ。HostB Postfixは smartリレーで外部のSMTP(Google/Gmail)などへ丸投げ。こうすることとにする。

ssh を使ってメールを送信

HostBのsendmail は、実はSSH経由で呼び出すことができる。

hostBから HostAの sendmail を起動してメール送信

cat sample-mail.txt | ssh HostB sendmail -i -t 

ローカルの場合。

自ホストにpostfixが導入され設定済みであれば、ローカルのpostfix を経由してsendmail でメール送信が可能。

次のように、ローカルのUNIXソケットを使って sendmailコマンドを起動したら終了である。

cat sample-mail.txt | sendmail -i -t 

この、sendmail コマンドは、ssh 経由でも起動することができるので、とてもかんたんに sendmail を使うことができる。

ぶっちゃけ、php だとか、wordpressだとか、python だとかを開発環境で動かす際のメール配送はこれでほとんどが解決する。送信メールコマンドを /usr/sbin/sendmail から ssh hostB /usr/sbin/sendmail に設定を変えれば済むのだから。

ただ、仮想マシンやコンテナだとそうもいかないので、postfixを設定しssh 経由で丸投げすることにする。

postfixssh 経由で sendmail へ転送する。

postfix は メールの配送をいろいろなやりかたで転送することができる。 古えのメーリスだとか、ローカル配送だとか、LAN内で配送とか、部署ごとに配送とかできるわけである。

その一つが postfixのpipe である。すでにpipeがあるんだから、postfix が、 sshコマンドで外部sendmail を呼び出せば設定はとてつもなく簡単になるはずである。

HostA の Postfixssh hostB sendmail を実行させメール配送させる

HostA ( postfix) ---ssh----> HostB (postfix  sendmail)-smtp--> gmail smtp など
  • HostA ( postfix をインストールしたが、自身は外部へ送信しない。
  • HostB ( postfix をインストールしサーバ、smart-replay で外部へ送信する)

これをやる方法が transport service 定義である。

master.cf

postfix のmaster.cf に次の行を追記する。

ssh-relay unix    -       n       n       -       -     pipe
  user=takuya argv=/usr/bin/ssh HostB /usr/sbin/sendmail -i $recipient

main.cf

main.cf 設定に、次の1行を加え、postfix の転送をすべて ssh-relay 経由にする。default_transport を記述すればオッケ

default_transport = ssh-relay

反映

あとは postfix をリロードするわけである。

$ systemctl restart postfix

テスト

cat sample-mail.txt | sendmail -i -t 

これで、メールはPostfixから、ssh のコマンドパイプ(pipe)へ転送され、HostB側で送信処理される。

設定の記述量も極小であり、SSHのポートと公開鍵認証だけを意識すれば解決である。ウルトラシンプルである。

公開鍵の設定。

postfix のmaster.cf に追記した箇所を見てみる。

ssh-relay unix    -       n       n       -       -     pipe
  user=takuya argv=/usr/bin/ssh HostB /usr/sbin/sendmail -i $recipient

ここでは、どのようにメールを配送するのか書いてある。 unix ソケットで受け付けて pipeながす。

pipe の先に ssh コマンドを起動する。起動するコマンドは ssh コマンドで sshがHostBでリモートsendmail を起動する。

とくに、難しいことはない。

ただし、公開鍵認証でコマンドが実行できる必要がある。

hostA に takuya ユーザーを作成し、hostB へ鍵を登録する。

root@hostB:/root $ adduser takuya
root@hostB:/root $ su takuya
takuya@hostB:~ $ ssh-keyen -t rsa 
takuya@hostB:~ $ ssh-copy-id hostA

公開鍵の登録をすれば、ssh 経由で sendmail が呼び出せることを確認しておく

takuya@hostB:~ $ cat - | ssh hostA /usr/sbin/sendmail -i -t 
To:takuya@example.com
From:takuya@example.com
Subject: relay test


hello from HostA via ssh HostB

メールが無事に配送されることを確認する。あとは hostA の postfix にローカルからの sendmail コマンドでSSH経由させるだけである。 楽である。

この設定を作ったときに躓いたポイント。

ユーザーの秘密鍵パーミッション。と master.cf へ記述する user=$USER のユーザー

ssh を実行するユーザーは root/postfix とかだとうまく行かなかった。

  • postfix ユーザーで ssh を起動しようとしたら status=deferred (unknown mail transport error) になるし
  • mail ユーザーで ssh 起動しようとしたら、No such file or directory. Permission denied, please try again._ Permission denied, please try again になるし
  • root の場合は、postfix が privilegedはだめとかいうし。

というわけで一般ユーザーで起動するのが無難だった。

秘密鍵を指定してみる。

ssh コマンドを指定なのだから、秘密鍵を引数でファイル指定すればいいはずである。 ssh -i 秘密鍵PATHで使えるのでそれを設定すれば動くはずである。

ssh-relay unix    -       n       n       -       -     pipe
  user=mail argv=/usr/bin/ssh -i  秘密鍵パス  takuya@HostB /usr/sbin/sendmail -i $recipient

hostA で次のコマンドを実行して、HostBからメール送信ができれば、postfixも同じ設定を使えるはずである。

mail ユーザ が sendmail をリモート実行できることを確認する。

root@hostA:~ $ cat sample-mail.txt | sudo -u mail ssh -i /etc/mail/ssh-sendmail-key -l takuya hostB  /usr/sbin/sendmail -i takuya@example.com

送信できれば、mail ユーザーを使う設定を記入する

postfix/master.cf に設定を追記する

今回は、設定名を変えて追記した。

ssh-relay2 unix    -       n       n       -       -     pipe
  user=mail argv=/usr/bin/ssh -i /etc/mail/ssh-sendmail-key -l takuya 192.168.2.5 /usr/sbin/sendmail -i $recipient

postfix/main.cf に設定を追記する

default_transport = ssh-relay2

これで、固定ユーザーに依存せずにメール起動ができるのである。便利ですね。

公開鍵の機能を限定しておく。

特定の公開鍵では、機能を限定することが可能なので、 authorized_keys を使って機能を限定しておけば安心である。接続元を限定したり、起動可能なコマンドを限定しておけばいい。

実際にやってみると楽だった

たとえば、SSHが可能でsendmail が利用可能なレンタルサーバーやVPS経由でメールを送信すれば、 OP25B や submission ポートに悩まされずに済む。

また、VPS側で postfixをリッスンせず、SSHのみ済むのでファイアウォール設定がとてもシンプルに片付くのである。

また、仮想マシンを増やすたびに smart-replay ホストを設定しパスワード保存する必要もないし、 smart-relayを設定するたびに、Google SMTPサーバーや google account secutiy で警告をもらわずに済むのである。

ssh で トンネル貼る必要もないし、socks5しなくても済むし、VPNも要らないのである。SSHなのでちゃんと暗号化されているのである。

さくらVPSやheteml レンタルサーバーで ssh sendmail をしてしまえば、25番ポートからfromをアレしたメールが送り放題になってしまうのである。postfixSSH pipe経由とは、実に、けしからんメール配送解決策である。

参考資料

Using sendmail over SSH - Super User

sendmail コマンドを ssh 経由で呼び出せることに気づいた。

sendmail でメールを送ろうとして苦労してた。

webの問い合わせフォームだとか、phpsendmail をサーバでは使えるが、ローカルでは smart-relay な postfix を設定して試していた。

実にめんどくさいことだった。或る日、コマンドを眺めていて、ふと気づいた。sendmail って ssh経由で呼び出せるんじゃね。

ローカルのpostfix を経由してsendmail を使う場合、次のように、ローカルのUNIXソケットを使って sendmailコマンドを起動したら終了である。

cat sample-mail.txt |sendmail -i -t 

これ、ssh経由でコマンド呼び出せば、メール配信完了するんじゃないか。ためしたできた。いままでの 苦労は何だったんだ・・・

ssh を使ってメールを送信

HostBのsendmail は、じつは、SSH経由で呼び出すことができる。

cat sample-mail.txt | ssh HostB /usr/sbin/sendmail -i -t 

この、sendmail コマンドは、ssh 経由でも起動することができるので、とてもかんたんに sendmail を使うことができる。

ぶっちゃけ、php だとか、wordpressだとか、python だとかを開発環境で動かす際のメール配送はこれでほとんどが解決する。

レンタルサーバーやVPSSSH経由でsendmail コマンドを発行すればいいのだから。

windows の標準搭載されている、マイクロソフトのアプリを削除する

プリインアプリは正直言って要らないもある。

右クリックメニューででてきたり、開くメニューで目障りなので消してしまいたい。

windows の標準搭載されている、マイクロソフトのアプリを削除する。

メール・カレンダーは消すか迷う。

たとえば People を消すには、次のようにします。

get-appxpackage *Microsoft.People* | remove-appxpackage

f:id:takuya_1st:20210305111340p:plain

まず使わないアプリを消す

以下は、まず使うことがないので消しておく。

## Groove ミュージック
get-appxpackage *Microsoft.ZuneMusic* | remove-appxpackage
### 映画テレビ
get-appxpackage *Microsoft.ZuneVideo* | remove-appxpackage
## OneNote
get-appxpackage *Microsoft.Office.OneNote* | remove-appxpackage
## People
get-appxpackage *Microsoft.People* | remove-appxpackage
## Xbox
get-appxpackage *Microsoft.XboxApp* | remove-appxpackage
## ペイント 3D
get-appxpackage *Microsoft.MSPaint* | remove-appxpackage

ペイント 3Dは、標準から削除されるようなのでとっとと削除してほしい。

Xboxも要らないと思うし、映画テレビなんてもっといらない。Grooveに至ってはMSは買収後放置しすぎだろ。

アプリ名の調べ方。

Powershell だけだと覚えることが多すぎるので、MSYS/MinGWから動作すると楽。

MINGW64 ~$ powershell  'get-appxpackage Microsoft*' | grep ^Name | sort 

参考資料

https://answers.microsoft.com/ja-jp/windows/forum/apps_windows_10-outlook_mail/windows-10/239ef7e9-9f4f-40dc-bf41-2cd2b8217843

windows 標準カレンダ・メールにiCloud のアカウントを接続する。

windows のメール設定に書いても設定できない。

Windows のカレンダーとメール設定に icloud のアカウントを設定し、iPhone とカレンダーを共有する。

iCloud のアカウントと接続すれば問題ない。だが、設定にはいくつかの問題点がある。

アプリのプライバシー設定

アプリのプライバシー設定で、Windowsのカレンダ・メールが「アカウント」のアクセス権をもっていないと、エラーにすらならず、設定画面が設定中で止まるだけである。権限がないというメッセージも出てこない。

icloud のパスワード設定

iCloud では、パスワードをデバイスに保存する使い方が非推奨となっていて、パスワードを保存が必要なアプリごと「別のパスワード」を発行するようになっている。OAuthをしなくてもいいのは便利だが、設定がわかりにくいので知らないと詰む。

アプリのプライバシー設定

アプリのプライバシー設定は、Windowsの設定からプライバシー、アカウントを選んで設定。

f:id:takuya_1st:20210304070807p:plain

Apple ID の設定画面でパスワードを生成

https://appleid.apple.com/account/manage にアクセスし、セキュリティからパスワードを追加。

f:id:takuya_1st:20210304071450p:plain

準備が整ったら、 Windowsでアカウントを追加する。

アカウントの追加を押す。

f:id:takuya_1st:20210304071645p:plain

icloud を選んで作成したパスワードを入れる。

f:id:takuya_1st:20210304071113p:plain

これでWindowsのカレンダーからiCloud が使える。

Windowsのカレンダーからイベント(予定)の編集と追加が行えるようになる。

その他の方法。

applewindows 版の icloud アプリをインストールしてもいいが、 outlook にしか対応しておらず、Windowsプリインアプリのメール・カレンダーでは使えないので注意が必要。

WSL (v1)からdocker を使う

WSL (v1)からdocker を使う

WSL から Docker を使うには、TCPでローカルホストに接続するのが楽ちん

docker ( windows ) のインストール

まずは、Windows にDocker-Desktop をインストール

choco install docker-desktop

port 2575 を有効にする。

インストールしたら、Dockerが外部からの接続を受け付けるように設定する。

f:id:takuya_1st:20210304070117p:plain

WSL 側で docker-client を使えるようにインストール。

WSL v1 ( ubuntu / debian )で docker コマンドをインストール ( cli だけでいい)

sudo apt install docker-ce-cli

DOCKER_HOST の環境変数を用意する。

docker-desktop がリッスンしているポートを指定する。

export DOCKER_HOST=tcp://localhost:2375

あとは通常通り使える

WSL v2 じゃないとだめってわけじゃなく、TCP接続すれば別に問題なく動く。

docker ps 

たとえば、php を動かす。

php のコードを docker 内部で動作させる。

wsl v1 のパスを 明示的に変換する必要がある。とくにボリュームを接続するときは、 wslpath を使ってwindowsC:\ のパスに変換して上げる必要ある。

docker run --rm -it -v "$(wslpath -m ${PWD})":/app -w /app -u www-data php:7.4-cli php test.php

ボリュームの接続先はどこでも動きそうだ。

WindowsビルトインのOpenSSH サーバーが鍵認証できない。(ログを有効にして確認しながら設定する。)

Windows のOpenSSH サーバーが鍵認証できない。

ログをみると、公開鍵で認証できない。理由はパーミッションパーミッションLinux/BSDと同じく他者から書き込み不可が必須である。

WindowsでもLinuxなどのOpenSSH-サーバーと同じ

Admin権限で sshd.exe が起動している。設定はLinuxと同じ。authorized_keys の権限は、他人から読み込みはオッケ。書き込みは自分だけ。

デフォルトの設置場所

C:\ProgramData\ssh\administrators_authorized_keys

WindowsのデフォルトのsshdC:\ProgramData\ssh に公開鍵を保存します。 ここはシステム領域なので注意が必要です。SSHログインするユーザがUACを使えないと書き込みできません。

設定

Windowsビルトインのssh サーバーに設定する設定は次のとおりです。

## 既存
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
## 追加
Match User takuya
       AuthorizedKeysFile .ssh/authorized_keys

私は、ユーザフォルダに設置するほうが確実だと思います。

公開鍵のフォルダのパーミッションに注意します。

公開鍵をいれた( authorized_keys ) のパーミッションは次のようにします。

編集は自分だけ。

閲覧はAdministrators だけ

エラーメッセージを見るには。

冒頭にある、パーミッションエラーの詳細なログ情報は、ssh サーバーの設定を変更し再起動するとファイルに書かれます。

sshd.exeの設定とログは、次のフォルダに設定ファイルがあり、ログも同じ場所に書かれます。

設定フォルダ

C:\ProgramData\ssh

logs にログを書き出したいとき。

logs フォルダに、ログを書き出し時は、つぎのように、設定を LOCAL0 に変えると、通常のLinuxと同じくファイルにAppendされてる。

# Logging
SyslogFacility LOCAL0
#SyslogFacility AUTH
#LogLevel INFO
LogLevel DEBUG3

もし設定をせず、デフォルト設定のままであれば、ログは、Syslog( event viewer )に書かれる。しかしsyslog では、ログの詳細情報が書かれず、全く役に立たない。そのためファイルに記入させる必要がある。 ファイルに記入させる設定が SyslogFacility local0 である。 設定し再起動 net stop ssh ; net start ssh するとログが見れるようになる。

ログを流すようにすると、公開鍵認証に関するエラー確認できる。公開鍵の認証設定が動くようになるまで、デバッグモードでログをファイルに書くようにする。

windows ビルトインの sshd(openssh-server)の再起動。

設定ファイルを編集したら、再起動して設定を反映します。

管理者権限の コマンドコンソールで

net stop sshd
net start sshd

PS (powershell) からは Service コマンドで、この手の記述でも動くはず(ためしてない)

PS C:\ProgramData\ssh> Stop-Service  sshd
PS C:\ProgramData\ssh> Start-Service sshd
PS C:\ProgramData\ssh> ReStart-Service sshd
PS C:\ProgramData\ssh> Stop-Service    'OpenSSH SSH Server'
PS C:\ProgramData\ssh> Start-Service   'OpenSSH SSH Server'
PS C:\ProgramData\ssh> ReStart-Service 'OpenSSH SSH Server'

注意点: 接続中は再起動されない。

これは、LinuxのOpenSSHサーバーと違う点なので注意。

接続中のセッションがあれば、サービス再起動されない。接続が残っていると再起動がうまく行かず、設定が反映されないことがあるので注意

わたしも、設定反映されなくてパニクった。

ユーザーフォルダのAuthorized_keys を使いたい。

デフォルトでは、authorize_keys の設置場所は、Adminと一般ユーザーで違う場所が指定されている。WEBサイトを閲覧していると、Match Group コメントアウトするように指示する記事を散見するが、個人的には Match User を追記する方法おすすめしたい。

sshd_config に自分のユーザーだけの設定を書く。

Match User takuya
       AuthorizedKeysFile .ssh/authorized_keys

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

Match Group administrators の末尾をコメントアウトするか、Match User を作るかは趣味の問題だが、個人的にはデフォルト設定を生かした設定をしたほうがベターだと思う。

公開鍵認証について

WindowsのOpenSSHサーバーでも通常通り公開鍵認証ができます。

「公開鍵認証」とは、<秘密鍵と公開鍵のペア>を使います。

公開鍵をサーバーに登録しておけば、秘密鍵を持った人だけが、アクセスできます。一般的に使われるRSA公開鍵では、秘密鍵から公開鍵が導出されます。

公開鍵は「公開」するためのものです。誤解を恐れず、極めて短言で表現すれば、公開鍵の束(authorized_keys)は「印鑑証明」です。公開するものです。臆さず公開して構いません。

ハンコと捺印で例れば、印章が「秘密鍵」、印影が「公開鍵」です、ログインが「捺印・印鑑」です。( RSA鍵の署名と暗号化については、詳しくは、RSA公開鍵暗号方式ググること)

また、公開鍵暗号方式RSA公開鍵であるとは限らないのも注意。

WindowsSSHサーバの公開鍵設定でググったら、公開鍵と秘密鍵の違いすら分かってないようなブログ記事が散見され、ヤバさしかなかった。

公開鍵は「秘匿する」ものじゃないですからね。また id_rsa が公開鍵じゃないですからね。

Windowsな人たちは、なんで、id_rsa を公開キーとか書いちゃうんだろう。また公開鍵を秘密にしたがるんだろう。 なんで鍵ペアを知らないんだろう。

関連記事

SSHが鍵認証されないとき、パーミッションを疑え。 - それマグで!

右クリック禁止のサイトへ対策するシンプルな方法。

アフィサイトごときが、右クリック禁止をするなんておこがましい。

銀行サイトごときが、残高表示の金額を選択させないなんて、バカにしてんのか。

ドメイン購入サイトごときが、戻るだけで決済されてませんって、フザケンナと。

というわけで、一瞬にして対策できるシンプルなコードを

右クリック禁止の対応。

`
selectstart
contextmenu
dragstart
mousedown
copy
cut
paste
mousedown
mouseup
beforeunload
beforeprint
`.split(/\s/).filter(String).forEach((e, i) => {
  window["on"+e] &&(  window["on"+e] = null );
  document["on"+e] && (document["on"+e] = null);
  window.addEventListener(e, function(ev){ev.stopPropagation()}, true);  
});

Array.from(document.querySelectorAll('*')).filter( e => e.style.userSelect ).forEach(e => e.style.userSelect='auto')

UserJSなどに突っ込んでおけば、お手軽にいらっとすることがなくなる。

他人の記事をパクるサイトほど、右クリック禁止だし。

銀行が、残高表示させるくせに、残高をコピーできないとかさ。

ほんとうにWEBをなめてるよね。

拡張機能でもいいけど、iOS Safari でどうしようもないのは、本当に困りますね。

userSelectはメニューなどでテキスト選択が暴発すること防ぐためにあって、本文をコピーされないためではないですよね。

全角の英数を半角の英数に統一する(ただし、記号は除外)

全角を半角にする。

php で日本語の英数字(A-Z)を半角にしたいときは、文字コードのコードポイントを用いた計算ができる。

英数字だけを半角にしたいとき。

<?php
$v = 'Microso'
$v = preg_replace_callback('/[A-Za-z0-9]/u',function($s){
  $s = IntlChar::chr(IntlChar::ord($s[0]) - 0xFEE0);
  return $s;
},$v);

通常であれば mb_convert_kana

mb_convert_kana でもいいのだけれど、記号が変換されてしまう。

<?php
$v = 'Microso'
mb_convert_kana( $v , 'a')

ord ではなく、IntlChar::ordを使う理由

IntlChar::ord が必須。ord()はユニコード(utf8) の文字コードを計算できない。

配列の全てを半角にするには

filter_vars を使うと便利

<?php
 $arr_group =filter_var($section_group, FILTER_CALLBACK, ['options' => function ($v) {
                  $v = preg_replace_callback('/[A-Za-z0-9]/u',function($s){
                    $s = IntlChar::chr(IntlChar::ord($s[0]) - 0xFEE0);
                    return $s;
                  },$v);
                  return $v;
                }]);

全角半角の置換

全角半角の英数字の置き換えは、Unicode文字コードポイントをだして、 cp - 0xFEE0 をすればいい。これを覚えておけば、他のプログラム言語でも対応が可能になる。

参考資料

wireguardのvpn をwg-quickを抜きで作ってみる。(ip6tablesなどの細かい設定を制御してv6NATしたい)

wireguard vpn を手作業で作る

openwrt がv6のアドレスに対して wireguard を作成すると、インタフェースの設定ではなぜかエラーになったので、手作業でコマンドを打ち込んでwireguard を起動する必要があってめんどくさかった。wg-quick もそのままインストールできないし。

マニュアルで接続する

wg-quick がないときに、手作業(マニュアル)でwg0のインターフェイスを定義して、そこをWireguardを使ってVPNを接続する。

最初に受け付ける側(サーバー動作)

wireguardはサーバとクライアントの区別が曖昧なので、明確にサーバーと呼べないと思われる。

最初に、接続受けつける側で受け付けられる用に設定を作っていく。

既存の削除

ip link set wg0 down
ip link delete dev wg0

インターフェースの作成

インターフェイスを作成して、IPアドレスを割り当てる。

ip link add dev wg0 type wireguard
ip addr add 172.16.3.2/32 dev wg0

ポートとプライベートキーの設定

どのポートでリッスンするかを決める。リッスンポートは決められるがリッスンするインターフェイスは決められない。

ポートは自由に決められる。iOSのソフトウェアやwireguardのマニュアルは 51821 を使っているのでそれに倣う。

wg set wg0 listen-port 51821 \
private-key /etc/config/custom/wireguard/wg0.server.key 

peer 接続

さらにサーバー側に、peer 間接続で使う設定を入れる。

wg set wg0 \
 peer UF52AMi4xLFYHN21XVcZUnDmuYY6xriM3TyAOrmNTHE=\
 preshared-key   /etc/config/custom/wireguard/wg_psk.psk\
 endpoint 2xxx:xxx:8383:a300:5054:ff:fxxx:xxxx:51821\
 allowed-ips 172.16.3.1/32

次のクライアントのを接続を受け付けますよ。という設定をする。

接続可能なクライアントの設定という体になる。 peer 同士が接続するのでサーバーとクライアントの明確な区別はないのだが。便宜上。

クライアント側も同様にしておく。

同様の設定を peerの両端に行う。

開始

ip link set wg0 up

必要に応じて routing を設定する。

172.16.3.1/32 側(今回のサーバー側で、クライアント側への経路)

ip route add 172.16.3.2/32 dev wg0

172.16.3.2/32 側(今回のクライアント側で。サーバー側への経路)

ip route add 172.16.3.1/32 dev wg0

覚えにくいのでスクリプトにまとめる。

シンプルとはいえ、手順は多いので、スクリプトにwg0 の作成と接続とルーティングをまとめて行うスクリプトをを作っておいた。

wireguard の 手順がわかりやすくなった。

出来上がった実行スクリプト

/etc/config/custom/wireguard/wg0-start.sh

#!/bin/bash

# ## LOCAL
# WG_IF=wg0
# WG_PORT=51821
# WG_LOCAL_LISTEN_PORT=$WG_PORT
# WG_LOCAL_IPv4=172.16.3.2/24
# WG_LOCAL_IPv6=fd00:baba:afac:4610::2/64
# WG_LOCAL_v4_NETADDR="${WG_LOCAL_IPv4%.*}.0/24"
# WG_LOCAL_v6_NETADDR="${WG_LOCAL_IPv6%:*}::/64"
#
# CONFIG_PATH=/etc/config/custom/wireguard/$WG_IF
#
# ## 秘密鍵
# WG_LOCAL_SECRETKEY_PATH=$CONFIG_PATH/secret.key
#
# ## PEER 設定
# WG_PEER_PUBKEY=$(cat $CONFIG_PATH/peer.pub)
# WG_PEER_PSK_PATH=$CONFIG_PATH/peer.psk
# WG_PEER_KEEPALIVE=60
# WG_PEER_ENDPOINT_IP=
# WG_PEER_ENDPOINT_PORT=$WG_PORT
# WG_PEER_ENDPOINT=$WG_PEER_ENDPOINT_IP:$WG_PEER_ENDPOINT_PORT
# ## 対向IPアドレス
# WG_PEER_IPv4="${WG_LOCAL_IPv4%.*}.1/24"
# WG_PEER_IPv6="${WG_LOCAL_IPv6%:*}:1/64"
# ## wg0ネットワークアドレス
# WG_PEER_IPv4_NET_ADDR=$WG_LOCAL_v4_NETADDR
# WG_PEER_IPv6_NET_ADDR=$WG_LOCAL_v6_NETADDR
# ## 転送をするリモートネットワーク
# REMOTE_NETWORK=( 192.168.2.0/24 192.168.100.0/24 )
# ENABLE_ROUTING=1
# ENABLE_DEFAULT_GW=1


WG_NATv6_ENABLED=1


function restart(){
  stop;start;
}
function stop(){
  ## 既存の削除
  if ip link show  $WG_IF 1>/dev/null  2>&1  ; then
    ip link set $WG_IF down
    ip link delete dev $WG_IF
  fi
}
function start_wg(){
  ## 既存の削除
  if ip link show  $WG_IF 1>/dev/null  2>&1  ; then
    echo already up.
    return 0;
  fi
  ## v6 経由の経路を追加しとく
  set_NTTflets_NGN_route;

  # インターフェースの作成
  ip link add dev $WG_IF type wireguard
  ip addr add $WG_LOCAL_IPv4 dev $WG_IF
  ip addr add $WG_LOCAL_IPv6 dev $WG_IF
  ip link set mtu 1420 up dev $WG_IF


  # ポートとプライベートキーの設定
  cmd="wg set $WG_IF listen-port $WG_LOCAL_LISTEN_PORT \
   private-key $WG_LOCAL_SECRETKEY_PATH"
  #echo $cmd
  $cmd;
  # 開始
  ip link set $WG_IF up

}
function add_peer(){
  ## peer 接続
  cmd="wg set wg0
   peer $WG_PEER_PUBKEY
   preshared-key   $WG_PEER_PSK_PATH
   persistent-keepalive $WG_PEER_KEEPALIVE
   allowed-ips $WG_PEER_IPv4_NET_ADDR,$WG_PEER_IPv6_NET_ADDR,$(IFS=,; printf '%s' "${REMOTE_NETWORK[*]}")
   "
  if [[ ! -z $WG_PEER_ENDPOINT ]]; then
    cmd="$cmd endpoint $WG_PEER_ENDPOINT ";
  fi
  # 実行
  # echo $cmd
  $cmd;

  ## 経路作成
  allow_forwardings_v4
  #allow_forwardings_v6
  add_route

}
function start(){
  ## wg接続を開始
  start_wg;

  ## peer を作成
  add_peer


}

function allow_forwardings_v6(){
  enable_v6_forwarding
  allow_v6_forwarding
}
function allow_v6_forwarding(){

  echo WG_NATv6_ENABLED=$WG_NATv6_ENABLED
  if [[ -z $WG_NATv6_ENABLED  ]] ; then
    ip6tables -I INPUT   -i $WG_IF -j ACCEPT
    ip6tables -I FORWARD -i $WG_IF -j ACCEPT
    ip6tables -I OUTPUT  -o $WG_IF -j ACCEPT
    ip6tables -I FORWARD -o $WG_IF -j ACCEPT
  else
    allow_v6_masquerade
  fi
}
function allow_v6_masquerade(){

  WG_IF=wg0
  NGN_IF=eth1
  LAN_IF=eth0

  DEFAULT_v6_GW=$( [[ $(ip neigh show dev $NGN_IF ) =~ (fe80[0-9a-f:]+) ]] ; echo ${BASH_REMATCH} )
  NGN_Adr=$([[ $(ip -6 addr show dev $NGN_IF ) =~ (2001|2400)[a-f0-9:/]+ ]]; echo $BASH_REMATCH)
  NGN_NAdr=${NGN_v6%:*:*:*:*}::/64

  WG_Adr=$([[ $(ip -6 addr show dev $WG_IF ) =~ fd([a-f0-9:]{1,4})+/[0-9]+ ]]; echo $BASH_REMATCH)
  WG_NAdr=$(owipcalc  $WG_Adr network)

  ## WG_IF → NGN へのNAT
  #echo ip6tables -A FORWARD -i $WG_IF  -o $NGN_IF -j ACCEPT
  #echo ip6tables -A FORWARD -i $NGN_IF -o $WG_IF  -j ACCEPT -m conntrack --ctstate RELATED,ESTABLISHED
  #echo ip6tables -t nat -A POSTROUTING -o $NGN_IF -d ::/0 -j MASQUERADE
  ip6tables -A FORWARD -i $WG_IF  -o $NGN_IF -j ACCEPT
  ip6tables -A FORWARD -i $NGN_IF -o $WG_IF  -j ACCEPT -m conntrack --ctstate RELATED,ESTABLISHED
  ip6tables -t nat -A POSTROUTING -o $NGN_IF -d ::/0 -j MASQUERADE
  ## LAN→ WG_IF へのNAT
  ip6tables -I FORWARD -i $WG_IF  -o $LAN_IF -j ACCEPT
  ip6tables -t nat -A POSTROUTING -o $WG_IF -d ::/0 -j MASQUERADE

}

function allow_forwardings_v4(){
  enable_v4_forwarding
  allow_v4_forwarding
}
function allow_v4_forwarding(){
  iptables -I INPUT   -i $WG_IF -j ACCEPT
  iptables -I FORWARD -i $WG_IF -j ACCEPT
  iptables -I OUTPUT  -o $WG_IF -j ACCEPT
  iptables -I FORWARD -o $WG_IF -j ACCEPT
}
function enable_v4_forwarding(){
  sysctl net.ipv4.conf.all.forwarding=1 > /dev/null
}

function enable_v6_forwarding(){
  sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
}
function add_route(){


  ip route add ${WG_PEER_IPv6%/*} from ${WG_LOCAL_IPv6%/*} dev $WG_IF metric 499 onlink

  if [[ $ENABLE_ROUTING != 1 ]]; then
    return;
  fi
  ## 例
  # 特定のIPだけ転送する場合。
  #   ip route add 192.168.100.5/32  dev $WG_IF via ${WG_PEER_IPv4%/*} onlink
  # ネットワーク転送する場合。
  #   ip route add 192.168.100.0/24  dev $WG_IF via ${WG_PEER_IPv4%/*} onlink
  for e in ${REMOTE_NETWORK[@]} ; do
    GATEWAY=''
    if [[ $e =~ : ]] ; then
      v6='-6'
      GATEWAY=${WG_PEER_IPv6%/*}
    else
      v6=''
      GATEWAY=${WG_PEER_IPv4%/*}
    fi
    if [[ $e == 0.0.0.0/0 && ! $ENABLE_DEFAULT_GW == 1 ]]; then
      return
    fi
    if [[ $e == ::/0 && ! $ENABLE_DEFAULT_GW == 1 ]]; then
      return
    fi

    echo ip route add $e  dev $WG_IF via $GATEWAY  metric 499 onlink
    ip route add $e  dev $WG_IF via $GATEWAY metric 499 onlink
  done
}
function set_NTTflets_NGN_route(){
  ## v6 の経路を明示的に指定したいとき
  ## わたしはNGNを壊れたまま運用。v6デフォルトGWを設定せずv6を壊してある。
  ## 特定のv6と通信するとき経路情報を都度入れている。
  /etc/config/custom/ipip6/v6_default_route.sh add $WG_PEER_ENDPOINT_IP
}





function main(){

  case $1 in
    start*)
      echo "start interface $WG_IF";
      start;
      ;;
    stop*)
      echo "stop interface $WG_IF";
      stop;
      ;;
     restart*)
      echo "restart interface $WG_IF";
      restart;
      ;;
    *)
      echo $0 'start|stop|restart';
      ;;

   esac

}

接続する側(クライアント)

#!/bin/bash


scripts=$(echo $(dirname $0)/../wg-start.sh)
source $scripts

## LOCAL
WG_IF=wg0
WG_PORT=51821
WG_LOCAL_LISTEN_PORT=$WG_PORT
WG_LOCAL_IPv4=172.16.3.1/24
WG_LOCAL_IPv6=fd00:baba:afac:4610::1/64
WG_LOCAL_v4_NETADDR="${WG_LOCAL_IPv4%.*}.0/24"
WG_LOCAL_v6_NETADDR="${WG_LOCAL_IPv6%:*}:/64"

CONFIG_PATH=/etc/config/custom/wireguard/$WG_IF

## 秘密鍵
WG_LOCAL_SECRETKEY_PATH=$CONFIG_PATH/secret.key

## PEER 設定
WG_PEER_PUBKEY=$(cat $CONFIG_PATH/peer.pub)
WG_PEER_PSK_PATH=$CONFIG_PATH/peer.psk
WG_PEER_KEEPALIVE=60
#### サーバー側ではendpoint は使わない
#### WG_PEER_ENDPOINT_IP=
#### WG_PEER_ENDPOINT_PORT=$WG_PORT
#### WG_PEER_ENDPOINT=$WG_PEER_ENDPOINT_IP:$WG_PEER_ENDPOINT_PORT
## 対向IPアドレス
WG_PEER_IPv4="${WG_LOCAL_IPv4%.*}.2/24"
WG_PEER_IPv6="${WG_LOCAL_IPv6%:*}:2/64"
## wg0ネットワークアドレス
WG_PEER_IPv4_NET_ADDR=$WG_LOCAL_v4_NETADDR
WG_PEER_IPv6_NET_ADDR=$WG_LOCAL_v6_NETADDR
## 転送をするリモートネットワーク
REMOTE_NETWORK=( 192.168.1.0/24 ::/0 )
##
ENABLE_ROUTING=1


##
main $@

接続を貰う側(サーバー)

#!/bin/bash


scripts=$(echo $(dirname $0)/../wg-start.sh)
source $scripts

## LOCAL
WG_IF=wg0
WG_PORT=51821
WG_LOCAL_LISTEN_PORT=$WG_PORT
WG_LOCAL_IPv4=172.16.3.2/24
WG_LOCAL_IPv6=fd00:baba:afac:4610::2/64
WG_LOCAL_v4_NETADDR="${WG_LOCAL_IPv4%.*}.0/24"
WG_LOCAL_v6_NETADDR="${WG_LOCAL_IPv6%:*}:/64"

CONFIG_PATH=/etc/config/custom/wireguard/$WG_IF

## 秘密鍵
WG_LOCAL_SECRETKEY_PATH=$CONFIG_PATH/secret.key

## PEER 設定(接続先)
WG_PEER_PUBKEY=$(cat $CONFIG_PATH/peer.pub)
WG_PEER_PSK_PATH=$CONFIG_PATH/peer.psk
WG_PEER_KEEPALIVE=60
WG_PEER_ENDPOINT_IP=2xxx:xxxx:a300:5054:ff:fea9:xxxxx
WG_PEER_ENDPOINT_PORT=$WG_PORT
WG_PEER_ENDPOINT=$WG_PEER_ENDPOINT_IP:$WG_PEER_ENDPOINT_PORT
## 対向IPアドレス
WG_PEER_IPv4="${WG_LOCAL_IPv4%.*}.1/24"
WG_PEER_IPv6="${WG_LOCAL_IPv6%:*}:1/64"
## wg0ネットワークアドレス
WG_PEER_IPv4_NET_ADDR=$WG_LOCAL_v4_NETADDR
WG_PEER_IPv6_NET_ADDR=$WG_LOCAL_v6_NETADDR
## 転送をするリモートネットワーク
REMOTE_NETWORK=( 192.168.2.0/24 192.168.100.0/24 ::/0 )
##
ENABLE_ROUTING=1


##
main $@

参考資料

https://qiita.com/fluo10/items/78e91884042645b08fb9

OpenWrt の Luci (web)で wireguard を作る

OpenWrt の Luci (web)で wireguard を作る

WireGuardは、サービスではなくインタフェースから作る。

インタフェースを追加したら、Peerを追加する。

秘密鍵と共有鍵の一覧は、ステータスにでてくる。

注意点

wireguard の設定を save & apply して適用しあとに、

ネットワークからインターフェース再起動が必要です。

2023-11-02 追記

OpenWrt 22.03.5 r20134で Wireguard を設定してもクライアントとして動作しない

Endpointを設定しても、通信が開始されない。

Persistent Keep Alive を設定する通信が開始された。Persistent Keep AliveがないときはEndpointへ接続へ行かないのはなぜだろう。

2023-11-02 追記

wireguardを入れたインターフェースをファイアウォール・ゾーン(グループ)に入れた場合、wireguardで割り当てるIPだけが対象かと思ってたが、wireguardの接続リクエストのパケットもゾーン対象に入ってしまう。そのためゾーン設定するには、wireguardの「接続確立」ができるようなAccept設定が必要だった。これは不具合だと思うので修正してほしい。。。

windows のIPアドレスの確認 ・変更( netshと ip の比較 )

windowsIPアドレスの確認 ( netsh )

Windowsには netsh コマンドがあって、IPアドレス関連の各種設定ができる。

netsh の使い方をまとめておく

コマンド linux windows
IPアドレス確認 ip addr show eth0 netsh interface ipv4 show addresses eth0
v6アドレス確認 ip -6 addr show eth0 netsh interface ipv6 show addresses eth0
IP追加 ip addr add 192.168.10.2/24 dev eth1 netsh interface ip add address eth01 192.168.10.2/24
ip 削除 ip addr del 192.168.10.2 dev eth1 netsh interface delete address 'eth0' 192.168.10.2
ルーティング表 ip  ip route netsh interface ipv4 show route
v6ルーティング表 ip -6 ip route netsh interface ipv6 show route
route 追加 ip route add 192.168.1.0/24 via 192.168.1.1 netsh interface add route 192.168.1.0/24 "eth0" 192.168.1.1
route 削除 ip route delete 192.168.1.0/24 via 192.168.1.1 netsh interface delete route 192.168.1.0/24 "eth0" 192.168.1.1

windows 固有

ネットワークデバイス(インタフェース)の名前を変える。

netsh interface set interface name = "ローカルエリア接続 2" newname = "eth2"

デフォルトの空白の入った長い名前は、コマンドから扱いづらいので、私は分かりやすいシンプルな名前にしている。

ネットワーク・デバイス(インタフェース)の一覧を取得

netsh interface ipv4 show interface 

ipv4 / ipv6 を使い分ける。

netsh interface show interface 
netsh interface ipv4 show interface 
netsh interface ipv6 show interface 

省略 / ipv4 / ipv6 でそれぞれに、動作がが違うので注意。

サンプル v6

IPv6アドレスを指定する。

netsh interface ipv6 add address fd03:ac7f:3852:67bb::3

v6デフォルトGWを設定する。

netsh interface ipv6 add route  ::/0  eth01  fd03:ac7f:3852:67bb::1

v6 でルーティングテーブルに追加する。

netsh interface ipv6 add route  2001:a253:8383:a300::/64 eth01  fd03:ac7f:3852:67bb::1 

省略形・省略しない場合。

ここまで書いた書式は省略形になっている。

次の2つは同じコマンドになる。引数の書き方の流儀が違うだけ。

これは

netsh interface ipv6 add address eth01 fd03:ac7f:3852:67bb::3/64

これと同じ。

netsh interface ipv6 add address interface=eth01 address=fd03:ac7f:3852:67bb::2/64

サンプルv4

v4 の場合は次のようになっている。

netsh interface ipv4 add address eth01 192.168.5.2/24

v6ルーティングテーブルに追加する。(デフォルトGWを設定する。)

netsh interface ipv4 add route 0.0.0.0/0  eth01 192.168.5.1
netsh interface ipv4 add route 10.100.100.0/24 vpn01 10.100.100.1

Joplin でプラグインのインストール

joplin のプラグインをインストールするには、

設定からプラグインのインストールができる。次のような画面からインストールできる。

f:id:takuya_1st:20210224031719p:plain

プラグインの一覧を出すには

検索ボックスに「スペース」を入れてエンターすると全部出てくる。これは気づかない。

f:id:takuya_1st:20210224031737p:plain

Joplin を Nextcloud と連携する

joplin とは?

Evernoteのように、メモを同期するやつ。Markdownで書けるアプリ。

似たようなものとして、Boostnote や Quiver が挙げられる。

特徴として、Self-hosted可能であり、オープンソース(MITライセンス)である。

同期先に、ローカルファイルや WebDAV や docker Joplin Server や S3 Bucket などが使えて、ストレージをSelf-hosted可能なところである。ローカルファイルの保存先をGoogleDriveへ同期フォルダに指定するのが一般的だろうか。

Joplin を Nextcloud と連携する

Joplin は NextCloud のWebDAVと連携して、NextCloudの指定フォルダにデータを書き込むことができる。

わたしは脱Google依存したいので、NextCloud を使うことにした。

joplin-nextcloud のアプリの有効化

Nextcloud の管理画面から joolin のアプリを有効にする。

f:id:takuya_1st:20210224030750p:plain 2021-01-16 現在の最新版では、NextCloudのAppStoreでエラーが出ているのでマニュアルでインストールが必要ですね。Issue には上がってるので、そのうち解決されると思います。

手動インストール

手動インストールは、NextCloudのアプリの手動インストールに従う。

  • nextcloud/apps フォルダに移動
  • app を wget で取得
  • app を unarchive する
  • app を有効にする
cd PATH/TO/NextCloud
cd apps
wget https://github.com/laurent22/joplin-nextcloud/releases/download/v0.0.25/joplin-0.0.25.tar.gz
unar joplin-0.0.25.tar.gz
rm joplin-0.0.25.tar.gz
cd ..
sudo -u www-data php occ app:enable joplin

joplin のアドレスを取得する。

NextCloudの「ファイル」から、Joplinを保存したいディレクトリを作る。

私は、 /Documents/joplin のフォルダを作成した。

f:id:takuya_1st:20210224030901p:plain

このフォルダを含めた アドレスを webdav のアドレスとして生成する

https://nextcloud.EXAMPLE.COM/remote.php/webdav/Documents/joplin

末尾に、NextCloud上でのルートからのディレクトリを入れるのがポイント

joplin クライアントに設定する。

joplin の 設定画面を開いて NextCloud を指定する。

f:id:takuya_1st:20210224030941p:plain 先程のWebDAVのURLと、ログインユーザー名・パスワードを入力して接続テストする。

f:id:takuya_1st:20210224031056p:plain

接続テストができればOK

iOSAndroid も同様に

スマートフォンのJoplinも同様にすることで同期ができるようになる。

快適マークダウンメモ生活。

スクショも含めた、マークダウンを手軽に書けるようになり、とても快適である。

惜しいところ

ゴミ箱機能がないところがとても惜しい。

Evernoteのような暗号化テキストを扱えないのがつらい。

markdown の表を扱いづらいのがちょっとめんどくさい。

Electron なアプリにありがちな日本語入力がおかしくなる現象は仕方ないとしても残念。

はてなブログにインポート機能がないので画像をうまくいインポートできない。

添付ファイルは、resource/ にまとめて保存されるので、ノート数が巨大になると多分動かない。enex はその点やっぱり良く出来てるフォーマットだったと思う。Evernoteはenexを捨てようとしてるっぽいけど。

課題は多いけど無料で、概ね良好に使える。

Windows版のEvernoteが酷くて、まともにメモを取れないので、本当に助かる。

WindowsでAlt-F4が指がつりそうになるのでWin-wに割り当ててmacOSっぽくしたら革命が起きた。

ALT-F4を Win-w に割り当てた。

PowerToysのキーリマッピングで、Win-WをAlt-F4に割り当てたら、すごく便利だった。

f:id:takuya_1st:20210223193728p:plain

macOSの command-W の便利さ

macOSのCMD-Wが便利すぎるので、Windowsでもやろうかとおもってやったら便利だった。

Alt-F4って押しにくいので、このキーリマッピングはすごく気に入った。

ほかにもmacから移植した

macOSのキー操作ってすごく便利で、なれたら必須と言えるレベルなので、Windowsにも移植しよう

Home/Endが押しにくい

Home/Endは押しにくいし、INSERTキーを間違えて押すトラブルがあってつらい。

かといて、Ctrl-A/EはWindowでは重要なショートカットなので、リマッピングはつらい。

そこで、よく考えた。一番良く使うのは行頭まで選択、行末まで選択じゃないか。そこでShift-Home/Shift-EndをShift-Ctrl-E/Aに移植した。便利。

DELETEが押しにくい

DELETEも押し間違える定番で苦しい。ノートPCのDELETEなど勇者スキルでも持ってないと正確に押せないじゃないか。

そこで Win-Backspaceにした。Deleteキーは退場してもらった。明示的にWinキーを押さないとDELETEできないの。macOSの誤発動を防止の良さを取り込むことができた。幸せだ。

いままで、Alt-F4が押しにくいので Win-spaceでメニューをだし、↑おしてEnterってした。

いままでは、Windowメニューを使ってた。 f:id:takuya_1st:20210223194120p:plain

LXC のストレージサイズ変更(拡張・縮小)する。

LXC のストレージサイズが足りない。

LXC のストレージのりサイズをなんとかしたいです。容量不足になって困らないようにしたい。調べました。

lxdのリサイズはストレージのフォーマットに従う。

バックエンドのストレージにbtrfs を使っていたら btrfs の手法。LVMならLVMを使う。

今回は、btrfs をリサイズして、縮小(shrink)と拡張(expand)を試す。

lxd のbtrfsを拡大する場合

全体の流れはこんな感じになります。

lxc storage list
lxc storage info bt01
truncate -s +10G /var/snap/lxd/common/lxd/disks/bt01.img
losetup -c /dev/loop6
mount /dev/loop6 /mnt
btrfs filesystem resize max /mnt
btrfs filesystem show
lxc storage list
lxc storage info bt01

lxd のストレージ一覧

ストレージ一覧から、拡大したいストレージを調べます。

takuya@lxd-host:~$ lxc storage list
+---------+-------------+--------+--------------------------------------------+---------+
|  NAME   | DESCRIPTION | DRIVER |                   SOURCE                   | USED BY |
+---------+-------------+--------+--------------------------------------------+---------+
| bt01    |             | btrfs  | /var/snap/lxd/common/lxd/disks/bt01.img    | 3       |
+---------+-------------+--------+--------------------------------------------+---------+
| bt02    |             | btrfs  | /var/snap/lxd/common/lxd/disks/bt02.img    | 0       |
+---------+-------------+--------+--------------------------------------------+---------+
| default |             | zfs    | /var/snap/lxd/common/lxd/disks/default.img | 13      |
+---------+-------------+--------+--------------------------------------------+---------+

このコマンドで、ストレージのファイル名とフォーマットが確認できる。

今回は、btrfs のbt01 が容量が足りないので、容量を割り当てる。

念の為に、増加前の容量を確認しておく。

lxc storage info bt01

bt01 / btrfs 増加させる。

bt01 は btrfs で作成しているので、btrfs のやり方に従う。

ファイルを増量させる

割当ファイルのサイズをtruncate で増加させる。

takuya@lxd-host:~$ truncate -s +70G /var/snap/lxd/common/lxd/disks/bt01.img

loop デバイスを確認

takuya@lxd-host:~$ losetup | grep bt
/dev/loop6          0      0         1  0 /var/snap/lxd/common/lxd/disks/bt01.img         0     512
/dev/loop7          0      0         1  0 /var/snap/lxd/common/lxd/disks/bt02.img         0     512

lxd のストレージはループデバイスにブロックデバイス接続されているので、ループデバイスのファイル名(番号)を確認。

loopデバイスにファイルの増量を検知させる。

losetup -c で loop デバイスを更新し、ファイルの容量を反映する。

takuya@lxd-host:~$ losetup -c /dev/loop6

(2022-05-14) 追記

追加容量反映はlxc stop でコンテナ停止が必要。ストレージを利用しているコンテナが起動していると容量反映がうまくいかないことがある。停止なし容量追加でうまくいくこともあるのだが・・・

マウント

ループデバイスを、ファイルシステムにマウント

takuya@lxd-host:~$ mount /dev/loop6 /mnt

btrfs の resize が、マウントポイントへ行われるらしいのでマウントする。

btrfs を容量変更(最大に)

btrfs filesystem コマンドを使ってデバイス空き容量の最大値までファイルシステムを拡張する。

takuya@lxd-host:~$ btrfs filesystem resize max /mnt
Resize 'mnt' of 'max'
もしマウントしてなかったら

マウントをせずに、直接ブロックデバイスへ操作しようとしてもエラーになった。ちょっと不思議。マウントが必要な理由はよくわからない。

losetup で デバイスファイルをloop デバイスから確認して、そのデバイスを mount して、いったん /mnt に持ってくる。 その上でないと、 btrfs の filesystem resize が動かない。

takuya@lxd-host:~$ btrfs filesystem resize max /dev/loop6
ERROR: resize works on mounted filesystems and accepts only
directories as argument. Passing file containing a btrfs image
would resize the underlying filesystem instead of the image.

リサイズ(拡張)結果を確認する。

btrfsのファイルシステムが拡張されたことを確認する。

takuya@lxd-host:~$ btrfs filesystem show
Label: 'bt01'  uuid: 6d9a8707-3766-4561-99c5
        Total devices 1 FS bytes used 59.97GiB
        devid    1 size 170.00GiB used 95.13GiB path /dev/loop6

Label: 'bt02'  uuid: 7c4aca0a-e942-4fa5-abef
        Total devices 1 FS bytes used 384.00KiB
        devid    1 size 50.00GiB used 2.02GiB path /dev/loop7

LXD/lxc で認識されたことを確認する。

lxc storgate info を使って、btrfsのファイルシステム拡張がlxd側で確認できる。

takuya@lxd-host:~$ lxc storage info bt01
info:
  description: ""
  driver: btrfs
  name: bt01
  space used: 65.24GB
  total space: 171.80GB
used by:
  images:
  - afcfbe9e40d27eb91cfbabf240823186d
  instances:
  - lxd-guest
  - vps

lxd の仮想マシン内部から確認する。

lxdのコンテナから、容量が増えていることを確認する。

root@lxd-guest:/var/www/virtualhosts# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop6      170G   66G  103G  40% /

縮小するときは

縮小はほぼ同じ。truncate で負数指定が変わるくらい。

truncate -10G /path/to/storgage

(2022-05-14) 拡張は、truncate -> btrfs resize の順、縮小はbtrfs resize -> truncate の順。

Snap版とapt版の違い

snap 版は /var/snap/lxd/common/lxd/disks

apt 版は /var/lib/lxd/disks/

とファイルの格納場所が異なる。

まとめ

lxd でのストレージはbtrfs では、手軽にサイズ変更できる。

ゲスト(コンテナ)の終了しなくても良かった。強い。

truncate コマンド便利。

参考資料

https://linuxcontainers.org/lxd/docs/master/storage#btrfs
https://discuss.linuxcontainers.org/t/snap-lxd-resize-default-btrfs-storage-pool/2587