それマグで!

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

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

HTMLのリセット(reset)ボタンで検索条件をクリアのときに、すでにデータがあるとクリアされない

html で検索フォーム

HTMLのFormで検索フォームを作ると、検索条件のリセットが欲しくなる。

とくにテストしているとリセットボタンが欲しくなる。

フォームのリセット

フォームのリセット、とても簡単です。HTMLの遺物を使えばいいんです。

<form action=search method=get>
<input type=search name=user value='' >
<input type=submit value=search>
<input type=reset value=reset >
</form>

とても簡単です、ボタンを一つおけばいいのですから

<input type=reset value=reset >

問題点:リセットはクリアじゃない

WEB側のCGI*1でHTMLを生成するとき

サーバー側でHTMLレンダリングを行っていると

<input type=search name=user value='takuya' >

サーバー側から送られた状態にリセットされます。

リセットボタンは、ユーザーの入力による変更を破棄であり、フォームのクリアではない。

解決策

input[type=search] を使えばいい。検索フォームに input[type=text] は使わない

なぜか?input[type=search] はMDNに記載があるように、ブラウザ側でフォームの値を持ち回してくれる。なんちうHTML要素だ。

phpなどでecho が不要になるのである。

<input type=search name=user value='<?php echo $cond;?>' >

これを使っておけば、input[value]は常に空っぽの状態になる。

*1:あえてこういう古い言いまわしをている

lxcのコンテナがホスト側のブロックデバイス(SSD)に直接アクセスできるように

LXCのコンテナから、ホストのHDDを参照したい。

色々やり方がある。一番かんたんなのは privileged をつけて特権コンテナにする。

lxc launch ubuntu:xenial <container name> -c security.privileged=true

実際にやってみると。次のようになる。ちゃんとホスト側のブロックデバイスやUSBデバイスが見え、マウントはできることがわかる。

takuya@raspberrypi:~ $ lxc launch ubuntu:xenial test -c security.privileged=true
takuya@raspberrypi:~ $ lxc shell test
root@test:~# lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop1         7:1    0  54.3M  1 loop
loop4         7:4    0   4.7G  0 loop /
loop2         7:2    0  83.6M  1 loop
loop0         7:0    0    20K  1 loop
sda           8:0    0 447.1G  0 disk
`-sda1        8:1    0 447.1G  0 part
mmcblk0     179:0    0  29.7G  0 disk
|-mmcblk0p2 179:2    0  29.5G  0 part
`-mmcblk0p1 179:1    0   256M  0 part
loop3         7:3    0  45.9M  1 loop
root@test:~# lsusb
Bus 002 Device 002: ID 056e:6a06 Elecom Co., Ltd
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 25a7:fa61
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

非特権コンテナでも見えるには見えるのだけれど。マウントはできません。

root@nonpre-container:~# mount /dev/sda1 /mnt
mount: /mnt: permission denied.

config disk add

ディスクをAddすることもできる。

lxc config device add container01 homedir disk source=/home/ path=/home/

参考資料

https://github.com/lxc/lxd/issues/2667

standardnotesのDocker版 を使ってみた。

standardnotes を使ってみた。

3行まとめ

  • マークダウンも使えない。 -最新版では、ファイルの添付ができない。
  • 無料版StandardNotesは機能制限が辛すぎる。

という地獄なので、基本的にはないな。って感じ

サーバー立てても意味がない。

次のようになる。

Dockerやってみた記録。

services:
  server:
    image: standardnotes/server
    env_file: env
    container_name: server_self_hosted
    restart: unless-stopped
    ports:
      - 3000:3000
      - 3125:3104
    volumes:
      - ../storage/logs:/var/lib/server/logs
      - ../storage/uploads:/opt/server/packages/files/dist/uploads
    networks:
      - standardnotes_self_hosted
  localstack:
    image: localstack/localstack:1.3
    container_name: localstack_self_hosted
    expose:
      - 4566
    restart: unless-stopped
    environment:
      - SERVICES=sns,sqs
      - HOSTNAME_EXTERNAL=localstack
      - LS_LOG=warn
    volumes:
      - ./localstack_bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
    networks:
      - standardnotes_self_hosted

  db:
    image: mysql:8
    container_name: db_self_hosted
    env_file: env
    expose:
      - 3306
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    volumes:
      - ../storage/data/mysql:/var/lib/mysql
      - ../storage/data/import:/docker-entrypoint-initdb.d
    networks:
      - standardnotes_self_hosted

  cache:
    image: redis:6.0-alpine
    container_name: cache_self_hosted
    volumes:
      - ../storage/data/redis/:/data
    expose:
      - 6379
    restart: unless-stopped
    networks:
      - standardnotes_self_hosted

networks:
  standardnotes_self_hosted:
    name: standardnotes_self_hosted

結論

いまのStandardnotes はOSSライセンスだけど、自由に全機能が使えるわけではない

legacy 化されたものなら昔のように行ける。とおもう https://github.com/standardnotes/self-hosted

StandardNotesはSelf-Hostingでよく見かけたアプリケーションだけど、それなりに便利だと記事があったので試したが、最新版はもうだめですね。サーバー作る意味がないですね。

notion っぽい共有メモツール outline を入れる。

notion っぽい感じのメモツールを使う。

オンラインで、メモを取れて各種添付が使えて、チームで使えるノートツールを使ってみる。

3年位追いかけてるけど、そろそろ使えるようになってる。当初は日本語の入力もままならない感じだったが、大丈夫そう。

動作イメージ

Google Driveなどもリンクで貼り付けられて便利である。

Developerビルドを使ってみる。

Dockerfile などは、ここにおいた。 https://github.com/takuya/outline-dev-docker-sample

Supervisordなどを使い、さっと最新版を導入するに十分にした。

ユーザ毎にアレコレできる

インスタンスのDBを眺めていると、マルチドメインホスティングもできそうでなかなか面白そうである。

一人で使うにはちょっと持て余すかもれないが、ドキュメントを残しておくにはちょうどいいかもしれない。

マークダウンなしでいい

マークダウンを説明しなくていい。なので非エンジニアに向けたノート共有ツールとしては優秀かもしれない。

sqlite modeで様々に出力した例。

sqlite3 は出力を変えられる。

sqlite mode を使って出力例を変えてみた例。

markdown

マークダウンで表を表示できる。マークダウンを書くのがめんどくさいときにはデータ突っ込んで、変換したら楽かもしれない。

mode box

罫線(ボックス)を使って表をきれいに出す。

mode col

CSV(文字区切り / charactor separated values) で表示すると、桁区切りで整理されて、便利だと思う。

まとめ

sqlite> .mode markdown
sqlite> .mode html
sqlite> .mode box
sqlite> .mode col
sqlite> .mode tab
sqlite> .mode json
sqlite> .mode insert

気づけば、色々なモードが追加されていて素晴らしい。markdown は割と便利かもしれない。比較的に大きなテーブルをマークダウンに変換するのもめんどくさい。HTMLもそれなりに便利だと思う。

これを、コマンド以外のプログラミングで使えると、アプリケーションを作らなくてもいいもんね.

mode col は mode column ともかける。

ssh で v6 アドレスをv4 へポートフォワーディング

ssh で v6 アドレスをv4 へポートフォワーディングを試してみた。

ssh で v4-v4 のポートフォワーディング

ssh my-server -L8080:192.168.1.1:80

ssh で v4-v6 のポートフォワーディング

v4 のときと同じで、v6 アドレスを [::1] のように[ ] で囲むだけ。

ssh router -L8080:[xxxx::e80:63ff:fe2e:c53b]:80

ssh のポートフォワーディングで、v6 アドレスをフォワーディングすると、v4-v6 の簡易ブリッジができて嬉しい。

意外と簡単に動いたので、楽だった。

Apacheとphp-fpm でphpを実行する。

Apache+php-fpm

mod_phpphp-fpm に切り替える。

nginx でやることも多いけど、fpm 使ってfcgi へ転送するなら、apache2 でも nginx でもあまり変わりない。 同じような仕組みなので、速度も大幅に変わることもないと思う。

apacheが不利だとすれば、.htaccessのチェックが走ることくらいだろうか。

#
sudo a2enmod proxy_fcgi setenvif
#
sudo a2dismod mpm_prefork
sudo apt list libapache2-mod-fcgid
#
sudo a2enconf php8.1-fpm
sudo a2dismod php7.0

もとに戻す。

sudo a2dismod proxy_fcgi setenvif
sudo a2dismod mpm_event
sudo a2enmod mpm_prefork
sudo a2disconf php8.1-fpm
sudo a2enmod php7.0

こうやってみると、Debianではコマンドが整備されているApache2がらくで使いやすいよね。

php-fpm に切り替えたら、一部のアプリで不具合が発生したので、追加調査が必要。(たぶんモジュール関係とfcgi-param関連)

net-smpt xoauth2 でGmailを使って送信する。

net-smpt xoauth2 でGmailを使って送信する。

GMail はアレコレややこしい。とりあえず、OAuth2に対応させれば、SMTPサーバーを使わせてもらえる。

require 'gmail_xoauth'
require "googleauth"
require "googleauth/stores/file_token_store"
require 'gmail_xoauth'


def client_access_token(user_id)
    client_secret_path = File.expand_path(File.dirname(__FILE__)+"/../../credentials/client_secret.json")
    token_path = File.expand_path(File.dirname(__FILE__)+"/../../credentials/tokens.yaml")
    scope = 'https://mail.google.com/'
    authorizer = Google::Auth::UserAuthorizer.new(
      Google::Auth::ClientId.from_file(client_secret_path),
      scope,
      Google::Auth::Stores::FileTokenStore.new(file: token_path)
    )
    credentials = authorizer.get_credentials(user_id)
    credentials.refresh!
    credentials.access_token
end
def smtp_connect_by_xoauth()
    user="fax4783@morioka.biz"
    token=client_access_token(user)

    smtp = Net::SMTP.new("smtp.gmail.com", 587)
    smtp.enable_starttls_auto
    smtp.start('smtp.gmail.com', user, token, :xoauth2)
    smtp.finish
    puts 'OK'
    true
end

ret = smtp_connect_by_xoauth

client_secret や token は事前に発行しているという感じ

Gem の例

サンプルを作ったときに使ったGemfileの例

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "gserver"
gem "net-smtp", '~>0.3.3'
gem "mail", "~> 2.7"
gem "google-apis-gmail_v1"
gem "gmail_xoauth"

ここでのポイントは、"net-smtp", '~>0.3.3' である。0.4.0移行では"gmail_xoauth"のauth の仕組みが変わってて動かないので注意。

関連資料

参考資料

rsync でディレクトリ構造だけを同期する。

ディレクトリ構造だけを動悸する。

rsync -av -f"+ */" -f"- *" .

rclone だとディレクトリ構造をコピー出来ないので、

rclone mount 後に rsyncディレクトリ構造をコピーする。

参考資料

https://www.cyberciti.biz/faq/unix-linux-bsdosx-copying-directory-structures-trees-rsync/

df/lsblkを最適化する。

df の結果が見づらいので整理する。

dflsblk の結果がとても冗長になり、欲しい物が見えなくなった。

lsblk で loopデバイスが表示されるのはまだわかるが、マウント先も大量に表示されるともうカオス。

df では tmpfs や loopにかぎらずシステム運用のsquashfs まで表示されると本当にカオス

tmpfs をRAM-FSとして使っている場合は、

alias df='df -x squashfs'

とかかな。

たとえば、ext4 だけを表示したい、tmpfsだけ表示したい。その両方

df -t ext4
df -t tmpfs
df -t ext4 -t tmpfs 

本当に、こんなに表示が必要なのだろうか。絶対要らないし、見たいのは物理ストレージがほとんどですよね。

ってことで、参考資料を見て、よく使うものだけに絞り込むことにした

lsblk -e 7 がポイントだと思う。

alias df='df -x squashfs -x tmpfs'
alias lsblk='lsblk -e 7 -o NAME,SIZE,FSAVAIL,FSUSE%,FSTYPE'

参考資料

htop の色の意味(メモリの黄色は?)

htop の色の意味(メモリの黄色は?)

F1を押せばでてくる。

  • 黄色=Cache
  • 青色=buffers
  • 緑色=used
  • 紫色=Shared

ってことですね。

メモリでいうと、黄色のキャッシュがストレージのリードキャッシュでしょうね。tmpfs は黄色か紫色に出てくるはず。

WSLをエクスポートする

WSLをエクスポートする

WSL環境をバックアップ取っておきたい。

動作しながらのエクスポートは出来ないんで注意。

C:\Users\takuya>wsl.exe --export Debian Debian.tgz  

参考資料

https://superuser.com/questions/1589877/how-do-you-clone-a-wsl-distro

nginx で lua を使う(nginx lua でハローワールド)便利なテクニックをご紹介!

nginx で lua を使う

インストールと準備

deiban の場合は次で一発で終わる。

sudo apt install libnginx-mod-http-lua

最初に第一歩

  location ~ / {
    default_type 'text/html';
    content_by_lua "ngx.say('Hello, ngx_lua World!')";
  }

アクセスしてみる。

lua の実行結果が表示される。

もっと他の例

nginx で lua を使ってハローワールド(ソースを直接に記述)

  location /hello {
    content_by_lua '
      ngx.print("hello-")
      ngx.say("world")
    ';
  }

say( ) と print() がある。改行の違いがある say は改行付き。改行で "hello\n"とできない。sayを使う。

バージョン確認

location /lua_version{
    content_by_lua 'ngx.say(_VERSION)';
}

リクエストメソッドを見る。

location /method {
    content_by_lua '
        ngx.print(ngx.req.get_method())
    ';
}

if 文を使う。

  location /info {
    content_by_lua '
      m = ngx.req.get_method()
      if  m == "GET"  then
        ngx.print("we got GET request")
      elseif m == "POST" then
        ngx.print("we got POST request")
      else
        ngx.print("we got OTHER request")
      end
    ';
  }

テストする

curl  http://127.0.0.1/info
>  we got GET request
curl -X POST -d name  http://127.0.0.1/info
>  we got POST request
curl -X DELETE http://127.0.0.1/info
> we got OTHER requestt

ここまでで、if 文とHTTP メソッドの切り分け、そしてコンテンツの返し方がわかった。

ヘッダ書き出し

ヘッダの書き出し(リダイレクト)

https://github.com/openresty/lua-nginx-module#ngxredirect

location /info {
    content_by_lua '
      m = ngx.req.get_method()
      if m == "POST" then
         return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY)
      end
    ';
}

ステータスコードを変える 404 にする

location /info {
    content_by_lua '
      m = ngx.req.get_method()
      if m == "POST" then
        ngx.status = 404
        ngx.print("not found.")
        return;
       end
    ';
}

POSTの中身にアクセス。

https://github.com/openresty/lua-nginx-module#ngxreqget_post_args

  location /info {
    content_by_lua '
      m = ngx.req.get_method()
      if m == "POST" then
          ngx.req.read_body()
          local args, err = ngx.req.get_post_args()

          if err == "truncated" then
            -- one can choose to ignore or reject the current request here
          end

          if not args then
            ngx.say("failed to get post args: ", err)
            return
          end
          for key, val in pairs(args) do
            if type(val) == "table" then
              ngx.say(key, ": ", table.concat(val, ", "))
            else
              ngx.say(key, ": ", val)
            end
        end
      end
    ';
  }

エラー処理が多くてわかりにくい.、コア部分だけを書くと、次のようになる。

ngx.req.read_body()
local args, err = ngx.req.get_post_args()

key="input_name"
val=args[key]
if val then
  ngx.say( key, ": ",val)
end

コマンドの実行結果

適当なコマンドを実行して、結果をブラウザに返す。

 content_by_lua '
        local handle = io.popen("echo hello world")
        local ret = handle:read("*a")
        ngx.say( "ret : ", ret )
        return ;
';

luaにない機能を手早くつかうには、コマンドを呼び出したほうが早いから。

ただし、ユーザーのリクエスト(Cookieなどヘッダも含む)をつ勝ったコマンドのインジェクションには十分に注意すること。

リダイレクト

location /login {
  if ($request_method != POST) {
    return 302 $scheme://$host/auth.html;
  }
  if ($request_method = POST) {
    content_by_lua '
        -- なにか処理
        ngx.header["Set-Cookie"] = {
          string.format("hash=%s; path=/; Expires=%s", hash, expires),
          string.format("key=%s;  path=/; Expires=%s", rand, expires),
        }
        ngx.status=302
      else
        ngx.status=401
      end

      return ngx.redirect("/?"..ngx.var.query_string)  }
}

乱数の使い方。

シードが同じなら、同じ乱数が返される。

math.randomseed( tonumber("4a4",16) )

s = ""
for i = 64,1,-1 do
   s = s..(string.format("%x",math.random(0,15)))
end

print(s)

random と hash の cookie の値を一つにする

lua から nginx 変数をセットする、かつ外部ファイルにする。

lua とnginxは変数を共有することができるのです。

また、Luaは外部ファイルに記述が可能、外部Luaライブラリ・外部Luaファイルを使えば、nginxの設定ファイルから切り離して使い回しができる。

nginx の設定を抽象化してプログラミングっぽくLuaで書くことで可搬性がかなり向上します。

準備

外部ファイルを保存する場所を作る。

## nginx の起動時のディレクトリは /usr/share/nginx/ なので
mkdir -p /etc/nginx/lua
sudo ln -sr /etc/nginx/lua /usr/share/nginx/

server in nginx.conf

  location ~ / {
    default_type 'text/html';
    set_by_lua_file $greeting 'lua/hello.lua';
    return 200 'var from lua = "$greeting"';
  }

lua ファイル /etc/nginx/lua/hello.lua ( nginx からは/usr/share/nginx/lua/hello.luaとして見えている)

return 'Hello from lua file'

実行すると

まとめ

lua を使って nginx の痒いところに手が届く

## コンテンツを帰す場合
content_by_lua "ngx.say('Hello, ngx_lua World!')";
content_by_lua_file "lua/content.lua;
## 変数をセットする場合
set_by_lua  var_name  'return var_value';
set_by_lua_file $greeting 'lua/hello.lua';

これで、「動的に中身を変えた変数」を作ることが出来て、nginx の設定ファイルの中に固定値で設定を書く必要がなくなり、lua スクリプトから変数を自在に設定することができる。

リバプロ先を考えるとき、サーバーの設定を変えずに済むわけである。またCookieなどのcredentials をスタティックに書く必要がなくなり、nginx の設定にパスワード類が記載されないようになる。そのため「余計なものを持たない」ことになり、管理が向上しセキュリティ向上(セキュア)になるという算段である。

nginx再起動は必要か?

再起動の実行は不要だが、リロードは必要。つまり実質的に再起動は必須といえる。

nginx は lua のコンテンツをファイルの中身から読み取ってロードして保持しているので、都度都度ファイルからは読まない。

php とどっちがいいの

本当にちょっとしたことをするくらいなら lua で書いちゃうのがありだと思う。ログインチェックとかヘッダ追加とか。

たとえば、APIを他人に使わせないBearerで固定キー認証くらいならlua で書いてしまえばnginx+luaで片付くので、本当にシンプルでいい。

参考資料

nginxでlua を使おうと思ったらdebianが楽

debian のnginxでluaを使ってたのでUbuntuで使おうと思ったらなかった。

debian のnginx には lua があった。どこで入れたんだっけ。

nginx -V 

確認したけどコンパイルでは入ってない。

モジュールでは入ってる。

apt-file show libnginx-mod-http-lua
libnginx-mod-http-lua: /usr/lib/nginx/modules/ngx_http_lua_module.so
libnginx-mod-http-lua: /usr/share/doc/libnginx-mod-http-lua/changelog.Debian.gz
libnginx-mod-http-lua: /usr/share/doc/libnginx-mod-http-lua/copyright
libnginx-mod-http-lua: /usr/share/nginx/modules-available/mod-http-lua.conf

インストールの詳細

takuya@:~$ apt show libnginx-mod-http-lua
Package: libnginx-mod-http-lua
Version: 1:0.10.23-1
Priority: optional
Section: httpd
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Installed-Size: 471 kB
Depends: libnginx-mod-http-ndk, lua-resty-core (<< 0.1.25.1~), lua-resty-core (>= 0.1.25), nginx-abi-1.22.1-7, libc6 (>= 2.33), libluajit2-5.1-2 (>= 2.1-20220411) | libluajit-5.1-2 (>= 2.1.0~beta3), libpcre3
Recommends: nginx
Homepage: https://github.com/openresty/lua-nginx-module
Download-Size: 157 kB
APT-Manual-Installed: yes
APT-Sources: http://debian-mirror.sakura.ne.jp/debian bookworm/main amd64 Packages
Description: Lua module for Nginx
 Embed Lua runtime into nginx.
 .
 This module embeds Lua, via LuaJIT 2-5.1, into Nginx and by leveraging Nginx's
 subrequests, allows the integration of the powerful Lua threads
 (Lua coroutines) into the Nginx event model.

Ubuntuのnginxは面倒だった。

Ubuntuの場合はもっと劣悪で、モジュールが提供されてない。

調べたら、Ubuntuには提供されてない。

https://launchpad.net/%7Eondrej/+archive/ubuntu/nginx

どうしようかと思ってたらPPAにありましたした。 https://askubuntu.com/questions/1375817/libnginx-mod-http-lua-at-ubuntu-21-10

debian が楽だった。

debian なら標準aptに提供されていてnginx + lua はらくちんだった。

github のワークフローでシークレット(環境変数)を取り出す方法のメモ

githubのワークフローに設定したキー紛失

事故で環境変数を喪失しました。はい。シークレットがわかりません。

でも、Githubのワークフローには残ってるんです。使えているのです。なんとかしてGithubワークフローで使っているシークレット変数を取り出して、パスワードをリカバリーして取り出しできないか、検討した。

githubのワークフローに設定したキーを取り出す。

方法が2つある。

  • 方法1 Artifactsとして成果物として取り出す。
  • 方法2 SSHで強引に入って、強奪する。

Artifactsでいいのなら、Artifactsで取り出せばいいけど。Artifactsは残り続けるので管理がめんどくさい。

私は、方法2が楽でいいと思った。

github actions のインスタンスSSHを追加してログインできるようにしてくれるツールが有る。 mxschmitt/action-tmate@v3 を使えば良い。

いったん、echo で環境を書き出しておいて、SSHでログインして取り出せば楽。

こんな感じ。

name: development-ssh
on:
  push:
    branch:
      - dev

jobs:
  run-ssh:
    runs-on: ubuntu-latest
    permissions: read-all
    steps:
      - name: checkout
        uses: actions/checkout@v3
      - name : env_vars
        run:
          echo MY_TOKEN1=${{ secrets.MY_TOKEN1  }} >> aenv
          echo MY_SECERTS=${{ secrets.MY_SECRETS  }} >> aenv
      - name: Setup tmate session
        uses: mxschmitt/action-tmate@v3

ワークフローを起動するとSSHが出てくるので、 そこへSSHしてcat する

ssh RANDSTRING@sfo2.tmate.io 'cat aenv'

これで、出力できて、無事にgithubにプロジェクト・ワークフローに設定した。秘密鍵を取り出すことができた。

参考資料

https://qiita.com/shonansurvivors/items/cb8902acfe5c3a1b3ca0 https://blog.n-z.jp/blog/2019-11-10-github-actions-tmate.html