それマグで!

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

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

gitlab への git push やgit lfs の送信で413 エラーになった。

gitlab を使ってて謎だったエラー

LFS: Client error: https://gitlab.example.com/takuya/sample.git/gitlab-lfs/objects/5f32fd160/10 from HTTP 413

なんか解決しなくて、しばらく放置してたけど、原因に気づいた、これgitlabじゃないnginx だ。

nginx 側で送信されるファイルサイズを制限

 ## gitlab specified location
  location / {
    client_max_body_size 50M;

そういえば、50Mになっていた。LFSで1GB のファイルとか送れないわけですよ。

なるほどね。

    client_max_body_size 1000M;

とかにして解決。

gitlab の構成的に、nginx → gitlab内蔵nginx → gitlab-workhorse(rails) なので、わかりにくいだろうな。うちは内蔵ngix 切ってるから気づけた。

そういえば、apache+php + jquery file upload とかでも昔ハマりました。nginx が多段で入ってるのすっかり忘れてた。

参考資料

https://github.com/go-gitea/gitea/issues/2930

bash の* ( アスタリスクのワイルドカード)でドットファイル(隠しファイル)を一時的にマッチさせる

TL;DR

shopt -s dotglob
shopt -u dotglob

ドットファイルも含めたい時がある。

for i in $ (ls -a) はめんどくさいんだよなぁ

ホームディレクトリで、*でワイルドカードマッチさせても一致しないのが不便。 ls -al しているときは気にならないのだけど、一括して容量を取得したり、ファイルをまとめて移動させたいときなど、ワイルドカードドットファイル(隠しファイル)が指定されなくて困る時がある。

ホームフォルダ内の容量を見たいとき。

takuya@takuya$ du -cksh *
9.0M    Documents
17M Library
20K PhpStorm2018.3-settings.zip
2.5M    iodine
28M total

あああ、ドットファイル無いよ。

これで解決。

shopt -s dotglob

shopt のdotglob を指定すれば、dotfile も含めて コマンドの引数に展開される。

takuya@takuya$ du -cksh *
4.0K    .auth_keys
4.0K    .bash_aliases
4.0K    .bash_completion
48K .bash_completion.d
4.0K    .bash_profile
8.0K    .bashrc
4.0K    .bashrc.cygwin
4.0K    .sqliterc
36K .ssh
8.0K    .tidy.conf
32K .vim
20K .viminfo
12K .vimrc
9.0M    Documents
17M Library
2.5M    iodine
136M    total
takuya@takuya$ shopt -u dotglob

やったね。

もとに戻すなら

かと言って、いつでもdotfiles が含めコマンドの引数に、ワイルドカードが展開されるのは不便なので、一時的にオンにしたらもとに戻したい。

shopt -u dotglob # 設定をオフにする

現在の設定を確認する。

あれ?いま展開するんだっけ?しないんだっけ?設定を見るには。

takuya@$ shopt -p dotglob
shopt -u dotglob

これで設定ができる。

使い方の例

設定を見ると、設定がコマンドとして機能するので、これを利用して、次のように活用できる。

dotglob_last_state=$(shopt -p dotglob)
for i in * ; do
  echo $i;
done
$(dotglob_last_state)

トグルできるコマンドを作ってもいいけど、そこまでするほどでもないと思う。

その他の解決方法

find や ls と組み合わせで出来なくもないけど、すこし煩雑な気がする。半角スペースが混じったファイル名やフォルダ名のときにうまくいかない。(IFSを指定すればうまくいくけど)

find -maxdepth 1 -exec  echo {}\;
for i in $( ls -a ) ; do echo $i; done

shopt で設定できるその他のglob 関連

ワイルドカード関連の自動展開や補完の関連がshopt で設定できるので合わせて覚えておきたい。

  • dotglob
  • extglob
  • globstar
  • nocaseglob
  • nullglob
  • direxpand

関連資料

http://takuya-1st.hatenablog.jp/entry/2016/04/05/025553

参考資料

https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html

ssh の秘密鍵から公開鍵を復元(再生成)する方法

ssh の公開鍵を再度作成する。

うっかり、公開鍵を消しちゃったときに、秘密鍵から公開鍵を作成する。

ssh-keygen -y  -f ~/.ssh/id_rsa  

普通はこういうことは起きないけど、今回は、.ssh のフォルダをちょっと触っててやらかした。

ファイルに上書きするときはこれ。

ssh-keygen -y  -f ~/.ssh/id_rsa  > id_rsa.pub

すでに登録済みの公開鍵から復元する。

公開鍵なので、どこかにコピーして公開しているだろうし、そこから取り出してもいいですね。

例えば、github に登録してあったら、 curl https://github.com/$USERNAME.keys で取り出せます。

また、別のサーバーにssh でログインできるのであれば、 cat ~/.ssh/authorized_keys で取り出せます。

公開鍵は「公開」してください。

公開鍵は、公開して意味のあるものです。

秘密鍵から公開鍵を導出したら、公開してください。秘匿しても意味がありません。

公開鍵を、パスワードzip送信する??

世の中すごいな、俺が考えた最強セキュリティがワークフローとして成立するんだね。

公開鍵は、公開しているものであるし、ソレが本人の公開鍵であるかどうかは認証局(CA)の署名を受けるものであるし。

公開しても大丈夫・紛失しても大丈夫。

秘密鍵を現順に管理していれば、再生成(再計算)できます。

カジュアルに紛失しても問題ないのです。

2021-07-04

記述を見直し。

pipenvを使う。pyenv+venvもいいけど、いまどきな'pipenv' で環境構築に使って使い勝手を調べてみた.

目次

python のパッケージ周りの進化(?)

python はパッケージ管理がガラッと変わることが多い。

  • setup.py
  • pip
  • pyenv
  • virtualenv
  • direnv
  • requirements.txt
  • pipenv ← now

そういえば、古くは - egg / easy_install とかありましたね。 機能追加じゃなくて、以前の機能をつかって新しいコマンドとして作られるんだけど、個人的には、同じコマンドが進化してくれればいいのにと思ったりする。

pipenv を一言でいうと

今どきな「パッケージ管理」に対応してるのが pipevn コマンドらしい。

これを使うと。

他言語のパッケージ管理に使い勝手が近くなると思われる。

  • php composer
  • ruby bundler
  • npm / yarn

この的な、プロジェクト単位のパッケージ管理と同等になるんですね。アップデートとかも含めて"pipenv"で事足りる様になるようだ。だとしたらすごく便利だよね。

pipenv を使うことで venv や pyenv を併せたようなことが できるようになって便利だよね。

すぐわかるpipenvの使い方。

pip install pipenv 
mkdir myProjcet
cd myProjcet
pipenv install 

pipenv についてはこれ読むとわかる。

この記事が詳しい。

Pythonのパッケージ周りのベストプラクティスを理解する - エムスリーテックブログ

requirements.txt

次に、インストールしたパッケージ群を、正確にもう一度インストールし直す方法が問題になりました。

venv (virtualenv)

さて、パッケージをインストールできるようになりましたが、 別のプロジェクトで使うパッケージが混ざってしまう問題が起きました。

pyenv

次に、複数のPython自体をビルドするのが大変という問題が起きました。

pipenvその2

次に開発環境を作る手順が面倒という問題が起きました。

というわけで、requirements.txt の問題点とpyenvも問題点を片付けたのがpipenv という位置づけのようですね。

pipenvを使ってみる。

まず、pipenv コマンドをインストールします。

コマンドは、グローバル環境で使うので

pyenv な globalなpipでインストール

pip install pipenv

プロジェクト単位のpython環境のフォルダを作るためのコマンドを自分のシステム環境に導入するので、global 環境に用意します。

pipenv 環境を作る

最初にプロジェクトのディレクトリを作る

mkdir sample 
cd sample

pipenv インストール環境の初期化

プロジェクトのディレクトリ内でpipenv install をすると環境が作られる。

pipenv install 

もし、python のバージョンを指定したいときは、次のようにする。

pipenv install --python=3.7

Pipfile と .lock が作られる。

takuya@sample$ ll
total 12K
-rw-r--r-- 1 takuya staff 138 2019-04-14 18:35 Pipfile
-rw-r--r-- 1 takuya staff 453 2019-04-14 18:35 Pipfile.lock

venv 環境に入る

pipenv で準備は終わってるので

よくある、venv 環境を使うパターン

$ pipenv shell 
(sample) $ 
(sample) $  deactivate
$

直接 activate を source することでも可能。

source  $(pipenv --venv)/bin/activate

venv 環境を使う2

pipenv shell でもいいんだけど、pyenv 的な使い方もできる

takuya@sample $ pipenv run python -V
Python 3.7.2

プロジェクトでpipを使いたいときは

takuya@dojin$ pipenv run pip -V
pip 19.0.3 from /Users/takuya/Desktop/sample/.venv/lib/python3.7/site-packages/pip (python 3.7)

いい感じにvenv を確保してくれてるのがわかる。

パッケージのインストールとアンインストール

pipenv install requests
pipenv uninstall requests

ただ、これをやっても、プロジェクトのフォルダにファイルがコピーされて生成されるわけではなかった。

どこに環境がインストされたか詳細を見るには

pipenv install requests --verbose

ここを見る限り、/Users/takuya/.local/share/virtualenvs/sample-8HuA3Lk0/bin/pip にvenv が作られていた。

具体的にvenv がどこに作られているのか知りたいときは、次のようにコマンドを叩けばいいことが解る

pipenv --venv

とすれば、venv の場所が表示されます。

開発用パッケージのインストール

pipenv install --dev ipython

--dev をつけるのはよく見るパターンですね。

npm run 的なアレ

pipenvでもnpm run 的なことが出来る。

Pipfile に scripts を書けば、npm run 的なアレができる。

[scripts]
echo = 'echo Hello world'

実行

takuya@sample $ pipenv run echo
Hello world

手作業でpipenv は編集しなくていい。pipenv install

ついつい、 pip install を叩きそうになるのを我慢。

pipenv install speedtest-cli

これでPipfile が更新されます。

github でバージョン管理するときに、Pipfileを対象にして環境をデプロイ先で再現するときに大事。

プロジェクト内にvenv 環境を作りたいんだけど

npm の node_module や composer vendor/ のようにしたいときは、

export PIPENV_VENV_IN_PROJECT=1
pipenv 

面倒なときは次のようにalias か?

alias pipenv='PIPENV_VENV_IN_PROJECT=1 pipenv'

alias で十分ですね。

$ alias pipenv='PIPENV_VENV_IN_PROJECT=1 pipenv'
$ pipenv --venv

/Users/takuya/Desktop/sample/.venv

PIPENV_VENV_IN_PROJECTの注意(2019-08-21)追加

/home/takuya/Pipfile のようにすでに上位ディレクトリにPIpfile があると、そっちが優先されてディレクトリ単位に作られないので注意が必要

ll /home/takuya/Pipfile
cd /home/takuya/myproject/
pipenv install 

Pipfile が上位ディレクトリに存在すると、venv 環境下になるので、うっかり $HOME などにPipfile を作らないように注意すること。

うっかり pipenv しちゃったときは、即座に消しておかないと混乱します。

pipenv のシェル補完がしたい

bash completion が欲しい人は

これを書くだけ。

eval "$(pipenv --completion)"

ただし、実行時間に注意(i5 Macbook 2018 で 500ms ) 。 bashrc に書くとシェル起動がすこし遅くなるので注意。

git clone した python プロジェクトをpipenv する。

git clone した プロジェクトがpython プロジェクトで pip インストールが必要な場合。

pipenv を使うと次のようになります。

git clone $URL
cd $procject
export PIPENV_VENV_IN_PROJECT=1
pipenv install 
pipenv run pip -r requirements.txt

export PIPENV_VENV_IN_PROJECT=1 はお好みで。

追記

PIL をなんとなく、pipenvでインストールしてエラ−になった。 よく考えたら、PILはpypthon3 はもう無いのに。 pipenv.exceptions.ResolutionFailure が出まくる。

pipenv.exceptions.ResolutionFailure
ERROR: ERROR: Could not find a version that matches pil

このあと、pipenv install がすべてエラーになってしまった。macos など環境依存でライブラリが足りずにインストールに失敗したあと、lock ファイルが汚くなることがあるようです。

こういうときは、とりあえずlock ファイル消して、Pipfile を書き直したらきれいになるようです。

インストール失敗しても失敗したpipfile のママ残りました。インストール成功してから pipfile を更新してほしいですよね。

2019-10-29

Googleのpipenv で検索にヒットしないので、ほんとうにGoogle検索どうなってんだろう

2019/10/30更新

pipenv で google の検索インデックスに入らないので、記事を一部書き直した。

2019-12-17

PIPENV_VENV_IN_PROJECT でまた混乱したので、追記・改変

参考資料

必読 → https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#configuration-with-environment-variables

公式→ https://pipenv.readthedocs.io/en/latest/

日本語→ https://pipenv-ja.readthedocs.io/ja/translate-ja/install.html

Pipenvを使ったPython開発まとめ - Qiita

https://github.com/pypa/pipenv/issues/259

秘密の質問の回答ジェネレータを、pythonでぱぱっと

TL;DR

ひらがな10文字の秘密の質問の回答を作る。

python -c 'import random; print("".join([ chr(0x3042+random.randint(0,82) ) for i in range(1,10)]))';

秘密の質問って効果あるの?

秘密の質問はないよりはあったほうがマシとかいうレベルで無くても問題ないと思う。

秘密の質問は「ひらがなのみ」とかアホらしいですね。

憶測可能で非ランダムなら「ひみつの質問」ってセキュリティ的には全く意味ないですよね。

ひらがな1文字でOKです。

f:id:takuya_1st:20190414154233p:plain

そりゃそうだ、「あなたの出身地は」という質問に「三重県 津市」のような1文字地名を1文字が許可されなときは、どう答えるのだ。

秘密の質問とかいう謎仕様に頭を悩ませる。

秘密の質問って効果あるの?→無いです。

全角ひらがなだと83文字です。

秘密の質問は8文字もありません。1文字でも5文字でも通ってしまう。 ASCIIで記号+小文字+大文字+数字=約80字が8文字以上組み合わされた通常パスワードより強度が低い。

わざわざ強度の低い文字を、しかも「現実に存在する単語」で入れさせるなんてアホらしいですね。 こういう似非セキュリティは無くなってしかるべきです。

辞書の単語をパスワードに利用するなと言うのは鉄則ですよね。

出身地の小学校の名前が十分な強度を得られるほどランダム性があるわけでもない。

何から何を守るのかも不明確

セキュリティの基本として、「何を誰から守るのか」という視点を失ってほしくないですね。

秘密の質問は誰から何を守るのでしょうか。今回の例は「イオンカード」ですが、明細の「閲覧」権限を保護はそこまで重要な情報なんでしょうか。

そもそも正直に答える必要など無い。

そもそも正直に答える必要など無い。ランダムなひらがな文字列で構わない。

というわけで、自動的に生成してしまいましょう。

f:id:takuya_1st:20190414154658p:plain

python -c 'import random; print("".join([ chr(0x3042+random.randint(0,82) ) for i in range(1,10)]))'

そもそも、ひらがなは「あーん」なのか?

ひらがなをprint してみて思うのだけど、「あーん」がひらがなでいいのだろうか。

>>> [ chr(0x3042+i) for i in range(0,190) ]
['あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か', 'が', 'き', 'ぎ', 'く', 'ぐ', 'け', 'げ', 'こ', 'ご', 'さ', 'ざ', 'し', 'じ', 'す', 'ず', 'せ', 'ぜ', 'そ',
 'ぞ', 'た', 'だ', 'ち', 'ぢ', 'っ', 'つ', 'づ', 'て', 'で', 'と', 'ど', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ば', 'ぱ', 'ひ', 'び', 'ぴ', 'ふ', 'ぶ', 'ぷ', 'へ', 'べ', 
'ぺ', 'ほ', 'ぼ', 'ぽ', 'ま', 'み', 'む', 'め', 'も', 'ゃ', 'や', 'ゅ', 'ゆ', 'ょ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ', 'ゎ', 'わ', 'ゐ', 'ゑ', 'を', 'ん', 'ゔ', 'ゕ',
 'ゖ', '\u3097', '\u3098', '゙', '゚', '゛', '゜', 'ゝ', 'ゞ', 'ゟ', '゠', 'ァ', 'ア', 'ィ', 'イ', 'ゥ', 'ウ', 'ェ', 'エ', 'ォ', 'オ', 'カ', 'ガ', 'キ', 'ギ', 'ク', 'グ',
 'ケ', 'ゲ', 'コ', 'ゴ', 'サ', 'ザ', 'シ', 'ジ', 'ス', 'ズ', 'セ', 'ゼ', 'ソ', 'ゾ', 'タ', 'ダ', 'チ', 'ヂ', 'ッ', 'ツ', 'ヅ', 'テ', 'デ', 'ト', 'ド', 'ナ', 'ニ', 'ヌ', 
'ネ', 'ノ', 'ハ', 'バ', 'パ', 'ヒ', 'ビ', 'ピ', 'フ', 'ブ', 'プ', 'ヘ', 'ベ', 'ペ', 'ホ', 'ボ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ャ', 'ヤ', 'ュ', 'ユ', 'ョ', 'ヨ', 
'ラ', 'リ', 'ル', 'レ', 'ロ', 'ヮ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン', 'ヴ', 'ヵ', 'ヶ', 'ヷ', 'ヸ', 'ヹ', 'ヺ', '・', 'ー', 'ヽ', 'ヾ', 'ヿ']

あーんだと次の3文字が欠損する

 'ゔ', 'ゕ', 'ゖ',

他にも、ダッシューは?波線〜は?

長音、ダッシュとハイフンの違いはどうするんだろうか。

>>> hex(ord('ー'))
'0x30fc'
>>> hex(ord('―'))
'0x2015'
>>> hex(ord('−'))
'0x2212'

こんなあやふやでフワっとした「秘密の質問」ってもう無くていも問題ないと思うんですよね。

さて、イオンカードの場合を見てみよう。

ああ、やっぱり「あーん」ですね。

f:id:takuya_1st:20190414153607p:plain

元になってる日本語判別はなんだろう jquery の野良プラグインですね。お疲れ様です。

f:id:takuya_1st:20190414153803p:plain

正規表現エンジンで  /あ-んー\s/ ですか。それならブラウザのinput:invalidate のrequired pattern= の組み合わせで十分なんじゃないですかね。。。

判定条件はこれだった。

"hiragana": {
                    "regex": /^[ぁ-んー\s]+$/,
                    "alertText": "* ひらがなのみで入力してください。"
                },

うーん・・・これでいいのか?

しかも、この判定だと、半角スペースを「ひらがな」として通してしまいませんか?

こうなってくると、他の判定正規表現、たとえばemail アドレスの判定も疑わしいですね。

結論:自動生成使用。

あーん だと抜ける文字がある。ハイフン長音の違いでユーザーに不親切になる。このjQuery野良プラグインは半角スペースを通してしまう。

秘密の質問はやっぱりいらない。

自動生成で十分だ。

追記:秘密の質問のパターン甘い

こんな、適当な秘密の質問でも通ってしまう

f:id:takuya_1st:20190414153658p:plain

ほんと、なんのためにあるんですかね。

追記:しかも平文で保存される。

最大20文字とか制限があるんでオカシイなとおもったら、やっぱり平文保存だった。

最大文字数が制限されいるとき、殆どの場合で「データベースのカラム長」だと思われる。つまり保存は平文である。

変更画面でもとの秘密の質問が表示される。うーんここは平文で保存する必要があるのかな?ハッシュ化してないんだね。

f:id:takuya_1st:20190414160508p:plain

python で日本語のUnicode のコードポイントから平仮名を連番テーブルを作る

python でA-Zみたいに 「ひらがな」をコードポイントで扱う。

f:id:takuya_1st:20190414152203p:plain

tl;dr

>>> [ chr( i+ 0x3042) for i in range(0,85)]
['あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か', 'が', 'き', 'ぎ', 'く', 'ぐ', 'け', 'げ', 'こ', 'ご', 'さ', 'ざ', 'し', 'じ', 'す', 'ず', 'せ', 'ぜ', 'そ', 'ぞ', 'た', 'だ', 'ち', 'ぢ', 'っ', 'つ', 'づ', 'て', 'で', 'と', 'ど', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ば', 'ぱ', 'ひ', 'び', 'ぴ', 'ふ', 'ぶ', 'ぷ', 'へ', 'べ', 'ぺ', 'ほ', 'ぼ', 'ぽ', 'ま', 'み', 'む', 'め', 'も', 'ゃ', 'や', 'ゅ', 'ゆ', 'ょ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ', 'ゎ', 'わ', 'ゐ', 'ゑ', 'を', 'ん', 'ゔ', 'ゕ', 'ゖ']

解説

chr ( 0x3042 )

これは、以下と同じ

'\u3042'

\u でユニコードにコードポイントであることを示している。

'\u3042'を示したときに、Pythonで内部エンコーディングにデコードされ文字列として格納されている。

文字符号化方式UTF-8/UTF-16エンコードすると、次のようなバイト列になる。

>>> '\u3042'.encode('utf-8')
b'\xe3\x81\x82'
>>> '\u3042'.encode('utf-16')
b'\xff\xfeB0'

ちなみに、内部エンコーディングは次のように確認できる(いまはUTF-8固定かな?たしか)

import sys; sys.getdefaultencoding()

得られたバイト列を、文字列にする

>>> b'\xe3\x81\x82'.decode()
'あ'

ちなみに b'\xxxx' はバイト列であることを示す b です。

UTF-16のバイト列をそのままデコードしてもエラーになります。

>>> b'\xff\xfeB0'.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

内部エンコーディングUTF-8(デフォルト)なので、UTF-16UTF-8としてデコードしようとしてエラーですね。

>>> b'\xff\xfeB0'.decode('utf16')
'あ'

これで、バイト列がUTF-16の符号化として扱われて、デコードされ、Unicodeのコードポイントを得ることが出来て、内部エンコーディング(この場合UTF-8)にデコードされ出力された。

ユニコードのコードポイントを連番で扱う。

あ=0x3042 であることを利用して連番「ひらがな」を作ってみる。

>>> [chr(0x3042+i) for i in range(0,10)]
['あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か']

逆に、「あいうえお」をすべてユニコードのコードポイントにしてみる

>>> [ (ord(i)) for i in  "あいうえお"]
[12354, 12356, 12358, 12360, 12362]

見やすいように16進数 Hexにする

>>> [ hex(ord(i)) for i in  "あいうえお"]
['0x3042', '0x3044', '0x3046', '0x3048', '0x304a']

まとめ

chr でユニコードのコードポイント(数字)から、文字へ

>>> chr( 0x3042 )
'あ'
>>> chr( 0x3042 + 1  )
'ぃ'

ord で、文字を数字(int)へ。hex で16進数表記へ

>>> ord('あ')
12354
>>> hex(ord('あ'))
'0x3042'

補足

ユニコードUnicode)のコードポイントは、文字符号の変換表(数字→文字)であり、utf-8utf-16 はその変換した数字をバイナリとしてどうやって保存するかになる。

ユニコードでは、あ=0x3042 である。これはUTF-8でもUTF-16 でも変わらない。ただし、この0x304 をどうやって0/1に落とし込むかで表現方法は変わる。

$(pyenv init -) が遅いので遅延ロードにした

ターミナルの起動が遅い。

最近、妙にターミナルの起動が遅くて苦痛だなと思って調べたら pyenv 関連だった。

rbenv もそうだったし、pyenv もやはり遅い。 rbenv に関してはrbenv init では諦めて、symlink を使って解決しているが pyenv は別の方法を模索した。

pyenv 関連の起動遅いねん

f:id:takuya_1st:20190414143941p:plain f:id:takuya_1st:20190414144043p:plain f:id:takuya_1st:20190414143856p:plain

ああ、わりと時間かかりすぎ。

## init 系を測定してみる
time { 
  ## rb
  eval "$(rbenv init -)"
  ## py
  eval "$(pyenv init -)"
  eval "$(pip completion --bash)"
  eval "$(pipenv --completion)"
}

シェル起動の処理で4秒超えは、ストレス溜まりそう。

f:id:takuya_1st:20190414151002p:plain

ターミナルの起動を早くしたい。

python は使わないこともあるし、ターミナル自体はもっと早く起動してサクサクと使いたい。

lazyload をする方法が紹介されている

ログインシェルの起動を高速化する lazyenv を作った - Qiita

方針としては

  1. pyenv と同名の function pyenv(){} をbashrcに登録する
  2. pyenv 関数内で、自分自身を消す
  3. 消すときに同時にpyenv をちゃんとロードする
  4. 自分自身のかわりにロードしたpyenv を起動する。

これらの関数をpyenv の初期化に変わって実行すると、bashrc 内部で init が行われないので、bashrcの読み込みが、遅くなることはない。

シェルスクリプトで表すとこんな感じ。

pyenv () {
    unset -f pyenv
    pyenv_load_function
    pyenv "$@"
}

上記の関数は、関数名とロード関数名が同じであれば、抽象化できるので、作ろうと思ったら、すでに作ってる人がいた。

使い方

私は、遅延ロードさせる関数を .bashrc.d/ に配置した。

.bashrc

bashrc.d をロードする。

if [[ -d ~/.bashrc.d/ ]]; then
  for i in ~/.bashrc.d/* ; do source $i; done
fi

以下のファイル名にして、layzyenv を先に読み込まれるように設定。

  • .bashrc.d/00-lazyenv.bash
  • .bashrc.d/pyenv-init.bash

.bashrc.d/00-lazyenv.bash

これは、takezoh/lazyenv から取得した。

.bashrc.d/pyenv-init.bash

## 2019-04-13 takuya
## python 関連の設定をまとめる
## lazyload を使って pip を遅延させる
# これをすることでコマンドを実行するまで補完ができなくなるので
# 初回起動まで、補完が出来なかったりする
# なので、一見すると補完が効かないように見えることがあるので注意
## pyenv init -
## pip completion
## pipenv --completion

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
export PYTHONSTARTUP=~/.pythonrc

_pyenv_init() {
  # python 関連の起動遅いから、ここにまとめる

  # pyenv を使う
  if  ( type "$0" > /dev/null 2>&1  ||  [[ -d  ~/.pyenv  ]] ) && [[ $TERM != screen* ]]; then
    ### pyenv
    eval "$(pyenv init -)"
    eval "$(pip completion --bash)"
    eval "$(pipenv --completion)"
    # cmd_is_exists pyenv-virtualenv && eval "$(pyenv virtualenv-init -)"
  fi
}
eval "$(lazyenv.load _pyenv_init pyenv python pip pipenv )"

screen / tmux の起動時は環境変数を引き継ぐので重複処理はしないようにしてたり。

他の似たようなコマンドはどうしたか

nvm / node

これらに関しては、bashrcで読み込む必要もないし、プロジェクト単位で使うことが前提でなので、bashrc から外した。 その後 nvm はあまり使わないことに気づいたのでnvm 自体を外した。

rbenv /ruby

これらに関しては、私が個人的に結構ruby使うのと、brewruby を使ってることもあり、rbenv 自体を外すことは諦めた。それぞれ固定バージョンへのsymlinkを作成してPATHの優先度で対応した。 rbenv init は使わずに済ませた。

phpenv / php

これらに関しては、プロジェクト単位にbashrc を作ることで対応している。

その他の解決方法。

pyenv 自体は、バージョンとコマンド名を解決するものなので、bash 用に専用の pyenv-virtualenv を作り、symlinkしてバージョンを固定。 シェルではロードして利用し、プロジェクトや環境ではプロジェクト環境ごとに pyenv を毎回ロードして使ってもいいかもしれない。

処理後の時間

1秒未満なら、まぁ許容範囲かな。500ms 切りたいとこではあるが。brew の completion 系がたくさんあるのでそれを外すのは難しいし。諦めた。 f:id:takuya_1st:20190414151325p:plain

2019/05/17 追記

pyenv init を見ていて気づいた。

pyenv init を実行してPATH を見ようと実行して気づいたのですが。

pyenv init 自体は、pyenv の別名関数を定義していて、pyenv は遅延ロード的な動作になっている。

他の処理を取り除いた bash や root の bash で pyenv init - するとすごく早い。

もしかしたらpyenv init が遅い原因は、pyenv ではなく、brew など他のパッケージにあるのかもしれない。

# pyenv init -
export PATH="/var/root/.pyenv/shims:${PATH}"
export PYENV_SHELL=sh
command pyenv rehash 2>/dev/null
pyenv() {
  local command
  command="${1:-}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  activate|deactivate|rehash|shell)
    eval "$(pyenv "sh-$command" "$@")";;
  *)
    command pyenv "$command" "$@";;
  esac
}

参考資料

GitHub - takezoh/lazyenv: lazyenv provides the delayed calling function associated with the specified commands.

ログインシェルの起動を高速化する lazyenv を作った - Qiita

Lazy load nvm for faster shell start - Broken By Me

Certbot を自動的に更新するタイマーを設定する。

certbotapache/nginx を殺される。

通常のCertbotだと、DNSのAレコードとHTTP(s)を使って、ドメインの確認を行う。

しかし、web サーバーを不用意にシャットダウンされるのは面倒でした。あとポート転送とかやってたりするとめんどくさいんだよなぁ。

DNS の認証をTXTレコードで行う。

これは以前やりました  → certbotの更新でCloudflareプラグインを使ってDNSの認証を楽にする - それマグで!

自動的に更新する

WEBサーバーをシャットダウン・再起動を行わずに、DNSのTXTレコードでCertbotによる証明書発行ができるたら、最後は自動化です。

systemd のタイマー機能を使う。

今回は、Cronではなくsystemd のタイマー機能を使って自動実行をしようと思います。

編集するファイル

  • 実行するスクリプトファイル /usr/local/sbin/certbot-renewal.sh
  • サービス /etc/systemd/system/certbot-renewal.service
  • タイマー /etc/systemd/system/certbot-renewal.timer
  • /lib/systemd/system/certbot.timer 既存のsystemd certbot の自動実行ジョブ

実行するジョブとして登録するファイルを準備します。

ジョブとして実行するファイルを準備しました。

複数の証明書があるので、スクリプトファイルにまとめています。

/usr/local/sbin/certbot-renewal.sh

#!/usr/bin/env bash

certbot=/home/takuya/certbot/certbot-test/bin/certbot

## cloudflare の場合
CERT_NAME=example.com-wildcard
$certbot  renew --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflareapi.cfg \
  --cert-name $CERT_NAME


## mydns の場合
CERT_NAME=example.com-mydns
mydns=/usr/local/lib/mydns/DirectEdit-master
cmd="$certbot renew --manual --preferred-challenges=dns \
  --cert-name $CERT_NAME\
  --manual-auth-hook $mydns/txtregist.php\
  --manual-cleanup-hook $mydns/txtdelete.php\
  --manual-public-ip-logging-ok"

# echo $cmd
$cmd

systemd にタイマーサービスとして登録します。

新しくファイルを準備します。

/etc/systemd/system/certbot-renewal.service

takuya@:~$ cat  /etc/systemd/system/certbot-renewal.service
[Unit]
Description=Certbot Renewal
Type=oneshot

[Service]
ExecStart=/usr/local/sbin/certbot-renewal.sh

systemd にタイマーを準備します

新しくファイルを準備します。

/etc/systemd/system/certbot-renewal.timer

[Unit]
Description=Certbot を定期的に更新する。

[Timer]
OnBootSec=3000
OnUnitActiveSec=1w

[Install]
WantedBy=multi-user.target

もし、apt などでタイマーがすでに入っていたら止めておきます。

わたしの場合、apt でいれた古いcertbot の設定があったので止めました。

sudo systemctl disable certbot.service
sudo systemctl disable certbot.timer

apt でいれた実際のファイルは次のようになっていました。

service側

takuya@sakura:~$ cat /lib/systemd/system/certbot.service
[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew
PrivateTmp=true

timer 側

takuya@sakura:~$ cat /lib/systemd/system/certbot.timer
[Unit]
Description=Run certbot twice daily

[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true

[Install]
WantedBy=timers.target

あとは登録して実行します。

手動で動かすとき。最初に1度実行して確認しておきます。

sudo systemctl start certbot-renewal.timer

タイマーを有効にする。

 sudo systemctl enable certbot-renewal.timer

これで、しばらく証明書の期限切れに悩まされなくていいですね。

まとめ

letsencrypt は 手軽に証明書が作れるけど、手軽さ故に枚数が増えすぎて管理が煩雑だった。

これらをおこなったことで、管理は楽になったし、枕を高くして寝る事ができそうです。

関連資料

Certbot 関連であれこれやった記事たちです。

参考資料

https://stevenwestmoreland.com/2017/11/renewing-certbot-certificates-using-a-systemd-timer.html

プロジェクト単位のnode_module の実行コマンドの格納場所 .bin

プロジェクトでインストールした node_module の実行コマンドはどこ?

npm -g i とかでいちいちグローバルなんて使ってられないし、プロジェクトの実行環境内で完結させたい。DockerとかデプロイCIとか絡んでくると特にその思いが顕著になる。

./node_modules/.bin

公式に資料が書いてある。

Executables§ When in global mode, executables are linked into {prefix}/bin on Unix, or directly into {prefix} on Windows.

When in local mode, executables are linked into ./node_modules/.bin so that they can be made available to scripts run through npm. (For example, so that a test runner will be in the path when you run npm test.)

サンプル

たまたま手元にあったLaravelで npm i した結果で確認したら、次のように用意されている。

コマンドはここから拾えば動きますね。やったね。

takuya@bookmarklets$ ls -l  node_modules/.bin/
total 0
lrwxr-xr-x 1 takuya staff 18 2019-04-02 16:52 acorn -> ../acorn/bin/acorn
lrwxr-xr-x 1 takuya staff 26 2019-04-02 16:52 ansi-html -> ../ansi-html/bin/ansi-html
lrwxr-xr-x 1 takuya staff 19 2019-04-02 16:52 atob -> ../atob/bin/atob.js
lrwxr-xr-x 1 takuya staff 32 2019-04-02 16:52 autoprefixer -> ../autoprefixer/bin/autoprefixer
lrwxr-xr-x 1 takuya staff 22 2019-04-02 16:52 browserslist -> ../browserslist/cli.js
lrwxr-xr-x 1 takuya staff 34 2019-04-02 16:52 cross-env -> ../cross-env/dist/bin/cross-env.js
lrwxr-xr-x 1 takuya staff 40 2019-04-02 16:52 cross-env-shell -> ../cross-env/dist/bin/cross-env-shell.js
lrwxr-xr-x 1 takuya staff 20 2019-04-02 16:52 cssesc -> ../cssesc/bin/cssesc
lrwxr-xr-x 1 takuya staff 15 2019-04-02 16:52 errno -> ../errno/cli.js
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 esparse -> ../esprima/bin/esparse.js
lrwxr-xr-x 1 takuya staff 28 2019-04-02 16:52 esvalidate -> ../esprima/bin/esvalidate.js
lrwxr-xr-x 1 takuya staff 12 2019-04-02 16:52 he -> ../he/bin/he
lrwxr-xr-x 1 takuya staff 23 2019-04-02 16:52 html-minifier -> ../html-minifier/cli.js
lrwxr-xr-x 1 takuya staff 31 2019-04-02 16:52 import-local-fixture -> ../import-local/fixtures/cli.js
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 js-yaml -> ../js-yaml/bin/js-yaml.js
lrwxr-xr-x 1 takuya staff 18 2019-04-02 16:52 jsesc -> ../jsesc/bin/jsesc
lrwxr-xr-x 1 takuya staff 19 2019-04-02 16:52 json5 -> ../json5/lib/cli.js
lrwxr-xr-x 1 takuya staff 22 2019-04-02 16:52 loose-envify -> ../loose-envify/cli.js
lrwxr-xr-x 1 takuya staff 32 2019-04-02 16:52 miller-rabin -> ../miller-rabin/bin/miller-rabin
lrwxr-xr-x 1 takuya staff 14 2019-04-02 16:52 mime -> ../mime/cli.js
lrwxr-xr-x 1 takuya staff 20 2019-04-02 16:52 mkdirp -> ../mkdirp/bin/cmd.js
lrwxr-xr-x 1 takuya staff 23 2019-04-02 16:52 multicast-dns -> ../multicast-dns/cli.js
lrwxr-xr-x 1 takuya staff 36 2019-04-02 16:52 parser -> ../@babel/parser/bin/babel-parser.js
lrwxr-xr-x 1 takuya staff 27 2019-04-02 16:52 prettier -> ../prettier/bin-prettier.js
lrwxr-xr-x 1 takuya staff 30 2019-04-02 16:52 regexp-tree -> ../regexp-tree/bin/regexp-tree
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 regjsparser -> ../regjsparser/bin/parser
lrwxr-xr-x 1 takuya staff 16 2019-04-02 16:52 rimraf -> ../rimraf/bin.js
lrwxr-xr-x 1 takuya staff 15 2019-04-02 16:52 sass -> ../sass/sass.js
lrwxr-xr-x 1 takuya staff 16 2019-04-02 16:52 sha.js -> ../sha.js/bin.js
lrwxr-xr-x 1 takuya staff 16 2019-04-02 16:52 svgo -> ../svgo/bin/svgo
lrwxr-xr-x 1 takuya staff 22 2019-04-02 16:52 terser -> ../terser/bin/uglifyjs
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 uglifyjs -> ../uglify-js/bin/uglifyjs
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 webpack -> ../webpack/bin/webpack.js
lrwxr-xr-x 1 takuya staff 25 2019-04-02 16:52 webpack-cli -> ../webpack-cli/bin/cli.js
lrwxr-xr-x 1 takuya staff 47 2019-04-02 16:52 webpack-dev-server -> ../webpack-dev-server/bin/webpack-dev-server.js
lrwxr-xr-x 1 takuya staff 18 2019-04-02 16:52 which -> ../which/bin/which

参考資料

https://docs.npmjs.com/files/folders#executables

ubuntu /debian のLTSにphp7.1/php7.2/php8.0/php8.1 などを複数バージョン導入する

Ubuntu 16 LTSのPHPが古い

WindowsのWSLでインストールされる Ubuntu 16 LTS のパッケージがLTSらしく、どれもちょっと古くて困るので、php7.1 php7.2 をapt インストールして使いたい。

LTS だとphpが古い

php5.6 のサポートは終わりました。

php7.0 のサポートも終わりました。

php7.1系ももうすぐ終わりそうです。(終わりました。

wordpressに導入するためには、現行のubuntu/DebianのLTSサポートだとちょっと困る。

php のサポートライン

f:id:takuya_1st:20211129124747p:plain

ubuntu LTS や debian 9 / debian LTS

debian はstable は古いが安定してるというか、長期運用が可能といえど追いついてこないのは本当に困るよね。

配布レポジトリを追加する

debian

eval " $( cat /etc/os-release  )"
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
sudo  sh -c "echo 'deb https://packages.sury.org/php/ $VERSION_CODENAME main' > /etc/apt/sources.list.d/php.list"
sudo  apt install apt-transport-https ca-certificates
sudi apt update

ubuntu

add-apt-repository ppa:ondrej/php

インストール

パッケージはお好みで。

sudo apt install php7.1-apcu\
 php7.1-bcmath\
 php7.1-cli\
 php7.1-curl\
 php7.1-fpm\
 php7.1-gd\
 php7.1-intl\
 php7.1-imagick\
 php7.1-mcrypt\
 php7.1-mbstring\
 php7.1-mysql\
 php7.1-pgsql\
 php7.1-sqlite3\
 php7.1-xml\
 php7.1-zip\
 php7.1-phpdbg

php8.1 のインストール

sudo apt install \
  php8.1-apcu \
  php8.1-bcmath \
  php8.1-curl \
  php8.1-cli \
  php8.1-common \
  php8.1-dev \
  php8.1-fpm \
  php8.1-gd \
  php8.1-intl \
  php8.1-imagick \
  php8.1-mbstring \
  php8.1-mcrypt \
  php8.1-mysql \
  php8.1-opcache \
  php8.1-sqlite3 \
  php8.1-xml \
  php8.1-xsl \
  php8.1 \
;

デフォルトのphpを設定する。

いきなり全部あげてしまうと影響もあるし、デフォルトのphpコマンドのバージョンを固定してしまってもいいだろう。

sudo update-alternatives --set php /usr/bin/php8.0

任意のバージョンを使う。

$ php7.0 -i 
$ php7.4 -i 
$ php8.0 -i 
$ php8.1 -i 

phpのモジュールを有効・無効を切り替える

有効化

phpenmod -v 7.0 imap
phpenmod -v 8.0 imap

無効化

phpdismod -v 7.0 imap
phpdismod -v 8.0 imap

任意のPECL/PEARバージョンを入れる。

PEAR/PECL のモジュールは、バージョン共通のパッケージを使う。

apt install php-pear

ビルドして、PECLのパッケージを有効化する。

たとえば、pam のパッケージをビルドして使う場合。

sudo apt install php8.1-dev
wget https://pecl.php.net/get/pam-2.2.3.tgz
tar zxvf pam-2.2.3.tgz
cd pam-2.2.3
phpize8.1
./configure 
make 
sudo make install 
phpenmod -v 8.1 pam
systemctl restart php8.1-fpm apache2

PECLphpはバージョンが上がるとビルドし直しなので、なにかいい方法がないかと思う。 自前でビルドパッケージシステムを作り、aptパッケージとしてapt-lineしか無いかもしれない

設定など

mod_phpphp-fpm を使うわけだが

mod_php の場合、設定すれば行けるのですが、競合とかめんどくさいので apache(prefork)+mod_phpapache(worker)+php-fpm にしたほうが無難かと思われる。もちろんnginx でもいいんだけど、thread や worker を使うならapacheでも対して変わらない。

2021-11-15

stretch / buster / bullseye を直接書いてたので、再利用しやすいように変更

2021-11-29

php8.1が出たので更新。

参考資料

System installation on Debian 9 (Stretch) — Akeneo PIM documentation

https://pierre-schmitz.com/using-opcache-to-speed-up-your-cli-scripts/

https://tecadmin.net/install-php-debian-9-stretch/

DebianのBackportsを使う

debian のバックポートを使う。

パッケージがしっかりメンテされているので安心できる stable だけど、どうしても新しいものが欲しい時がある。

そういうときは、deiban のbackports よりも各ソフトウェアの公式のレポジトリを使えばいい。( node とか vivaldi とか gitlab とか chromeとか)

それでも足りないときに backportsが必要になるので追加する。

最初にほしいパッケージがバックポートにあるかカクニンする。

そもそも、ほしいパッケージがバックポートにあるのかどうか調べておく。これをやらないと徒労に終わる。

ここで検索するか、https://backports.debian.org/Packages/

ここで、一覧を眺めるか。 https://packages.debian.org/stretch-backports/

/etc/apt/sources.list

deb http://deb.debian.org/debian stretch-backports main

apt の source ラインに、1行追記するだけ。

その後、アップデート

sudo apt update 

ほしいパッケージをいれる。

バックポートからインストールするときには、バックポートから入れることを明示する。

sudo apt-get -t stretch-backports install "package"

backports にはあんまりないよ

パッケージがそもそも数多くない。たぶん皆さんが求めるのは sid から導入だったり unstable/testing の最新版だったりしませんかね。

繰り返しになりますが、apt で入れるならソフトウェアの公開元が提供している レポジトリを使ったほうがいい。

それでも、unstable/testing がいいんだってときは。 たぶん、この辺が参考になります。 http://www.j96.org/~yuya/d/20090725.html

参考資料

SpeedTest(スピードテスト)をコマンドからやりたい

皆さんも、おなじみスピードテスト

f:id:takuya_1st:20190328173714p:plain

コマンドからやりたい

ssh 経由でリモートの接続の速度を知りたいですよね。うん。

コマンドインタフェースがあるんです。

https://www.howtoforge.com/tutorial/check-internet-speed-with-speedtest-cli-on-ubuntu/

インストール

pip install speedtest-cli

python パッケージが用意されてるので pip るだけで準備完了。

実際にやってみた

takuya@:~$ speedtest-cli
Retrieving speedtest.net configuration...
Testing from Softbank BB (126.xxx.59.xxx)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by JAIST(ino-lab) (Nomi) [220.91 km]: 22.356 ms
Testing download speed................................................................................
Download: 179.96 Mbit/s
Testing upload speed......................................................................................................
Upload: 197.91 Mbit/s

シェアしたい。

オプションでシェアをつけるとPNGファイルが用意される。はーメッチャ便利。

speedtest-cli --share

実際の例

takuya@:~$ speedtest-cli --share
Retrieving speedtest.net configuration...
Testing from Softbank BB (126.xxx.59.xxx)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by JAIST(ino-lab) (Nomi) [220.91 km]: 17.672 ms
Testing download speed................................................................................
Download: 160.62 Mbit/s
Testing upload speed......................................................................................................
Upload: 215.63 Mbit/s
Share results: http://www.speedtest.net/result/81456xxxxxxxxxxxxxxxxxxx.png

画像はこれ

自動生成された画像はこれ

f:id:takuya_1st:20190328174138p:plain

他にも

サーバー選んだり、ダウン速度だけ調べたり、JSONで結果撮ってきたり。

は~便利これ。

参考資料

MacのWiFiやルーティング設定をターミナルのコマンド networksetup でやる

MacOSWiFi設定をnetworksetup コマンドで行う。

過去にも何度もエントリにしたり、まとめてるんだけど、全然覚えられないし、逆引きとして自分のブログがヒットしないし、ブログ内検索でもマッチしないので、書き直します。 networksetup コマンドはわかりにくいと思う。本当にわかりにくい。

イベントのお手伝いでネットワークの構築に言ったときに設定をアレコレするのに、環境設定から手作業で何度もやり直すのがめんどくさかったし、コマンドと履歴で呼び出せるようにしたい。

無線LANに静的にIPを割り当てる

networksetup -setmanual  Wi-Fi 192.168.2.220 255.255.0.0

有線LAN(wired)に静的なDNS IPアドレスを割り振る

networksetup -setdnsservers 'AX88179 USB 3.0 to Gigabit Ethernet' 1.1.1.1

有線LAN・無線LANをコマンドで処理するときの指定名を調べる。

networksetupで指定するインターフェース名はどこので調べるのか。

最初の例の名前をどうやって取得するのか

takuya@~$ networksetup -listallnetworkservices
An asterisk (*) denotes that a network service is disabled.
PPPoE
Wi-Fi
USB 10/100/1000 LAN
AX88179 USB 3.0 to Gigabit Ethernet
iPad USB
iPhone USB 2
Bluetooth PAN
Thunderboltブリッジ
Thunderbolt ブリッジ

ハードウェアの名前と一致を調べる。

en0 などの古き良きデバイス名とMacでの名前を調べる。

takuya@~$ networksetup -listallhardwareports

Hardware Port: Wi-Fi
Device: en0
Ethernet Address: f0:18:98:11:3e:90
(略

VLAN Configurations
===================

指定したSSIDに接続する

networksetup -setairportnetwork en0 nsc_staff

WiFi の接続を切断し再接続する。

networksetup -setnetworkserviceenabled Wi-Fi off
networksetup -setnetworkserviceenabled Wi-Fi on

切断するとこういう感じ

f:id:takuya_1st:20190328171556p:plain

WiFi の接続を切断し、別のSSIDに接続する

networksetup -setnetworkserviceenabled Wi-Fi off
networksetup -setnetworkserviceenabled Wi-Fi on
networksetup -setairportnetwork en0 nsc_staff

デフォルト・ルートを書き換える

ip route del default
ip route add default via 172.16.1.253

WiFi 電源OFFにして再起動する。

networksetup -setairportpower en0 off
networksetup -setairportpower en0 on

電源OFFと接続切断は混同しやすいので特に注意が必要。iOS的な動きするのが -setnetworkserviceenabled です。 -setairportpower `は電源OFF

電源OFFするとこういう感じ。macOSのメニューからオフを選ぶのと同様の動作になる。

f:id:takuya_1st:20190328171624p:plain

関連記事

ip コマンドは -o オプションを使うと便利すぎてやばい

ip コマンド は -o オプションをつけるとメッチャ見やすい

ip コマンドの ip a の結果はごちゃって見辛くないですか?私は非常に辛い。 とくにIPv6 が混じってきて、1つのインターフェースに複数のIPが入ってくると辛い

シェルスクリプトで、grep してるけど、めっちゃめんどくさい。

オプション -o をつけると便利

1行に付き1つのIPアドレスが表示されるのでわかりやすい思う。

takuya@:~$ ip -o  a
1: lo    inet 127.0.0.1/8 scope host lo\       valid_lft forever preferred_lft forever
1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
2: enp3s0    inet 192.168.11.103/24 brd 192.168.11.255 scope global dynamic noprefixroute enp3s0\       valid_lft 39969sec preferred_lft 39969sec
2: enp3s0    inet6 fe80::6ae7:5e96:e212:xxxx/64 scope link noprefixroute \       valid_lft forever preferred_lft forever
3: vlan2    inet 192.168.2.102/24 brd 192.168.2.255 scope global dynamic noprefixroute vlan2\       valid_lft 18372sec preferred_lft 18372sec
3: vlan2    inet6 2001:xxxx:8383:a300:b1a2:9557:xxxx:adxxxxa4/64 scope global temporary dynamic \       valid_lft 13828sec preferred_lft 12028sec
3: vlan2    inet6 2001:xxxx:8383:a300:8012:e7db:xxxx:xxxx/64 scope global dynamic mngtmpaddr noprefixroute \       valid_lft 13828sec preferred_lft 12028sec
3: vlan2    inet6 fe80::91e1:2583:xxxx:edaf/64 scope link noprefixroute \       valid_lft forever preferred_lft forever

ip a の場合

一般的に使われる ip a の場合、次のように、インデントを使って表示される

  • インターフェース1
  • インターフェース2

オプションをつける

今回紹介した ip -o a の場合、次のように1行1レコードになる

  • インターフェース1 IPv4 アドレス
  • インターフェース1 IPv4 アドレス
  • インターフェース2 IPv4 アドレス
  • インターフェース2 IPv6 アドレス
  • インターフェース2 IPv6 アドレス

コマンドで処理をしたり、grep したり sed したりIP取得したりするときに、1行ごとの表示のほうが見やすくないですか?私は見やすいです

wc でIPの数を数えたり、grep で目的のIPレンジを探したり。インターフェースが増えてくるとこのほうが使いやすかった。

オプションについて

-o オプションは、LF(改行)を '\' バックスラッシュに置換してプリントしてくれるものです。もとに戻すなら置換をすればいいとわかります。

-o, -oneline output each record on a single line, replacing line feeds with the '\' character. This is convenient when you want to count records with wc(1) or to grep(1) the output.

参考資料

man ip

Certbotの証明書をドメインごとではなく、ワイルドカードで1枚証明書にまとめる。

certbot の証明書が増えすぎたので辛い

certbot で証明書をバンバン作ってたら管理がめんどくさくなってきた。

証明書の管理を楽にしたい。

LetsEncryptの証明書は、ワイルドカードに対応しているので、ワイルドカードな証明書を作ることもできるし

また、ワイルドカードだけでなく、複数のドメインを入れることができる。

  1. ワイルドカードを使う
  2. 複数ドメインを1つの証明書で賄う

これらの選択肢があります。

ワイルドカードの証明書の利用

ワイルドカード証明書を使うことで、ある程度の証明書をまとめることが出来た。

これについては、過去記事があります。→ certbot がLetsEncryptのワイルドカード証明書に対応してたので作ってみた - それマグで!

でも、まだ足りない。サブドメインワイルドカードや別ドメイン(別名)などもあると管理が煩雑だった。

複数ドメインを1枚の証明書にまとめる。

certbot の証明書は、「名前」(初期値はドメイン)単位で管理されているが、その証明書に含まれるドメインはいくつも指定が可能です。

説明
メインのドメイン example.com
ワイルドカード *.example.com
サブドメインのイルドカード *.takuya.example.com
ドメインワイルドカード *.example.jp

これらの複数のドメインワイルドカードを1枚に押し込める事が可能でした。

証明書をまとめるメリット

apache / nginx などの設定が非常に楽ちんになる。

証明書の更新作業が非常に楽ちんになる。

なので、ドメインを追加するときは新規で証明書作るより、既存の証明書(名前)にドメインを追加して再取得するほうがいい。

ワイルドカードで複数にサブドメインをまるっと突っ込む例。

mydomain=example.com \
sudo ./certbot-test/bin/certbot  \
  certonly \
  --cert-name $mydomain-all-in-one \
  --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflareapi.cfg \
  --server https://acme-v02.api.letsencrypt.org/directory \
   -d "$mydomain" \
   -d "*.$mydomain" \
   -d "*.a.$mydomain" 

このコマンドのポイントは

--cert-name で「覚えやすい名前」をつけているところ。(よく使われるの)ドメインそのままを名前にせず、自分で名付けています。これによって複数ドメインが入った証明書であることをわかりやすくしている

-d ドメイン で 複数ドメインワイルドカードも含めて)を指定しているところ。

オプションをこれら使うことで、証明書1つでマルチに対応できる

すでに存在する証明書をまとめる

これは、削除→新規作成と更新→追加の2つの選択肢がある。

  1. すでにある証明書を削除(delete/revoke)して、新規作成時にドメイン追加する。(覚えることが少ない
  2. すでにある証明書を更新して、ドメイン追加する。

削除→新規 の例

certbot revoke ...#略
certbot certonly  # 略

削除(revoke)と新規作成は、個別に記事があるので参照する。

追加 を使う

削除→追加以外にも追加オプションがあるので、これも知っておくと役に立ちそう

追加するときは、既存の証明書の名前を指定し、既存のドメインをすべて指定する。

設定例

mydomain=example.com \
sudo ./certbot-test/bin/certbot certonly \
   --cert-name $mydomain-allinone \
   -d git.example.com
  -d add.example.com

f:id:takuya_1st:20190328161857p:plain

TODO ↑の写真とコマンドは間違ってるので後で修正。

すると、次の様に、ドメインに追加するメニューと確認が出てくる。

本家解説

--expand documentation によると次のように解説されている。

--expand tells Certbot to update an existing certificate with a new certificate that contains all of the old domains and one or more additional new domains. With the --expand option, use the -d option to specify all existing domains and one or more new domains.

既存のドメインの証明書を新しい証明書に更新するが、一つ以上の追加(または削除)したいドメインがあるときに -d でドメインを列挙して指定する。

まとめ

証明書にドメイン追加とワイルドカードを使うことで、複数のサブドメインを1枚の証明書にまとめることができ、管理がとても楽ちんになる。

また、サブドメインでもなく、全然別のドメインを入れることができるので、別のドメインをまとめることで管理が簡素化する。 (ただし、同一証明書を利用しているときは、CDNやプロキシでさばくと便利なのですが、複数のドメインを証明書とプロキシでまとめるとその分平分で通信も見られやすいので注意が必要)

参考資料

https://certbot.eff.org/docs/using.html