<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
    <title>ktaka&#x27;s blog</title>
    <subtitle>ktaka&#x27;s blog — Linux, セキュリティ, プログラミングの技術メモ</subtitle>
    <link rel="self" type="application/atom+xml" href="https://ktaka.blog.ccmp.jp/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-07T00:00:00+00:00</updated>
    <id>https://ktaka.blog.ccmp.jp/atom.xml</id>
    <entry xml:lang="ja">
        <title>fcitx5 で日本語・中国語・英語の3言語入力環境を構築する</title>
        <published>2026-03-07T00:00:00+00:00</published>
        <updated>2026-03-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2026/Fcitx5MultilingualInput/"/>
        <id>https://ktaka.blog.ccmp.jp/2026/Fcitx5MultilingualInput/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2026/Fcitx5MultilingualInput/">&lt;p&gt;&lt;em&gt;筆者が普段使っている日本語・中国語・英語の3言語入力環境を、fcitx5 でどう設定しているかをまとめました。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;複数の言語を日常的に使う場合、入力メソッドの切り替えがスムーズにできるかどうかは作業効率に直結します。&lt;&#x2F;p&gt;
&lt;p&gt;Linux の入力メソッドフレームワークは主に2つあります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;フレームワーク&lt;&#x2F;th&gt;&lt;th&gt;特徴&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;fcitx5&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;多言語対応に強く、複数の入力メソッドをグループ化して切り替えられる。多言語環境ではこちらが主流&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ibus&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;GNOME のデフォルト。単一言語であれば十分だが、多言語の切り替えは fcitx5 の方がスムーズ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;この記事では、fcitx5 を使って以下の3言語を1つのキーで切り替えられる環境を構築します。&lt;&#x2F;p&gt;
&lt;!-- TODO: タスクトレイのアイコンが keyboard-jp → mozc → pinyin と切り替わるスクリーンショット3枚 or GIF --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;言語&lt;&#x2F;th&gt;&lt;th&gt;入力メソッド&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;英語&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;keyboard-jp&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;JIS 配列キーボードでそのまま英数入力&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;日本語&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;mozc&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Google 日本語入力の OSS 版。Linux 日本語入力のデファクトスタンダード&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;中国語&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;pinyin&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;fcitx5 内蔵のピンイン入力エンジン。簡体字・繁体字の両方に対応&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;動作環境は Debian 13 (trixie) + Xfce4 ですが、他のディストリビューションやデスクトップ環境でも手順はほぼ同じです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;patukezinoinsutoru&quot;&gt;パッケージのインストール&lt;&#x2F;h2&gt;
&lt;p&gt;必要なパッケージをインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install fcitx5 fcitx5-mozc fcitx5-chinese-addons&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;パッケージ&lt;&#x2F;th&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fcitx5&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;入力メソッドフレームワーク本体&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fcitx5-mozc&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;日本語入力エンジン（Mozc）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fcitx5-chinese-addons&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;中国語入力のメタパッケージ（pinyin、簡繁変換等を含む）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;fcitx5-chinese-addons&lt;&#x2F;code&gt; をインストールすると、依存関係で &lt;code&gt;fcitx5-pinyin&lt;&#x2F;code&gt;（ピンイン入力エンジン）や簡繁変換アドオンなども一緒にインストールされます。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;huan-jing-bian-shu-noshe-ding&quot;&gt;環境変数の設定&lt;&#x2F;h2&gt;
&lt;p&gt;fcitx5 をすべてのアプリケーションで使えるようにするため、以下の環境変数が必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; XMODIFIERS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;@im&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;fcitx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; GTK_IM_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;fcitx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; QT_IM_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;fcitx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Debian では &lt;code&gt;im-config&lt;&#x2F;code&gt; コマンドで設定するのが標準的な方法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;im-config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fcitx5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これにより &lt;code&gt;~&#x2F;.xinputrc&lt;&#x2F;code&gt; に &lt;code&gt;run_im fcitx5&lt;&#x2F;code&gt; が書き込まれ、X セッション開始時に &lt;code&gt;&#x2F;etc&#x2F;X11&#x2F;Xsession.d&#x2F;70im-config_launch&lt;&#x2F;code&gt; 経由で環境変数が自動的に設定されます。手動で &lt;code&gt;~&#x2F;.xprofile&lt;&#x2F;code&gt; 等に書く必要はありません。&lt;&#x2F;p&gt;
&lt;p&gt;設定後、ログインし直すと反映されます。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;purohuairunoshe-ding&quot;&gt;プロファイルの設定&lt;&#x2F;h2&gt;
&lt;p&gt;fcitx5 のプロファイル（&lt;code&gt;~&#x2F;.config&#x2F;fcitx5&#x2F;profile&lt;&#x2F;code&gt;）で、使用する入力メソッドを定義します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Groups&#x2F;0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Group Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;=Default&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Layout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Default &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Layout&lt;&#x2F;span&gt;&lt;span&gt;=jp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Default Input Method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;DefaultIM&lt;&#x2F;span&gt;&lt;span&gt;=mozc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Groups&#x2F;0&#x2F;Items&#x2F;0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;=keyboard-jp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Layout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Layout&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Groups&#x2F;0&#x2F;Items&#x2F;1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;=mozc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Layout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Layout&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Groups&#x2F;0&#x2F;Items&#x2F;2]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;=pinyin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Layout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Layout&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[GroupOrder]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;=Default&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Default Layout=jp&lt;&#x2F;code&gt; — ベースのキーボードレイアウトを JIS 配列に設定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;DefaultIM=mozc&lt;&#x2F;code&gt; — デフォルトの入力メソッドを Mozc に設定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Items&#x2F;0&lt;&#x2F;code&gt;〜&lt;code&gt;Items&#x2F;2&lt;&#x2F;code&gt; — トリガーキーで順に切り替わる入力メソッドの一覧&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;GUI で設定する場合は &lt;code&gt;fcitx5-configtool&lt;&#x2F;code&gt; を使って、Input Method の一覧に keyboard-jp、mozc、pinyin を追加します。&lt;&#x2F;p&gt;
&lt;!-- TODO: fcitx5-configtool の Input Method 一覧画面のスクリーンショット --&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hotutokinoshe-ding&quot;&gt;ホットキーの設定&lt;&#x2F;h2&gt;
&lt;p&gt;入力メソッドの切り替えキーは &lt;code&gt;~&#x2F;.config&#x2F;fcitx5&#x2F;config&lt;&#x2F;code&gt; で設定します。主要な設定項目を抜粋します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Hotkey]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Skip first input method while enumerating&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;EnumerateSkipFirst&lt;&#x2F;span&gt;&lt;span&gt;=False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Hotkey&#x2F;TriggerKeys]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;=Shift+space&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Hotkey&#x2F;EnumerateGroupForwardKeys]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;=Control+Shift+Shift_R&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Behavior]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Share Input State&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ShareInputState&lt;&#x2F;span&gt;&lt;span&gt;=No&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Show preedit in application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PreeditEnabledByDefault&lt;&#x2F;span&gt;&lt;span&gt;=True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TriggerKeys&lt;&#x2F;strong&gt; (&lt;code&gt;Shift+Space&lt;&#x2F;code&gt;) — 入力メソッドを順に切り替えるキー。押すたびに keyboard-jp → mozc → pinyin → keyboard-jp ... と循環します&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;EnumerateSkipFirst&lt;&#x2F;strong&gt; (&lt;code&gt;False&lt;&#x2F;code&gt;) — &lt;code&gt;False&lt;&#x2F;code&gt; にすると keyboard-jp（英語直接入力）も切り替え対象に含まれます。&lt;code&gt;True&lt;&#x2F;code&gt; にすると最初の入力メソッドをスキップします&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;EnumerateGroupForwardKeys&lt;&#x2F;strong&gt; (&lt;code&gt;Control+Shift+Shift_R&lt;&#x2F;code&gt;) — 入力メソッドグループ全体を切り替えるキー。グループを1つしか使わない場合は不要ですが、将来グループを追加した場合（例: 別のキーボードレイアウト用グループ）に使えます&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ShareInputState&lt;&#x2F;strong&gt; (&lt;code&gt;No&lt;&#x2F;code&gt;) — ウィンドウごとに入力メソッドの状態を独立させます&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;設定を変更したら fcitx5 を再起動します。&lt;code&gt;-r&lt;&#x2F;code&gt; は既存プロセスの置き換え（replace）、&lt;code&gt;-d&lt;&#x2F;code&gt; はデーモンとしてバックグラウンド実行です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fcitx5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r -d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;pinindefan-ti-zi-woru-li-suru&quot;&gt;ピンインで繁体字を入力する&lt;&#x2F;h2&gt;
&lt;p&gt;fcitx5-chinese-addons に含まれる「簡繁変換」アドオン（&lt;code&gt;chttrans&lt;&#x2F;code&gt;）を使うと、ピンイン入力のまま簡体字と繁体字を切り替えられます。別の入力メソッドを追加する必要はありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;qie-riti-efang-fa&quot;&gt;切り替え方法&lt;&#x2F;h3&gt;
&lt;p&gt;ピンイン入力中に &lt;strong&gt;&lt;code&gt;Ctrl+Shift+F&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; を押すと、出力が簡体字から繁体字に切り替わります。もう一度押すと簡体字に戻ります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;she-ding-noque-ren&quot;&gt;設定の確認&lt;&#x2F;h3&gt;
&lt;p&gt;このアドオンは &lt;code&gt;fcitx5-chinese-addons&lt;&#x2F;code&gt; に含まれているため、パッケージをインストールしていれば追加設定なしで使えます。&lt;code&gt;fcitx5-configtool&lt;&#x2F;code&gt; の Addons タブで「Simplified and Traditional Chinese Translation」が有効になっていることを確認してください。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;toraburusiyuteingu&quot;&gt;トラブルシューティング&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;purohuairugarisetutosareru&quot;&gt;プロファイルがリセットされる&lt;&#x2F;h3&gt;
&lt;p&gt;まれに、リブート後に &lt;code&gt;~&#x2F;.config&#x2F;fcitx5&#x2F;profile&lt;&#x2F;code&gt; がデフォルト（&lt;code&gt;keyboard-jp&lt;&#x2F;code&gt; のみ）にリセットされることがあります。原因はクラッシュや異常終了時のプロファイル書き戻し失敗が考えられます。&lt;&#x2F;p&gt;
&lt;p&gt;対策として、正常動作時のプロファイルと設定のバックアップを取っておくことをお勧めします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~&#x2F;.config&#x2F;fcitx5&#x2F;profile ~&#x2F;.config&#x2F;fcitx5&#x2F;profile.bak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~&#x2F;.config&#x2F;fcitx5&#x2F;config ~&#x2F;.config&#x2F;fcitx5&#x2F;config.bak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;fcitx5-gaqi-dong-sinai-ru-li-dekinai&quot;&gt;fcitx5 が起動しない・入力できない&lt;&#x2F;h3&gt;
&lt;p&gt;環境変数が正しく設定されているか確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span&gt; $XMODIFIERS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # @im=fcitx であること&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span&gt; $GTK_IM_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # fcitx であること&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span&gt; $QT_IM_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # fcitx であること&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;fcitx5-diagnose&lt;&#x2F;code&gt; コマンドを実行すると、設定の問題を包括的に診断できます。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;fcitx5 で日本語・中国語・英語の3言語入力環境を構築しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fcitx5&lt;&#x2F;strong&gt; — 多言語切り替えに適した入力メソッドフレームワーク&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;mozc&lt;&#x2F;strong&gt; — 日本語入力のデファクトスタンダード&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;pinyin&lt;&#x2F;strong&gt; — 中国語ピンイン入力。&lt;code&gt;Ctrl+Shift+F&lt;&#x2F;code&gt; で簡繁変換も可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Shift+Space&lt;&#x2F;strong&gt; 一つで3言語を循環切り替え&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;設定ファイルは &lt;code&gt;~&#x2F;.config&#x2F;fcitx5&#x2F;profile&lt;&#x2F;code&gt;（入力メソッドの構成）と &lt;code&gt;~&#x2F;.config&#x2F;fcitx5&#x2F;config&lt;&#x2F;code&gt;（ホットキーや動作設定）の2つだけなので、バックアップも容易です。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>パスワードなしの認証を試す: oauth2-passkey ライブデモ</title>
        <published>2026-03-02T00:00:00+00:00</published>
        <updated>2026-03-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2026/Oauth2PasskeyDemo/"/>
        <id>https://ktaka.blog.ccmp.jp/2026/Oauth2PasskeyDemo/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2026/Oauth2PasskeyDemo/">&lt;p style=&quot;text-align: right&quot;&gt;&lt;a href=&quot;&#x2F;en&#x2F;2026&#x2F;Oauth2PasskeyDemo&quot;&gt;English version&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt; は、OAuth2 と Passkey を組み合わせたパスワードレス認証を、少ないコードで Rust の Web アプリに組み込めるライブラリです。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;デモサイト &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt; を用意しました。
実際の操作を2本の動画で紹介し、その後にコードの使い方を説明します。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;demo-1-google-dedeng-lu-site-passkey-wozhui-jia&quot;&gt;デモ 1: Google で登録して Passkey を追加&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;video width=&quot;408&quot; src=&quot;&#x2F;2026&#x2F;Oauth2PasskeyDemo&#x2F;video&#x2F;o2p-2026-03-01_17.11.16-blurred.mp4&quot; controls&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;まず新規ユーザーとしてログインする流れです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ログインページには「Register &#x2F; Sign in with Google」と「Sign in with Passkey」の2つのボタンがあります。&lt;&#x2F;li&gt;
&lt;li&gt;「Register &#x2F; Sign in with Google」を押すと、おなじみの Google アカウント選択画面が開きます。&lt;&#x2F;li&gt;
&lt;li&gt;Google 認証が終わると、すぐに &lt;strong&gt;「Passkey を作成しますか？」&lt;&#x2F;strong&gt; というダイアログが出ます。これがこのライブラリの特徴の一つである &lt;strong&gt;「Passkey プロモーション」&lt;&#x2F;strong&gt; です。OAuth2 でログインしたユーザーに Passkey の登録を自然に促します。&lt;&#x2F;li&gt;
&lt;li&gt;Passkey を作成するとダッシュボードに遷移し、My Account や Admin Panel にアクセスできます。&lt;&#x2F;li&gt;
&lt;li&gt;My Account ページでは、ユーザー情報・Passkey 資格情報・連携 OAuth2 アカウント・ログイン履歴を一覧で確認できます。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;いつもの Google ログインで始めて、そのまま Passkey も登録できるのがこの仕組みのよいところです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;demo-2-passkey-desainin&quot;&gt;デモ 2: Passkey でサインイン&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;video width=&quot;408&quot; src=&quot;&#x2F;2026&#x2F;Oauth2PasskeyDemo&#x2F;video&#x2F;o2p-2026-03-01_17.12.01-blurred.mp4&quot; controls&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;続いて、同じユーザーが Passkey だけでログインする流れです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ログインページで「Sign in with Passkey」を押すと、ブラウザの Passkey ダイアログが表示されます。&lt;&#x2F;li&gt;
&lt;li&gt;指紋や顔認証で本人確認をすれば、それだけでログインが完了します。Google へのリダイレクトもパスワード入力も要りません。&lt;&#x2F;li&gt;
&lt;li&gt;ログイン履歴には Passkey と OAuth2 の両方のエントリーが残るので、いつ・どの方法でログインしたか確認できます。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Passkey を一度登録してしまえば、普段のログインはこれだけです。高速で、フィッシングにも強い認証が手に入ります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shi-sitemiru&quot;&gt;試してみる&lt;&#x2F;h2&gt;
&lt;p&gt;デモサイトはこちらです: &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Google でサインイン → Passkey を登録 → Passkey でサインイン、という一連の流れを試せます&lt;&#x2F;li&gt;
&lt;li&gt;デモでは全ユーザーに管理者権限が付与されるので、管理パネルも自由に操作できます&lt;&#x2F;li&gt;
&lt;li&gt;ログイン履歴ではデバイスや認証方法の詳細も確認できます&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;データはメモリ上に保存されていて、サーバー再起動時にリセットされます。気軽にどうぞ。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;oauth2-passkey-toha&quot;&gt;oauth2-passkey とは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt; は、Web アプリにパスワードレス認証を追加するための Rust ライブラリです。2種類の認証方式を一つのライブラリで扱えます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OAuth2 (Google)&lt;&#x2F;strong&gt; -- ユーザーにとって馴染みのある、ワンクリックの登録・ログイン&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Passkeys (WebAuthn&#x2F;FIDO2)&lt;&#x2F;strong&gt; -- 指紋・顔・セキュリティキーによる、フィッシング耐性のあるログイン&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;想定する運用フローは、まず Google で登録してもらい、その流れで Passkey も追加してもらう形です。デバイスを紛失した場合でも Google 経由でログインできるので、Passkey 一本に依存するリスクを回避できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kuitukusutato&quot;&gt;クイックスタート&lt;&#x2F;h2&gt;
&lt;p&gt;Axum アプリへの組み込みは以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; routing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;get,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;IntoResponse&lt;&#x2F;span&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; oauth2_passkey_axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AuthUser&lt;&#x2F;span&gt;&lt;span&gt;, oauth2_passkey_full_router};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[tokio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;main]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;dyn&lt;&#x2F;span&gt;&lt;span&gt; std&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    oauth2_passkey_axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; app&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Router&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; get&lt;&#x2F;span&gt;&lt;span&gt;(home))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&#x2F;protected&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; get&lt;&#x2F;span&gt;&lt;span&gt;(protected))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;merge&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;oauth2_passkey_full_router&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; listener&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tokio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;net&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;TcpListener&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;0.0.0.0:3001&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;serve&lt;&#x2F;span&gt;&lt;span&gt;(listener, app)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span&gt;(())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; home&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;Welcome! Visit &#x2F;o2p&#x2F;user&#x2F;login to sign in&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; protected&lt;&#x2F;span&gt;&lt;span&gt;(user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; AuthUser&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt; impl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; IntoResponse&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    format!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Hello, {}!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;account)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;oauth2_passkey_full_router()&lt;&#x2F;code&gt; を呼ぶと、&lt;code&gt;&#x2F;o2p&#x2F;*&lt;&#x2F;code&gt; 以下に、ログインページ・OAuth2 フロー・Passkey の登録／認証・ユーザーアカウント管理・管理パネルなど、一式のルートが追加されます。&lt;&#x2F;p&gt;
&lt;p&gt;あとは環境変数で Google OAuth2 のクレデンシャルとセッションシークレットを設定すれば動きます。詳しくは &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ktaka-ccmp.github.io&#x2F;oauth2-passkey&#x2F;&quot;&gt;Getting Started ガイド&lt;&#x2F;a&gt;をご覧ください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ji-neng-yi-lan&quot;&gt;機能一覧&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;デュアル認証&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;OAuth2 (Google) と Passkeys を一つのライブラリで提供&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;組み込み UI&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;ログインページ、ユーザーアカウント画面、管理パネル付き&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Passkey プロモーション&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;OAuth2 ユーザーに Passkey 登録を自然に提案&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ログイン履歴&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;IP・User-Agent・認証器の詳細を自動記録&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;セッション管理&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;セキュアな Cookie、セッション競合ポリシー、強制ログアウト&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;管理パネル&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;ユーザー管理、監査ログ、管理者の誤操作防止&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;テーマ&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;9種の CSS テーマを同梱、カスタムテーマにも対応&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ストレージ&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;SQLite（開発用）／PostgreSQL（本番用）、キャッシュは Redis またはインメモリに対応&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;rinku&quot;&gt;リンク&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ライブデモ&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;oauth2-passkey&quot;&gt;ktaka-ccmp&#x2F;oauth2-passkey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;crates.io&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt; &#x2F; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey-axum&quot;&gt;oauth2-passkey-axum&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ドキュメント&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ktaka-ccmp.github.io&#x2F;oauth2-passkey&#x2F;&quot;&gt;ktaka-ccmp.github.io&#x2F;oauth2-passkey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;bei-jing&quot;&gt;背景&lt;&#x2F;h2&gt;
&lt;p&gt;このライブラリは、2025年初頭に &lt;a href=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&quot;&gt;Passkey 認証をスクラッチで実装した記事&lt;&#x2F;a&gt;がきっかけで生まれました。そのとき WebAuthn プロトコルを一から学んだ経験をもとに、OAuth2 連携・セッション管理・UI を備えた汎用ライブラリとして仕立て直しました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Try Passwordless Auth: oauth2-passkey Live Demo</title>
        <published>2026-03-02T00:00:00+00:00</published>
        <updated>2026-03-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/en/2026/Oauth2PasskeyDemo/"/>
        <id>https://ktaka.blog.ccmp.jp/en/2026/Oauth2PasskeyDemo/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/en/2026/Oauth2PasskeyDemo/">&lt;p style=&quot;text-align: right&quot;&gt;&lt;a href=&quot;&#x2F;2026&#x2F;Oauth2PasskeyDemo&quot;&gt;日本語版&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;A live demo of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt;, a Rust library that adds OAuth2 and Passkey authentication to your web app with minimal code.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Two short videos below walk through the demo at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt; — first registering via Google and adding a Passkey, then signing in using only the Passkey.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;demo-1-register-with-google-and-add-a-passkey&quot;&gt;Demo 1: Register with Google and Add a Passkey&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;video width=&quot;408&quot; src=&quot;&#x2F;2026&#x2F;Oauth2PasskeyDemo&#x2F;video&#x2F;o2p-2026-03-01_17.11.16-blurred.mp4&quot; controls&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s what happens in the video:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;login page&lt;&#x2F;strong&gt; offers two options: &quot;Register &#x2F; Sign in with Google&quot; and &quot;Sign in with Passkey&quot;.&lt;&#x2F;li&gt;
&lt;li&gt;Clicking &lt;strong&gt;&quot;Register &#x2F; Sign in with Google&quot;&lt;&#x2F;strong&gt; opens the standard Google account chooser and consent screen.&lt;&#x2F;li&gt;
&lt;li&gt;Immediately after Google authentication, the app prompts: &lt;strong&gt;&quot;Create a passkey to sign in?&quot;&lt;&#x2F;strong&gt; — this is the &lt;em&gt;Passkey promotion&lt;&#x2F;em&gt; feature, encouraging OAuth2 users to register a Passkey for faster future logins.&lt;&#x2F;li&gt;
&lt;li&gt;After creating the Passkey, the user lands on the &lt;strong&gt;Dashboard&lt;&#x2F;strong&gt; with links to My Account and Admin Panel.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;strong&gt;My Account&lt;&#x2F;strong&gt; page shows User Information, Passkey Credentials, linked OAuth2 Accounts, and Recent Login History.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The key idea: users start with the familiarity of Google sign-in, then immediately gain the speed and security of Passkeys.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;demo-2-sign-in-with-passkey&quot;&gt;Demo 2: Sign in with Passkey&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;video width=&quot;408&quot; src=&quot;&#x2F;2026&#x2F;Oauth2PasskeyDemo&#x2F;video&#x2F;o2p-2026-03-01_17.12.01-blurred.mp4&quot; controls&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now the same user signs in again, this time with their Passkey:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;On the &lt;strong&gt;login page&lt;&#x2F;strong&gt;, clicking &lt;strong&gt;&quot;Sign in with Passkey&quot;&lt;&#x2F;strong&gt; triggers the browser&#x27;s built-in Passkey dialog.&lt;&#x2F;li&gt;
&lt;li&gt;After biometric verification (fingerprint, face, etc.), the user is &lt;strong&gt;logged in instantly&lt;&#x2F;strong&gt; —no redirect to Google, no password.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;strong&gt;Login History&lt;&#x2F;strong&gt; now shows both the Passkey login and the earlier OAuth2 login, so users can review their full authentication history.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is the daily login experience: fast, phishing-resistant, and free of external dependencies once the Passkey is registered.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;&#x2F;h2&gt;
&lt;p&gt;Try it now: &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Sign in with Google, register a Passkey, then sign in with just the Passkey&lt;&#x2F;li&gt;
&lt;li&gt;Explore the admin panel (all demo users get admin access)&lt;&#x2F;li&gt;
&lt;li&gt;View login history with device and authenticator details&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Data is stored in memory and resets on server restart, so feel free to experiment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-oauth2-passkey&quot;&gt;What is oauth2-passkey?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt; is a Rust library for adding passwordless authentication to web applications. It combines:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OAuth2 (Google)&lt;&#x2F;strong&gt; —One-click registration and login, familiar to users&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Passkeys (WebAuthn&#x2F;FIDO2)&lt;&#x2F;strong&gt; —Phishing-resistant, biometric login (fingerprint, face, security key)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Users sign up with Google, then optionally add a Passkey for faster daily logins. OAuth2 remains available as a fallback if a device is lost.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-start&quot;&gt;Quick Start&lt;&#x2F;h2&gt;
&lt;p&gt;Add oauth2-passkey to your Axum application:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Router&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; routing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;get,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;IntoResponse&lt;&#x2F;span&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; oauth2_passkey_axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AuthUser&lt;&#x2F;span&gt;&lt;span&gt;, oauth2_passkey_full_router};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[tokio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;main]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;dyn&lt;&#x2F;span&gt;&lt;span&gt; std&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    oauth2_passkey_axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; app&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Router&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; get&lt;&#x2F;span&gt;&lt;span&gt;(home))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&#x2F;protected&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; get&lt;&#x2F;span&gt;&lt;span&gt;(protected))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;merge&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;oauth2_passkey_full_router&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; listener&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tokio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;net&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;TcpListener&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;0.0.0.0:3001&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    axum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;serve&lt;&#x2F;span&gt;&lt;span&gt;(listener, app)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.await?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span&gt;(())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; home&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;Welcome! Visit &#x2F;o2p&#x2F;user&#x2F;login to sign in&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; protected&lt;&#x2F;span&gt;&lt;span&gt;(user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; AuthUser&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt; impl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; IntoResponse&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    format!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Hello, {}!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;account)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;oauth2_passkey_full_router()&lt;&#x2F;code&gt; call adds all authentication routes under &lt;code&gt;&#x2F;o2p&#x2F;*&lt;&#x2F;code&gt;, including the login page, OAuth2 flow, Passkey registration and authentication, user account management, and the admin panel.&lt;&#x2F;p&gt;
&lt;p&gt;Set a few environment variables (Google OAuth2 credentials, session secret) and you&#x27;re ready to go. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ktaka-ccmp.github.io&#x2F;oauth2-passkey&#x2F;&quot;&gt;Getting Started guide&lt;&#x2F;a&gt; for details.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Dual auth&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;OAuth2 (Google) + Passkeys in one library&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Built-in UI&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Login page, user account, admin panel&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Passkey promotion&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Prompts OAuth2 users to register a Passkey&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Login history&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Records IP, User-Agent, authenticator details&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Session management&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Secure cookies, conflict policies, force logout&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Admin panel&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;User management, audit trail, admin safeguards&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Theme system&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;9 built-in CSS themes + custom theme support&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Storage&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;SQLite (development) or PostgreSQL (production), with Redis or in-memory caching&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Live demo&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkey-demo.ccmp.jp&quot;&gt;passkey-demo.ccmp.jp&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;oauth2-passkey&quot;&gt;ktaka-ccmp&#x2F;oauth2-passkey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;crates.io&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey&quot;&gt;oauth2-passkey&lt;&#x2F;a&gt; &#x2F; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;oauth2-passkey-axum&quot;&gt;oauth2-passkey-axum&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ktaka-ccmp.github.io&#x2F;oauth2-passkey&#x2F;&quot;&gt;ktaka-ccmp.github.io&#x2F;oauth2-passkey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;&#x2F;h2&gt;
&lt;p&gt;This library grew out of a &lt;a href=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&quot;&gt;from-scratch Passkey implementation&lt;&#x2F;a&gt; I wrote in early 2025. That project gave me a deep understanding of the WebAuthn protocol, and I decided to package the result into a reusable library with OAuth2 integration, session management, and a complete UI.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>GNU Screen ユーザーのための tmux カスタマイズ</title>
        <published>2026-03-01T00:00:00+00:00</published>
        <updated>2026-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2026/TmuxForScreenUsers/"/>
        <id>https://ktaka.blog.ccmp.jp/2026/TmuxForScreenUsers/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2026/TmuxForScreenUsers/">&lt;p&gt;&lt;em&gt;長年 GNU Screen を使ってきたユーザーが tmux に移行する際に、違和感を減らすためのカスタマイズ記録です。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;20 年近く GNU Screen を使ってきました。ターミナルマルチプレクサとしては大きな不満もなく、乗り換える理由はありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;きっかけは Claude Code です。Claude Code はターミナル上で動作する AI コーディングアシスタントですが、Screen 上で使うと表示が崩れる問題がありました。具体的には、テキストの各単語に不正な背景色ブロックが付いて短冊状に表示されたり、起動時の ASCII アートロゴが白いブロックノイズに化けたりします。Screen が、Claude Code の TUI が使用するカラーエスケープシーケンスを正しく処理できていないようです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2026&#x2F;TmuxForScreenUsers&#x2F;image&#x2F;Scrot_screenshot-20260301_044515.png&quot; alt=&quot;Claude Code 起動直後の画面。ロゴが化け、テキストに不正な背景色ブロックが付いている&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2026&#x2F;TmuxForScreenUsers&#x2F;image&#x2F;Scrot_screenshot-20260301_044503.png&quot; alt=&quot;workspace の trust 確認画面。同様に各単語に背景色ブロックが付いている&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;tmux ではこの問題は起きませんでした。Claude Code を快適に使うために、tmux への移行を決めました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;screen-yuzagahu-huo-upointo&quot;&gt;Screen ユーザーが戸惑うポイント&lt;&#x2F;h2&gt;
&lt;p&gt;tmux に移行してまず戸惑ったのが、画面分割まわりの操作体系の違いです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;purehuitukusuki&quot;&gt;プレフィックスキー&lt;&#x2F;h3&gt;
&lt;p&gt;Screen のデフォルトプレフィックスは &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt;、tmux は &lt;code&gt;Ctrl+b&lt;&#x2F;code&gt; です。これは &lt;code&gt;~&#x2F;.tmux.conf&lt;&#x2F;code&gt; で簡単に変更できるので、すぐに解決しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hua-mian-fen-ge-nokao-efang-gawei-u&quot;&gt;画面分割の考え方が違う&lt;&#x2F;h3&gt;
&lt;p&gt;Screen の特徴として、「リージョン」と「ウィンドウ」が明確に分かれています。&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;S&lt;&#x2F;code&gt; で画面をリージョン分割し、各リージョンに既存のウィンドウを割り当てます。リージョンを閉じてもウィンドウ（シェル）は残ります。&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt; でリージョンを全解除して元の 1 画面に戻す、というのがよくある使い方でした。&lt;&#x2F;p&gt;
&lt;p&gt;tmux では「ペイン」がこれに相当しますが、ペインを作ると新しいシェルが自動起動します。Screen のように「画面を分割してから既存のウィンドウを割り当てる」という手順ではなく、「分割と同時に新しいシェルが生まれる」という動作です。&lt;&#x2F;p&gt;
&lt;p&gt;また、Screen の &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt;（リージョン全解除）に直接対応するキーがありません。tmux では &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;z&lt;&#x2F;code&gt; でペインをズーム（全画面化）するのが近い感覚ですが、他のペインを閉じるわけではないので挙動が異なります。&lt;&#x2F;p&gt;
&lt;p&gt;ペインを独立したウィンドウに戻したい場合は &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;!&lt;&#x2F;code&gt;（break-pane）で 1 つずつ分離する必要があります。複数ペインを一括で分離するコマンドはデフォルトにはありません。&lt;&#x2F;p&gt;
&lt;p&gt;こういった違いに戸惑うことが多かったので、Screen ユーザーが直感的に使えるキーバインドをカスタマイズしました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;tmux-conf&quot;&gt;~&#x2F;.tmux.conf&lt;&#x2F;h2&gt;
&lt;p&gt;以下がカスタマイズした設定です。カスタムキーバインドに加えて、デフォルトのよく使うキーバインドもコメントでチートシートとして埋め込んでいます。設定ファイル自体がリファレンスになるようにしています。&lt;&#x2F;p&gt;
&lt;p&gt;設定を変更した後は、tmux 内で &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;:&lt;&#x2F;code&gt; を押してコマンドモードに入り、&lt;code&gt;source-file ~&#x2F;.tmux.conf&lt;&#x2F;code&gt; と入力するか、シェルから &lt;code&gt;tmux source-file ~&#x2F;.tmux.conf&lt;&#x2F;code&gt; を実行すると反映されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Custom keybindings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use Ctrl+a as prefix (same as GNU Screen)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;unbind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; C-b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; prefix C-a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; a: Send literal Ctrl+a to the terminal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; a send-prefix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Enable mouse for pane resizing, selection, and scrolling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mouse on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; -: Split pane horizontally (top&#x2F;bottom)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; - split-window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; |: Split pane vertically (left&#x2F;right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; split-window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; @: Pull a pane from another window&#x2F;session (interactive)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; @ choose-tree &amp;quot;join-pane -s &amp;#39;%%&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; S: Send current pane to another window&#x2F;session (interactive)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; S choose-tree &amp;quot;join-pane -t &amp;#39;%%&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Q: Break all panes into separate windows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Q run-shell &amp;#39;while [ $(tmux list-panes | wc -l) -gt 1 ]; do tmux break-pane -d; done&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Cheat sheet (default keybindings)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane navigation ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Arrow keys: Move between panes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; o: Move to next pane&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; q: Display pane numbers (press number to jump)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; z: Toggle pane zoom (fullscreen)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane resizing ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Ctrl+Arrow keys: Resize pane by 1 cell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Alt+Arrow keys: Resize pane by 5 cells&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Mouse drag on pane border: Resize interactively&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane arrangement ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; {: Swap pane forward (up&#x2F;left)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; }: Swap pane backward (down&#x2F;right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Space: Cycle through layouts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane&#x2F;window management ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; !: Break current pane into a separate window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Window navigation ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; c: Create new window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; n: Next window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; p: Previous window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; 0-9: Jump to window by number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; w: List all windows&#x2F;sessions (interactive tree)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Session navigation ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; s: List sessions (interactive selection)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; (: Previous session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; ): Next session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Cross-session window management (via command mode: Ctrl+a -&amp;gt; :) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# move-window -t session_name:        Move current window to another session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# link-window -s session_name:N       Share a window across sessions (same window, multiple sessions)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# unlink-window                       Remove shared window from current session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;kasutamukibaindonojie-shuo&quot;&gt;カスタムキーバインドの解説&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;purehuitukusunobian-geng-ctrl-a&quot;&gt;プレフィックスの変更（&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt;）&lt;&#x2F;h3&gt;
&lt;p&gt;Screen と同じ &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; をプレフィックスにしています。&lt;code&gt;bind a send-prefix&lt;&#x2F;code&gt; で、&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;a&lt;&#x2F;code&gt; と押せば端末に素の &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt;（行頭移動など）を送れます。これも Screen と同じ挙動です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;peinfen-ge-to&quot;&gt;ペイン分割（&lt;code&gt;-&lt;&#x2F;code&gt; と &lt;code&gt;|&lt;&#x2F;code&gt;）&lt;&#x2F;h3&gt;
&lt;p&gt;tmux のデフォルトでは &lt;code&gt;&quot;&lt;&#x2F;code&gt; で横分割、&lt;code&gt;%&lt;&#x2F;code&gt; で縦分割ですが、少し覚えにくいと感じました。&lt;code&gt;-&lt;&#x2F;code&gt;（横線）で横分割、&lt;code&gt;|&lt;&#x2F;code&gt;（縦線）で縦分割にしています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;peinnoqu-riip-mitosong-richu-si-to-s&quot;&gt;ペインの取り込みと送り出し（&lt;code&gt;@&lt;&#x2F;code&gt; と &lt;code&gt;S&lt;&#x2F;code&gt;）&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;@&lt;&#x2F;code&gt; は別のウィンドウやセッションからペインを現在のウィンドウに取り込みます。&lt;code&gt;S&lt;&#x2F;code&gt; は現在のペインを別のウィンドウやセッションに送ります。いずれもインタラクティブなツリー表示から選択できます。&lt;&#x2F;p&gt;
&lt;p&gt;なお、Screen では &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;S&lt;&#x2F;code&gt; は横分割（リージョン分割）です。この設定ではその機能を &lt;code&gt;-&lt;&#x2F;code&gt; に移しているため、&lt;code&gt;S&lt;&#x2F;code&gt; を「ペイン送り出し」に再割り当てしています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;quan-peinfen-li-q&quot;&gt;全ペイン分離（&lt;code&gt;Q&lt;&#x2F;code&gt;）&lt;&#x2F;h3&gt;
&lt;p&gt;Screen の &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt;（リージョン全解除）に近い操作です。現在のウィンドウにある全ペインをそれぞれ独立したウィンドウに分離します。「分割して作業した後、元の 1 ペイン 1 ウィンドウの状態に戻したい」という Screen 的な使い方ができます。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;kibaindoyi-lan&quot;&gt;キーバインド一覧&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;kasutamushe-ding&quot;&gt;カスタム設定&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;キー&lt;&#x2F;th&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;プレフィックス（Screen と同じ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;a&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;端末に素の Ctrl+a を送る&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;-&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;横分割（上下）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;|&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;縦分割（左右）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;@&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;別ウィンドウ&#x2F;セッションからペインを取り込む&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;S&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;現在のペインを別ウィンドウ&#x2F;セッションに送る&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;!&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;現在のペインを独立ウィンドウにする（デフォルト）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;全ペインを独立ウィンドウにバラす&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;マウス&lt;&#x2F;td&gt;&lt;td&gt;ペイン境界ドラッグでリサイズ、選択、スクロール&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;dehuorutokibaindo-yokushi-umono&quot;&gt;デフォルトキーバインド（よく使うもの）&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;ペイン操作&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;キー&lt;&#x2F;th&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → 矢印キー&lt;&#x2F;td&gt;&lt;td&gt;ペイン間移動&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;o&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;次のペインに移動&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;q&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ペイン番号表示（番号押下でジャンプ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;z&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ペインのズーム切替（全画面）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Space&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;レイアウト順次切替&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;ウィンドウ操作&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;キー&lt;&#x2F;th&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;c&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;新規ウィンドウ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;n&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;p&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;次&#x2F;前のウィンドウ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;0-9&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ウィンドウ番号でジャンプ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;w&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ウィンドウ&#x2F;セッション一覧（ツリー表示）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;セッション操作&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;キー&lt;&#x2F;th&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;s&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;セッション一覧&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;(&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;)&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;前&#x2F;次のセッション&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;d&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;デタッチ（セッションを残して切断）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;detatutitoatatuti&quot;&gt;デタッチとアタッチ&lt;&#x2F;h3&gt;
&lt;p&gt;ターミナルマルチプレクサの最も基本的な機能であるデタッチ&#x2F;アタッチは、Screen と tmux でほぼ同じです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;th&gt;Screen&lt;&#x2F;th&gt;&lt;th&gt;tmux&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;デタッチ&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;d&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;d&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;セッション一覧&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;screen -ls&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;tmux ls&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;アタッチ&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;screen -r&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;tmux attach&lt;&#x2F;code&gt; (&lt;code&gt;tmux a&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;名前付きセッション作成&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;screen -S name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;tmux new -s name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;名前指定でアタッチ&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;screen -r name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;tmux attach -t name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Screen ユーザーにとって最も馴染みのある操作なので、ここは移行のハードルが低いポイントです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;screen-tonogai-nian-nodui-ying&quot;&gt;Screen との概念の対応&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Screen&lt;&#x2F;th&gt;&lt;th&gt;tmux&lt;&#x2F;th&gt;&lt;th&gt;備考&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;リージョン&lt;&#x2F;td&gt;&lt;td&gt;ペイン&lt;&#x2F;td&gt;&lt;td&gt;tmux はペイン作成時にシェルが自動起動する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ウィンドウ&lt;&#x2F;td&gt;&lt;td&gt;ウィンドウ&lt;&#x2F;td&gt;&lt;td&gt;ほぼ同じ概念&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;（なし）&lt;&#x2F;td&gt;&lt;td&gt;セッション&lt;&#x2F;td&gt;&lt;td&gt;Screen にもセッション概念はあるが、tmux の方がセッション管理が強力&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt; (リージョン全解除)&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;Q&lt;&#x2F;code&gt; (全ペイン分離、カスタム)&lt;&#x2F;td&gt;&lt;td&gt;デフォルトの &lt;code&gt;z&lt;&#x2F;code&gt;（ズーム）は一時的な全画面化でペインが残る。カスタム &lt;code&gt;Q&lt;&#x2F;code&gt; で Screen に近い挙動を再現&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;S&lt;&#x2F;code&gt; (横分割)&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;-&lt;&#x2F;code&gt; (カスタム)&lt;&#x2F;td&gt;&lt;td&gt;デフォルトは &lt;code&gt;&quot;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;tmux 固有の便利な機能として、&lt;code&gt;link-window&lt;&#x2F;code&gt; で同じウィンドウを複数セッションから共有できます。これは Screen にはない機能です。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;kopi-pesutoto-os-kuritupubodolian-xi&quot;&gt;コピー＆ペーストと OS クリップボード連携&lt;&#x2F;h2&gt;
&lt;p&gt;tmux のコピーバッファと OS のクリップボードは、デフォルトでは連携していないようです。tmux 内でコピーしても OS 側に反映されません。また、&lt;code&gt;mouse on&lt;&#x2F;code&gt; にしていると tmux がマウスイベントを横取りするため、右クリックメニューからのコピペも効きません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;osc-52-niyorujie-jue&quot;&gt;OSC 52 による解決&lt;&#x2F;h3&gt;
&lt;p&gt;OSC 52 はターミナルのエスケープシーケンスを使ってクリップボードにアクセスする仕組みです。xclip などの外部ツールは不要で、SSH 越しでも動作します。&lt;&#x2F;p&gt;
&lt;p&gt;ターミナルエミュレータ側（Alacritty の例）:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;terminal&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;osc52 =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;CopyPaste&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;tmux 側（&lt;code&gt;~&#x2F;.tmux.conf&lt;&#x2F;code&gt;）:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set-clipboard on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mode-keys vi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; history-limit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;set-clipboard on&lt;&#x2F;code&gt; は tmux 3.2 以降ではデフォルトで有効ですが、明示しておくと意図が明確になります。&lt;code&gt;mode-keys vi&lt;&#x2F;code&gt; はコピーモードのキー操作を vi 式にします（hjkl 移動、&lt;code&gt;&#x2F;&lt;&#x2F;code&gt; で検索など）。vi に馴染みがなければこの行を省略すれば emacs 式（デフォルト）のままで、OSC 52 によるクリップボード連携は同様に動作します。&lt;code&gt;history-limit&lt;&#x2F;code&gt; はスクロールバックの行数です（デフォルトは 2000 行）。&lt;&#x2F;p&gt;
&lt;p&gt;これだけで tmux のコピーが OS クリップボードに反映されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kopicao-zuo&quot;&gt;コピー操作&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;[&lt;&#x2F;code&gt; — コピーモードに入る&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Space&lt;&#x2F;code&gt; — 選択開始&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Enter&lt;&#x2F;code&gt; — コピー（OS クリップボードにも入る）&lt;&#x2F;li&gt;
&lt;li&gt;通常の &lt;code&gt;Ctrl+v&lt;&#x2F;code&gt; や中クリックで貼り付け&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;tmux 内で貼り付ける場合は &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;]&lt;&#x2F;code&gt; です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;shift-kide-tmux-wobaipasu&quot;&gt;Shift キーで tmux をバイパス&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Shift&lt;&#x2F;code&gt; を押しながら操作すると tmux をバイパスしてターミナルエミュレータ側の操作になります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Shift&lt;&#x2F;code&gt; + ドラッグ: ターミナル側の選択&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Shift&lt;&#x2F;code&gt; + 右クリック: ターミナルのコンテキストメニュー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Shift&lt;&#x2F;code&gt; + 中クリック &#x2F; &lt;code&gt;Shift+Ctrl+V&lt;&#x2F;code&gt;: 貼り付け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;screen-tonobi-jiao&quot;&gt;Screen との比較&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;操作&lt;&#x2F;th&gt;&lt;th&gt;Screen&lt;&#x2F;th&gt;&lt;th&gt;tmux (この設定)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;コピーモード開始&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;[&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;[&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;選択開始&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Enter&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Space&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;コピー&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Enter&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Enter&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;貼り付け&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;]&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; → &lt;code&gt;]&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;OS クリップボード連携&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;OSC 52 で自動連携&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;コピーモードの基本操作は Screen とほぼ同じです。大きな違いは OS クリップボードとの連携で、Screen にはこの機能がありませんでした。tmux + OSC 52 対応ターミナルの組み合わせでは、コピーした内容がそのまま OS のクリップボードに入るため、ブラウザや他のアプリケーションにそのまま貼り付けられます。&lt;&#x2F;p&gt;
&lt;p&gt;なお、OSC 52 対応はターミナルエミュレータに依存します。Alacritty、Ghostty、WezTerm、iTerm2、Windows Terminal などは対応していますが、xfce4-terminal は未対応です。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;wan-quan-na-tmux-conf&quot;&gt;完全な ~&#x2F;.tmux.conf&lt;&#x2F;h2&gt;
&lt;p&gt;記事中で紹介した設定をまとめた完全版です。コピー＆ペーストしてそのまま使えます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Prefix key (same as GNU Screen)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;unbind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; C-b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; prefix C-a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; a send-prefix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# General settings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mouse on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set-clipboard on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mode-keys vi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; history-limit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Custom keybindings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pane splitting: - for horizontal, | for vertical&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; - split-window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; split-window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pull a pane from another window&#x2F;session (interactive)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; @ choose-tree &amp;quot;join-pane -s &amp;#39;%%&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Send current pane to another window&#x2F;session (interactive)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; S choose-tree &amp;quot;join-pane -t &amp;#39;%%&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Break all panes into separate windows (like Screen&amp;#39;s Ctrl+a -&amp;gt; Q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Q run-shell &amp;#39;while [ $(tmux list-panes | wc -l) -gt 1 ]; do tmux break-pane -d; done&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Cheat sheet (default keybindings)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane navigation ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Arrow keys: Move between panes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; o: Move to next pane&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; q: Display pane numbers (press number to jump)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; z: Toggle pane zoom (fullscreen)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane resizing ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Ctrl+Arrow keys: Resize pane by 1 cell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Alt+Arrow keys: Resize pane by 5 cells&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Mouse drag on pane border: Resize interactively&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane arrangement ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; {: Swap pane forward (up&#x2F;left)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; }: Swap pane backward (down&#x2F;right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; Space: Cycle through layouts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Pane&#x2F;window management ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; !: Break current pane into a separate window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Window navigation ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; c: Create new window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; n: Next window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; p: Previous window&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; 0-9: Jump to window by number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; w: List all windows&#x2F;sessions (interactive tree)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Session ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; d: Detach from session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; s: List sessions (interactive selection)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; (: Previous session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; ): Next session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Cross-session window management (via command mode: Ctrl+a -&amp;gt; :) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# move-window -t session_name:        Move current window to another session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# link-window -s session_name:N       Share a window across sessions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# unlink-window                       Remove shared window from current session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Copy mode ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; [: Enter copy mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Space: Start selection (vi mode) &#x2F; Ctrl+Space (emacs mode)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Enter: Copy selection (also copies to OS clipboard via OSC 52)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ctrl+a -&amp;gt; ]: Paste from tmux buffer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Screen から tmux への移行で最も戸惑ったのは、ペイン分割まわりの操作体系の違いでした。Screen の「リージョンを分割・解除する」という考え方と、tmux の「ペインを作る・ズームする」という考え方はアプローチが異なります。&lt;&#x2F;p&gt;
&lt;p&gt;今回のカスタマイズでは、プレフィックスの変更に加えて、&lt;code&gt;Q&lt;&#x2F;code&gt;（全ペイン分離）や &lt;code&gt;@&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;S&lt;&#x2F;code&gt;（ペインの取り込み・送り出し）を追加することで、Screen 的なワークフローを tmux 上で再現できるようにしました。&lt;&#x2F;p&gt;
&lt;p&gt;移行のきっかけは Claude Code の表示崩れという消極的な理由でしたが、使ってみると tmux のセッション管理やペインの柔軟さは Screen より優れていると感じます。OSC 52 によるクリップボード連携など、tmux ならではの利点もあり、長年の慣れを差し引いても移行してよかったと感じています。Screen に慣れている方は、まずプレフィックスを &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; に変えるだけでも移行のハードルはかなり下がると思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Blogspot の記事を Zola + GitHub Pages に移行した</title>
        <published>2026-02-24T00:00:00+00:00</published>
        <updated>2026-02-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2026/BlogspotToZola/"/>
        <id>https://ktaka.blog.ccmp.jp/2026/BlogspotToZola/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2026/BlogspotToZola/">&lt;p&gt;&lt;em&gt;2008 年から書いてきた Blogspot の 107 記事を、Zola + GitHub Pages に一括移行した記録です。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;個人ブログを Google Blogspot から GitHub Pages に移行しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;2026&#x2F;GcpToGitHubPages&quot;&gt;前回の記事&lt;&#x2F;a&gt;ではコーポレートサイト（ccmp.jp）の GCP → GitHub Pages 移行を紹介しましたが、今回はその続きとして、個人ブログ（ktaka.blog.ccmp.jp）の Blogspot → GitHub Pages 移行についてまとめます。&lt;&#x2F;p&gt;
&lt;p&gt;移行の全体像は次の通りです:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GitHub Pages の立ち上げ&lt;&#x2F;strong&gt; — pandoc + GitHub Actions でまず公開&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Zola 導入&lt;&#x2F;strong&gt; — 静的サイトジェネレーターに切り替え&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Blogspot 全記事の移行&lt;&#x2F;strong&gt; — 107 記事を一括変換&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ドメイン切替&lt;&#x2F;strong&gt; — Blogspot と同じドメインで GitHub Pages を公開&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;yi-xing-nobei-jing&quot;&gt;移行の背景&lt;&#x2F;h2&gt;
&lt;p&gt;Blogspot は手軽にブログを始められるサービスですが、技術ブログとして使い続けるにはいくつかの不満がありました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Markdown で書けない&lt;&#x2F;strong&gt;: HTML エディタが基本で、シンタックスハイライトもない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;変更履歴が残らない&lt;&#x2F;strong&gt;: Git のような差分確認やロールバックができない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;カスタマイズが面倒&lt;&#x2F;strong&gt;: テンプレートの自由度が低く、何か変えたいときに Blogger の作法を毎回調べ直す必要がある&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;そして何より、ブログを書こうと思っても、Blogger のエディタを開いて HTML を調整する作業が億劫で、記事を書くモチベーションが上がらないことが一番の問題でした。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、GitHub Pages + Zola なら:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Markdown でそのまま入稿&lt;&#x2F;li&gt;
&lt;li&gt;シンタックスハイライト標準搭載&lt;&#x2F;li&gt;
&lt;li&gt;テンプレートを完全に自作可能&lt;&#x2F;li&gt;
&lt;li&gt;コンテンツを Git で管理（変更履歴・ロールバック）&lt;&#x2F;li&gt;
&lt;li&gt;ローカルプレビューが &lt;code&gt;zola serve&lt;&#x2F;code&gt; 一発&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;phase-1-github-pages-noli-tishang-ge&quot;&gt;Phase 1: GitHub Pages の立ち上げ&lt;&#x2F;h2&gt;
&lt;p&gt;まず、既存の Markdown 記事を GitHub Pages で公開するところから始めました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pandoc-github-actions-gou-cheng&quot;&gt;pandoc + GitHub Actions 構成&lt;&#x2F;h3&gt;
&lt;p&gt;GitHub Actions ワークフロー（&lt;code&gt;.github&#x2F;workflows&#x2F;pages.yml&lt;&#x2F;code&gt;）を作成し、pandoc で Markdown → HTML 変換 + GitHub Pages デプロイを自動化しました。DNS CNAME レコードとカスタムドメイン設定で &lt;code&gt;kt.blog.ccmp.jp&lt;&#x2F;code&gt; として暫定公開しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;konogou-cheng-noke-ti&quot;&gt;この構成の課題&lt;&#x2F;h3&gt;
&lt;p&gt;動くことは動きましたが、運用面で問題がありました:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;記事追加ごとに YAML 手動編集&lt;&#x2F;strong&gt;: &lt;code&gt;mkdir&lt;&#x2F;code&gt;、&lt;code&gt;pandoc&lt;&#x2F;code&gt; コマンド、index 更新を毎回ワークフローに追加する必要がある&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ローカルプレビューが手動&lt;&#x2F;strong&gt;: pandoc を手で実行してブラウザで開く&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TOC 生成が外部ツール依存&lt;&#x2F;strong&gt;: &lt;code&gt;gh-md-toc&lt;&#x2F;code&gt; を別途実行&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;シンタックスハイライトなし&lt;&#x2F;strong&gt;: pandoc のデフォルトでは対応していない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;RSS&#x2F;サイトマップなし&lt;&#x2F;strong&gt;: 手動構成では現実的でない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;記事が 10 本程度のうちは何とかなりますが、Blogspot の 100 本以上の記事を移行するには、この構成では限界がありました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;phase-2-zola-dao-ru&quot;&gt;Phase 2: Zola 導入&lt;&#x2F;h2&gt;
&lt;p&gt;pandoc 手動構成の限界を解消するため、静的サイトジェネレーター Zola を導入しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zola-woxuan-ndali-you&quot;&gt;Zola を選んだ理由&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;pandoc 手動構成&lt;&#x2F;th&gt;&lt;th&gt;Zola 導入後&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;記事追加&lt;&#x2F;td&gt;&lt;td&gt;YAML 手動編集&lt;&#x2F;td&gt;&lt;td&gt;MD ファイル作成のみ（自動検出）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ローカルプレビュー&lt;&#x2F;td&gt;&lt;td&gt;pandoc 手動実行&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;zola serve&lt;&#x2F;code&gt;（ライブリロード）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TOC&lt;&#x2F;td&gt;&lt;td&gt;外部ツール&lt;&#x2F;td&gt;&lt;td&gt;標準搭載&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;シンタックスハイライト&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;標準搭載（syntect）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RSS&#x2F;Atom&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;自動生成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;多言語&lt;&#x2F;td&gt;&lt;td&gt;手動リンク管理&lt;&#x2F;td&gt;&lt;td&gt;標準搭載（&lt;code&gt;index.en.md&lt;&#x2F;code&gt; で自動認識）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Zola は Rust 製の単一バイナリで、依存関係なしでインストールできます。Hugo や Jekyll と比べてエコシステムは小さいですが、必要な機能は揃っていました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jian-zheng-xiang-mu&quot;&gt;検証項目&lt;&#x2F;h3&gt;
&lt;p&gt;導入前に以下を検証し、全項目をクリアしました:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;検証項目&lt;&#x2F;th&gt;&lt;th&gt;結果&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ビルド・ローカルプレビュー&lt;&#x2F;td&gt;&lt;td&gt;OK（&lt;code&gt;zola serve&lt;&#x2F;code&gt; でライブリロード対応）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;URL パス保持&lt;&#x2F;td&gt;&lt;td&gt;OK（&lt;code&gt;path&lt;&#x2F;code&gt; front matter で任意のパスを指定可能）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;多言語対応&lt;&#x2F;td&gt;&lt;td&gt;OK（&lt;code&gt;index.en.md&lt;&#x2F;code&gt; で自動認識）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;画像・動画の扱い&lt;&#x2F;td&gt;&lt;td&gt;OK（&lt;code&gt;content&#x2F;&lt;&#x2F;code&gt; 内に同居、相対パス参照）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;シンタックスハイライト&lt;&#x2F;td&gt;&lt;td&gt;OK（github-dark テーマ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Atom フィード&lt;&#x2F;td&gt;&lt;td&gt;OK（自動生成）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;tenpuretozi-zuo&quot;&gt;テンプレート自作&lt;&#x2F;h3&gt;
&lt;p&gt;既存のテーマは使わず、4 種のテンプレートを自作しました:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;base.html&lt;&#x2F;strong&gt; — 共通レイアウト（ナビゲーション、CSS）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;index.html&lt;&#x2F;strong&gt; — トップページ（セクション一覧へリダイレクト）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;section.html&lt;&#x2F;strong&gt; — 記事一覧（日付降順）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;page.html&lt;&#x2F;strong&gt; — 記事本文（TOC、前後ナビ、ライトボックス）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;CSS は &lt;code&gt;github-markdown.css&lt;&#x2F;code&gt; をベースにしており、最小限のスタイルで十分な表示品質を実現しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;yi-xing-noshi-shi&quot;&gt;移行の実施&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;既存の 11 記事を Zola 形式に変換（TOML front matter 追加、手動 TOC 削除）&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Actions を pandoc → &lt;code&gt;zola build&lt;&#x2F;code&gt; に更新&lt;&#x2F;li&gt;
&lt;li&gt;旧ファイル（&lt;code&gt;gh-md-toc&lt;&#x2F;code&gt;、ルート CSS、pandoc ワークフロー）を削除&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;phase-3-blogspot-quan-ji-shi-noyi-xing&quot;&gt;Phase 3: Blogspot 全記事の移行&lt;&#x2F;h2&gt;
&lt;p&gt;Zola の基盤が整ったところで、Blogspot の全記事を移行しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ekusupototobian-huan&quot;&gt;エクスポートと変換&lt;&#x2F;h3&gt;
&lt;p&gt;Blogspot の記事データは Google Takeout でエクスポートしました。Blogger の管理画面からの XML エクスポートではなく、Google Takeout を使ったのは、HTML 形式で各記事が個別ファイルとして取得できるためです。&lt;&#x2F;p&gt;
&lt;p&gt;変換は Python スクリプトで自動化しました:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Google Takeout (HTML) → Python スクリプト → Zola 用 Markdown + 画像&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;スクリプトが行う処理:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;HTML ファイルの解析&lt;&#x2F;li&gt;
&lt;li&gt;TOML front matter の自動生成（title, date, path）&lt;&#x2F;li&gt;
&lt;li&gt;HTML → Markdown 変換&lt;&#x2F;li&gt;
&lt;li&gt;画像ファイルのローカルコピーとパス書き換え&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;content&#x2F;{year}&#x2F;{slug}&#x2F;index.md&lt;&#x2F;code&gt; として出力&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;pei-zhi-gou-zao&quot;&gt;配置構造&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;content&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2008&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    first-post&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      index.md        # 記事本文（Markdown + TOML front matter）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      image&#x2F;           # 画像&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        photo.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    second-post&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      index.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2009&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2024&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;107 記事（うち 1 記事は &lt;code&gt;draft = true&lt;&#x2F;code&gt;）を年別ディレクトリに配置しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pin-zhi-jian-zheng&quot;&gt;品質検証&lt;&#x2F;h3&gt;
&lt;p&gt;自動変換した記事の品質を確認するため、Claude Code を使って全 104 記事（draft 除く）を本番 Blogspot サイトと 1 記事ずつ比較しました。各記事について WebFetch で本番ページを取得し、ローカルの Markdown と突き合わせる作業を並列エージェントで実行しています。&lt;&#x2F;p&gt;
&lt;p&gt;結果:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;100 記事&lt;&#x2F;strong&gt;: 問題なし&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;4 記事を修正&lt;&#x2F;strong&gt;:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;記事&lt;&#x2F;th&gt;&lt;th&gt;問題&lt;&#x2F;th&gt;&lt;th&gt;対応&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;2011&#x2F;blog-post&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;画像 2 枚が未取得&lt;&#x2F;td&gt;&lt;td&gt;Blogger CDN からダウンロード（WebP）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;2011&#x2F;hhkb-pro2&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;画像 1 枚が未取得&lt;&#x2F;td&gt;&lt;td&gt;Blogger CDN からダウンロード（WebP）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;2011&#x2F;galaxy-blogger&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;画像 1 枚が消失&lt;&#x2F;td&gt;&lt;td&gt;Blogger CDN から消失、復元不可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;2011&#x2F;gnu-tar124ok&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;変換アーティファクト&lt;&#x2F;td&gt;&lt;td&gt;空 blockquote・空コードブロックを除去&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Blogger CDN から消失していた画像が 1 枚ありましたが、それ以外は全記事を正常に移行できました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;phase-4-domeinqie-ti&quot;&gt;Phase 4: ドメイン切替&lt;&#x2F;h2&gt;
&lt;p&gt;コンテンツ移行の完了後、ドメインを切り替えました。&lt;&#x2F;p&gt;
&lt;p&gt;Blogspot で使っていたドメイン &lt;code&gt;ktaka.blog.ccmp.jp&lt;&#x2F;code&gt; を、そのまま GitHub Pages に向け替えました:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Blogspot 管理画面でカスタムドメイン（&lt;code&gt;ktaka.blog.ccmp.jp&lt;&#x2F;code&gt;）を解除&lt;&#x2F;li&gt;
&lt;li&gt;DNS CNAME を &lt;code&gt;ktaka-ccmp.github.io&lt;&#x2F;code&gt; に変更&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Pages のカスタムドメイン設定を更新&lt;&#x2F;li&gt;
&lt;li&gt;Zola の &lt;code&gt;config.toml&lt;&#x2F;code&gt;（&lt;code&gt;base_url&lt;&#x2F;code&gt;）と &lt;code&gt;static&#x2F;CNAME&lt;&#x2F;code&gt; を更新&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;暫定ドメイン &lt;code&gt;kt.blog.ccmp.jp&lt;&#x2F;code&gt; は廃止しました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;移行前（Blogspot）&lt;&#x2F;th&gt;&lt;th&gt;移行後（Zola + GitHub Pages）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;入稿形式&lt;&#x2F;td&gt;&lt;td&gt;HTML エディタ&lt;&#x2F;td&gt;&lt;td&gt;Markdown&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;シンタックスハイライト&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;あり（github-dark）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;プレビュー&lt;&#x2F;td&gt;&lt;td&gt;Blogger のプレビュー機能&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;zola serve&lt;&#x2F;code&gt;（ローカルでライブリロード）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;バージョン管理&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;Git&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;画像ホスト&lt;&#x2F;td&gt;&lt;td&gt;Blogger CDN&lt;&#x2F;td&gt;&lt;td&gt;リポジトリ内（Git 管理）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;カスタマイズ&lt;&#x2F;td&gt;&lt;td&gt;テンプレート制約あり&lt;&#x2F;td&gt;&lt;td&gt;完全自作テンプレート&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RSS&#x2F;Atom&lt;&#x2F;td&gt;&lt;td&gt;Blogger 独自形式&lt;&#x2F;td&gt;&lt;td&gt;Zola 自動生成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ホスティングコスト&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;大方の移行作業は 2 日間で完了しました。最も時間がかかったのは Blogspot 全記事の品質検証（104 記事の 1 対 1 比較）ですが、これは Claude Code の並列エージェントに任せたので、待ち時間が大半でした。&lt;&#x2F;p&gt;
&lt;p&gt;今まではブログを書こうと思っても、Blogger のエディタを開いて HTML を調整する作業が面倒で、かなり億劫に感じていました。Markdown なら文章を書くことに集中でき、それがそのままブログに変換されて CDN 配信されるので、記事を書くハードルがかなり下がりました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>9年前に Joomla + wget で静的化したサイトを GitHub Pages へ移行した</title>
        <published>2026-02-15T00:00:00+00:00</published>
        <updated>2026-02-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2026/GcpToGitHubPages/"/>
        <id>https://ktaka.blog.ccmp.jp/2026/GcpToGitHubPages/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2026/GcpToGitHubPages/">&lt;p&gt;&lt;em&gt;Joomla CMS + wget による静的サイト生成パイプラインが、ホスティング移行をシンプルにしてくれた事例です。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;自社のコーポレートサイト（ccmp.jp）を、GCP 上の VM + Cloud Load Balancer + Cloud CDN 構成から GitHub Pages に移行しました。&lt;&#x2F;p&gt;
&lt;p&gt;もともと GitHub の有料プラン（Team）でリポジトリを管理していたため、GitHub Pages への移行で GCP 側の月額約 $23 のホスティングコストをまるごと削減できました。&lt;&#x2F;p&gt;
&lt;p&gt;移行がスムーズにいった最大の要因は、もともと Joomla CMS で入稿しつつ、配信は静的 HTML で行う構成を採っていたことでした。ホスティング先が変わっても、入稿ワークフローには一切手を入れる必要がありませんでした。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;yi-xing-nobei-jing&quot;&gt;移行の背景&lt;&#x2F;h2&gt;
&lt;p&gt;現在の GCP 構成は 9 年前に構築したものです。当時としては、将来的な拡張性も考慮した妥当な設計でした。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、この 9 年の間に状況は変わりました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;VM の OS アップデート対応が地味に負担&lt;&#x2F;li&gt;
&lt;li&gt;Terraform で再構築できるとはいえ、「本当に今も動くのか」という心理的な不安&lt;&#x2F;li&gt;
&lt;li&gt;静的サイト配信の選択肢が大きく増えた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;実際の運用では動的機能を追加することはなく、静的配信のみが続いていました。「この規模のサイトに VM は本当に必要だろうか？」と考えるようになったのが、今回の移行のきっかけです。&lt;&#x2F;p&gt;
&lt;p&gt;なお、CMS として Joomla を使っているのは歴史的経緯によるものです。非エンジニアによる入稿を目的として 20 年近く継続利用してきました。9 年前にはすでに、CMS の本番公開をやめて &lt;code&gt;wget&lt;&#x2F;code&gt; による静的化へ移行していました。この「入稿と配信の分離」が、今回のホスティング移行を容易にしてくれました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;yi-xing-qian-nogou-cheng-joomla-cms-gcp&quot;&gt;移行前の構成: Joomla CMS + GCP&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;cms-ru-gao-jing-de-html-sheng-cheng-toiuakitekutiya&quot;&gt;CMS 入稿 → 静的 HTML 生成というアーキテクチャ&lt;&#x2F;h3&gt;
&lt;p&gt;コーポレートサイトのコンテンツは Joomla CMS で管理しています。ただし、Joomla を本番サーバで動かしているわけではありません。入稿から配信までの流れは次のようになっています:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Joomla CMS] → wget でクローリング → 静的 HTML 生成 → GitHub リポジトリに push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                          ↓&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                  本番サーバで git pull → nginx 配信&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;入稿&lt;&#x2F;strong&gt;: ローカル環境の Joomla CMS で記事を作成・編集&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;静的化&lt;&#x2F;strong&gt;: &lt;code&gt;wget&lt;&#x2F;code&gt; で CMS の出力をクローリングし、静的 HTML ファイルとして &lt;code&gt;localhost&#x2F;&lt;&#x2F;code&gt; ディレクトリに出力&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;デプロイ&lt;&#x2F;strong&gt;: 生成した HTML を GitHub リポジトリにマージし、GCP VM 上で &lt;code&gt;git pull&lt;&#x2F;code&gt; → nginx で配信&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;本番環境には PHP も MySQL も不要で、純粋な静的ファイル配信のみでした。前段に Cloud Load Balancer と Cloud CDN を配置し、キャッシュによるレスポンス高速化と VM への負荷軽減を行っていました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;konoakitekutiyanomerituto&quot;&gt;このアーキテクチャのメリット&lt;&#x2F;h3&gt;
&lt;p&gt;この「CMS で入稿、配信は静的 HTML」というアーキテクチャには、当初から以下のメリットがありました:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;入稿者にやさしい&lt;&#x2F;strong&gt;: 記事の作成・編集は Joomla の WYSIWYG エディタで行えます。Markdown や HTML を直接書く必要がなく、非エンジニアでも入稿できます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;CMS の便利さを維持しつつ脆弱性を排除&lt;&#x2F;strong&gt;: Joomla や WordPress などの CMS は頻繁に脆弱性が報告され、攻撃の標的になりがちです。しかしこの構成では CMS はローカル環境でのみ動作し、本番には PHP も MySQL も存在しません。入稿者は CMS の WYSIWYG エディタやテンプレート機能をそのまま使えますが、攻撃者から見える本番環境は単なる静的ファイルだけです。CMS の利便性とセキュリティを両立できます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ホスティングの自由度が高い&lt;&#x2F;strong&gt;: 配信するのは単なる静的ファイルなので、ホスティング先を自由に選べます。今回の GCP → GitHub Pages の移行でも、入稿フロー側は一切変更なしで済みました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;バージョン管理&lt;&#x2F;strong&gt;: 静的 HTML を GitHub リポジトリで管理しているため、変更履歴の追跡やロールバックが容易です。&lt;&#x2F;p&gt;
&lt;p&gt;そして、今回このメリットが最大限に活きました。移行作業はホスティング先の変更だけで完結し、コンテンツのワークフローには一切手を入れずに済みました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;yi-xing-xian-nojian-tao-github-pages-vs-netlify&quot;&gt;移行先の検討: GitHub Pages vs Netlify&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;hou-bu-noxuan-ding-ji-zhun&quot;&gt;候補の選定基準&lt;&#x2F;h3&gt;
&lt;p&gt;移行先の条件は以下の通りです:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;追加コスト $0&lt;&#x2F;strong&gt;: 既存の GitHub プランで利用できる静的ホスティングサービス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;カスタムドメイン対応&lt;&#x2F;strong&gt;: ccmp.jp（apex ドメイン）で運用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;HTTPS 対応&lt;&#x2F;strong&gt;: TLS 証明書の自動発行・更新&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;IPv6 対応&lt;&#x2F;strong&gt;: apex ドメインでも IPv6 到達可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;自社 NS 維持&lt;&#x2F;strong&gt;: DNS のネームサーバは変更しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Cloudflare Pages は NS 移管が原則必要なため不採用としました。自社 NS では ccmp.jp 以外のドメインやサービスの DNS も管理しており、NS を Cloudflare に移管すると他のサービスへの影響が避けられません。GitHub Pages と Netlify の 2 候補でステージング検証を行いました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sutezingujian-zheng&quot;&gt;ステージング検証&lt;&#x2F;h3&gt;
&lt;p&gt;それぞれサブドメインでステージング環境を構築し、実際の動作を検証しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;GitHub Pages（stg-g.ccmp.jp）&lt;&#x2F;strong&gt;: GitHub Actions ワークフローで &lt;code&gt;localhost&#x2F;&lt;&#x2F;code&gt; を Pages にデプロイしました。CNAME と &lt;code&gt;.nojekyll&lt;&#x2F;code&gt; はワークフロー内で動的生成する構成としています（コンテンツ生成時に &lt;code&gt;rm -rf localhost&#x2F;&lt;&#x2F;code&gt; されるため、ファイルを直接置けません）。全項目問題ありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Netlify（stg-n.ccmp.jp）&lt;&#x2F;strong&gt;: 今回のリポジトリは GitHub Organization 所有のプライベートリポジトリですが、Netlify Free プランではこの種のリポジトリの Git 連携が不可です（Pro $19&#x2F;月が必要）。GitHub Actions から &lt;code&gt;netlify deploy --prod&lt;&#x2F;code&gt; で CLI デプロイする方式で回避しました。また、&lt;code&gt;wget&lt;&#x2F;code&gt; が生成するファイル名に &lt;code&gt;?&lt;&#x2F;code&gt; や &lt;code&gt;#&lt;&#x2F;code&gt; が含まれており Netlify が拒否するため、デプロイ前にクリーンアップが必要でした。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bi-jiao-jie-guo&quot;&gt;比較結果&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;GitHub Pages&lt;&#x2F;th&gt;&lt;th&gt;Netlify Free&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;追加コスト&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;apex ドメイン A レコード&lt;&#x2F;td&gt;&lt;td&gt;4 IP&lt;&#x2F;td&gt;&lt;td&gt;1 IP のみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;apex ドメイン IPv6&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;OK（AAAA 4 IP）&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;NG（AAAA 非公開）&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Git 連携&lt;&#x2F;td&gt;&lt;td&gt;ネイティブ&lt;&#x2F;td&gt;&lt;td&gt;CLI 回避策が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ファイル名制約&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;?&lt;&#x2F;code&gt; &lt;code&gt;#&lt;&#x2F;code&gt; 不可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;GitHub Pages を採用しました&lt;&#x2F;strong&gt;。決め手は apex ドメインでの IPv6 対応、ネイティブ Git 連携、ファイル名制約がない点です。なお、CDN については GitHub Pages も Fastly ベースとされる CDN を内蔵しており、Cloud CDN を別途構築する必要がなくなりました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;ben-fan-yi-xing-noshi-shi&quot;&gt;本番移行の実施&lt;&#x2F;h2&gt;
&lt;p&gt;ステージング検証で問題がないことを確認した翌日に本番移行を実施しました。ステージング検証から GCP 撤去完了まで、作業期間は 2 日間でした。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub Actions ワークフローの CNAME をステージング用からプロダクション用（&lt;code&gt;ccmp.jp&lt;&#x2F;code&gt;）に変更&lt;&#x2F;li&gt;
&lt;li&gt;GitHub の Settings → Pages → Custom domain を &lt;code&gt;ccmp.jp&lt;&#x2F;code&gt; に設定（DNS 切替前に実施し、TLS 証明書の発行を最速化）&lt;&#x2F;li&gt;
&lt;li&gt;自社 NS で ccmp.jp の A&#x2F;AAAA レコードを GitHub Pages の IP に切替&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;www.ccmp.jp&lt;&#x2F;code&gt; の CNAME を追加（GitHub Pages が www → apex の自動リダイレクトを提供）&lt;&#x2F;li&gt;
&lt;li&gt;動作確認: HTTPS、Clean URL、リダイレクト、IPv4&#x2F;IPv6 すべて OK&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;TLS 証明書について:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Pages は DNS が向いた時点で自動的に Let&#x27;s Encrypt 証明書を発行します&lt;&#x2F;li&gt;
&lt;li&gt;旧 GCP VM の証明書との衝突はありません（Let&#x27;s Encrypt は同一ドメインに複数証明書を許可）&lt;&#x2F;li&gt;
&lt;li&gt;GCP 側の証明書は自然に期限切れになるだけで、手動対応は不要です&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;gcp-inhuranoche-qu&quot;&gt;GCP インフラの撤去&lt;&#x2F;h2&gt;
&lt;p&gt;本番移行の完了後、旧 GCP インフラ（VM、VPC、ロードバランサー、固定 IP、SSL 証明書など計 20 リソース以上）を Terraform で一括撤去しました。再構築が必要になった場合に備え、Terraform コードと手順書はリポジトリに残してあります。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;移行前（GCP）&lt;&#x2F;th&gt;&lt;th&gt;移行後（GitHub Pages）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GCP ホスティングコスト&lt;&#x2F;td&gt;&lt;td&gt;約 $23&#x2F;月&lt;&#x2F;td&gt;&lt;td&gt;$0（GitHub Pages に移行）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TLS 証明書&lt;&#x2F;td&gt;&lt;td&gt;自前で自動化（certbot）&lt;&#x2F;td&gt;&lt;td&gt;GitHub にお任せ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IPv6&lt;&#x2F;td&gt;&lt;td&gt;対応&lt;&#x2F;td&gt;&lt;td&gt;対応&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;デプロイ&lt;&#x2F;td&gt;&lt;td&gt;git pull + nginx&lt;&#x2F;td&gt;&lt;td&gt;GitHub Actions 自動デプロイ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;インフラ運用&lt;&#x2F;td&gt;&lt;td&gt;VM・LB・CDN の管理が必要&lt;&#x2F;td&gt;&lt;td&gt;不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;年間 $276 削減、管理対象リソース 20 → 0。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;※ GitHub Pages をプライベートリポジトリで利用するには GitHub Pro 以上のプランが必要です。今回は既に GitHub Team プランを利用していたため、追加コストなしで移行できました。パブリックリポジトリであれば Free プランでも利用でき、GitHub Actions の無料枠（月 2,000 分）の範囲内であれば完全に $0 で運用可能です。&lt;&#x2F;p&gt;
&lt;p&gt;9 年前の設計は、当時の最適解でした。そしてその設計が、9 年後の移行コストを最小化してくれました。&lt;&#x2F;p&gt;
&lt;p&gt;今回の移行で改めて実感したのは、&lt;strong&gt;入稿と配信を分離するアーキテクチャの強さ&lt;&#x2F;strong&gt;です。Joomla CMS による入稿ワークフローは一切変更せず、ホスティング先だけを差し替えることで移行が完了しました。コンテンツ管理と配信基盤を疎結合にしておくことで、将来また別のホスティングサービスに移る場合でも同様にスムーズな移行ができます。&lt;&#x2F;p&gt;
&lt;p&gt;もし「CMS は使いたいけど静的ホスティングのメリットも享受したい」という状況であれば、CMS + wget による静的サイト生成パイプラインは検討に値するアプローチだと思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>OAuth2 and OpenID Connect (OIDC) Flow Testing: A Comprehensive Analysis of Response Types and Modes</title>
        <published>2025-07-07T00:00:00+00:00</published>
        <updated>2025-07-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2025/07/oauth2-flow-testing-comprehensive.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2025/07/oauth2-flow-testing-comprehensive.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2025/07/oauth2-flow-testing-comprehensive.html/">&lt;p&gt;When implementing OAuth2 authorization and OpenID Connect (OIDC)
authentication, developers face numerous configuration choices that
significantly impact both security and user experience. While the OAuth2
and OIDC specifications provide guidance, understanding how different
combinations of response types and response modes behave in practice
requires empirical testing.&lt;&#x2F;p&gt;
&lt;p&gt;This post presents a systematic analysis of OAuth2&#x2F;OIDC flows using
Google’s implementation, revealing key insights about token delivery
patterns, security implications, and practical recommendations for
production deployments.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the&quot;&gt;The&lt;&#x2F;h2&gt;
&lt;p&gt;Challenge: Too Many Options, Too Little Clarity&lt;&#x2F;p&gt;
&lt;p&gt;OAuth2 and OpenID Connect (OIDC) offer multiple response types and
response modes that serve different purposes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OAuth2 Response Types&lt;&#x2F;strong&gt;: - &lt;code&gt;code&lt;&#x2F;code&gt; -
Authorization Code Grant (for access tokens) - &lt;code&gt;token&lt;&#x2F;code&gt; -
Implicit Grant (direct access tokens)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OIDC Response Types&lt;&#x2F;strong&gt;: - &lt;code&gt;id_token&lt;&#x2F;code&gt; -
Identity tokens for authentication - &lt;code&gt;code token&lt;&#x2F;code&gt;,
&lt;code&gt;code id_token&lt;&#x2F;code&gt;, &lt;code&gt;token id_token&lt;&#x2F;code&gt;,
&lt;code&gt;code token id_token&lt;&#x2F;code&gt; - Hybrid flows&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Response Modes&lt;&#x2F;strong&gt; (both OAuth2&#x2F;OIDC): -
&lt;code&gt;query&lt;&#x2F;code&gt;, &lt;code&gt;fragment&lt;&#x2F;code&gt;, &lt;code&gt;form_post&lt;&#x2F;code&gt; -
Different delivery methods&lt;&#x2F;p&gt;
&lt;p&gt;This creates a matrix of possibilities: 7 response types × 3 response
modes × various scope combinations = 42+ different flow configurations
to understand. Rather than rely on documentation alone, I built an
automated testing framework to examine how these flows actually
behave.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;methodology&quot;&gt;Methodology:&lt;&#x2F;h2&gt;
&lt;p&gt;Automated OAuth2&#x2F;OIDC Flow Testing&lt;&#x2F;p&gt;
&lt;p&gt;I created a Python script that systematically tests all OAuth2&#x2F;OIDC
flow combinations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Core testing parameters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RESPONSE_TYPES = [&amp;#39;code&amp;#39;, &amp;#39;token&amp;#39;, &amp;#39;id_token&amp;#39;, &amp;#39;code token&amp;#39;, &amp;#39;code id_token&amp;#39;, &amp;#39;token id_token&amp;#39;, &amp;#39;code token id_token&amp;#39;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RESPONSE_MODES = [&amp;#39;query&amp;#39;, &amp;#39;fragment&amp;#39;, &amp;#39;form_post&amp;#39;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SCOPES = [&amp;#39;profile email&amp;#39;, &amp;#39;openid profile email&amp;#39;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The testing framework:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generates authorization URLs&lt;&#x2F;strong&gt; for each OAuth2&#x2F;OIDC
combination&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Opens browser windows&lt;&#x2F;strong&gt; for user authentication&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Captures responses&lt;&#x2F;strong&gt; across query parameters, form
data, and URL fragments&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performs token exchange&lt;&#x2F;strong&gt; when authorization codes
are present (OAuth2 code flow)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Validates ID tokens&lt;&#x2F;strong&gt; when present (OIDC
authentication)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Logs comprehensive results&lt;&#x2F;strong&gt; for analysis&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This approach provided empirical data on how Google’s OAuth2&#x2F;OIDC
implementation handles each flow configuration.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-findings-response&quot;&gt;Key Findings: Response&lt;&#x2F;h2&gt;
&lt;p&gt;Behavior Patterns&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pattern-1-location&quot;&gt;Pattern 1: Location&lt;&#x2F;h3&gt;
&lt;p&gt;Predictability&lt;&#x2F;p&gt;
&lt;p&gt;The testing revealed consistent patterns in where tokens are
delivered:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Query&#x2F;Fragment Modes:&lt;&#x2F;strong&gt; - Single &lt;code&gt;code&lt;&#x2F;code&gt;
responses → Query parameters - Any token-containing responses → URL
fragments - Multiple tokens → Always delivered together&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Form Post Mode:&lt;&#x2F;strong&gt; - All responses → Form parameters
(consistent delivery)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pattern-2-token-grouping&quot;&gt;Pattern 2: Token Grouping&lt;&#x2F;h3&gt;
&lt;p&gt;When multiple tokens are requested
(&lt;code&gt;response_type=code token id_token&lt;&#x2F;code&gt;), they are always
delivered together in the same location. You never see mixed delivery
like code in query parameters while tokens appear in fragments.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pattern-3-oidc-scope&quot;&gt;Pattern 3: OIDC Scope&lt;&#x2F;h3&gt;
&lt;p&gt;Normalization&lt;&#x2F;p&gt;
&lt;p&gt;Regardless of requested scope, Google’s OIDC implementation
consistently: - Adds &lt;code&gt;openid&lt;&#x2F;code&gt; scope to all responses (making
them OIDC flows) - Expands scopes to include full URL versions -
Maintains identical behavior for &lt;code&gt;profile email&lt;&#x2F;code&gt; vs
&lt;code&gt;openid profile email&lt;&#x2F;code&gt; - Always includes identity information
when ID tokens are requested&lt;&#x2F;p&gt;
&lt;h2 id=&quot;detailed-test-results&quot;&gt;Detailed Test Results&lt;&#x2F;h2&gt;
&lt;p&gt;The comprehensive testing revealed distinct patterns across all
response mode and type combinations:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;query-response-mode-results&quot;&gt;Query Response Mode Results&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Response Type&lt;&#x2F;th&gt;&lt;th&gt;Scope&lt;&#x2F;th&gt;&lt;th&gt;Response Location&lt;&#x2F;th&gt;&lt;th&gt;Returned Tokens&lt;&#x2F;th&gt;&lt;th&gt;Token Exchange&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;profile email&lt;&#x2F;td&gt;&lt;td&gt;query params&lt;&#x2F;td&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;openid profile email&lt;&#x2F;td&gt;&lt;td&gt;query params&lt;&#x2F;td&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;access_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, access_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;fragment-response-mode&quot;&gt;Fragment Response Mode&lt;&#x2F;h3&gt;
&lt;p&gt;Results&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Response Type&lt;&#x2F;th&gt;&lt;th&gt;Scope&lt;&#x2F;th&gt;&lt;th&gt;Response Location&lt;&#x2F;th&gt;&lt;th&gt;Returned Tokens&lt;&#x2F;th&gt;&lt;th&gt;Token Exchange&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;query params&lt;&#x2F;td&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;access_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, access_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;fragment&lt;&#x2F;td&gt;&lt;td&gt;code, access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;form-post-response-mode&quot;&gt;Form Post Response Mode&lt;&#x2F;h3&gt;
&lt;p&gt;Results&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Response Type&lt;&#x2F;th&gt;&lt;th&gt;Scope&lt;&#x2F;th&gt;&lt;th&gt;Response Location&lt;&#x2F;th&gt;&lt;th&gt;Returned Tokens&lt;&#x2F;th&gt;&lt;th&gt;Token Exchange&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;code&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;access_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;code, access_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;code, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;none&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;code token id_token&lt;&#x2F;td&gt;&lt;td&gt;both scopes&lt;&#x2F;td&gt;&lt;td&gt;form params&lt;&#x2F;td&gt;&lt;td&gt;code, access_token, id_token&lt;&#x2F;td&gt;&lt;td&gt;access_token, id_token&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;key-observations-from&quot;&gt;Key Observations from&lt;&#x2F;h3&gt;
&lt;p&gt;Results&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OAuth2 Code Exchange Pattern&lt;&#x2F;strong&gt;: Any flow that
includes “code” triggers a token exchange, always returning both
access_token and id_token (full OIDC response)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OIDC Response Location Consistency&lt;&#x2F;strong&gt;: Code-only
responses go to query_params in query&#x2F;fragment modes, while any
responses containing tokens or ID tokens are delivered via URL fragments
(regardless of whether response_mode is query or fragment). Only
form_post mode consistently delivers all response types via the
specified method.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scope Independence&lt;&#x2F;strong&gt;: No difference in behavior
between “profile email” and “openid profile email” - OpenID scope is
always included, making all flows OIDC-compliant&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;security&quot;&gt;Security&lt;&#x2F;h2&gt;
&lt;p&gt;Analysis: Most and Least Recommended OAuth2&#x2F;OIDC Flows&lt;&#x2F;p&gt;
&lt;h3 id=&quot;trophy-most&quot;&gt;🏆 Most&lt;&#x2F;h3&gt;
&lt;p&gt;Recommended: Authorization Code Flow with Form Post&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Configuration&lt;&#x2F;strong&gt;: &lt;code&gt;response_type=code&lt;&#x2F;code&gt;,
&lt;code&gt;response_mode=form_post&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why it’s secure:&lt;&#x2F;strong&gt; - No tokens in URLs or browser
history - Credentials don’t appear in server logs - Backend token
exchange enables client authentication (OAuth2) - Authorization code is
short-lived and single-use - Full OIDC compliance with secure ID token
delivery&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Implementation benefits:&lt;&#x2F;strong&gt; - Simple to implement and
debug - Reliable across all browsers - No client-side token handling
required - Works for both OAuth2 authorization and OIDC
authentication&lt;&#x2F;p&gt;
&lt;h3 id=&quot;warning-least&quot;&gt;⚠️ Least&lt;&#x2F;h3&gt;
&lt;p&gt;Recommended: Implicit and OIDC Implicit Flows&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Configuration&lt;&#x2F;strong&gt;: &lt;code&gt;response_type=token&lt;&#x2F;code&gt; or
&lt;code&gt;response_type=id_token&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security concerns:&lt;&#x2F;strong&gt; - Tokens&#x2F;ID tokens exposed in URL
fragments - No client authentication possible - Higher risk of token
leakage - ID tokens may be logged in browser history (OIDC security
risk)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Functional limitations:&lt;&#x2F;strong&gt; - No refresh tokens
available - Shorter token lifetimes required - Limited error handling
capabilities - Deprecated in OAuth 2.1 draft&lt;&#x2F;p&gt;
&lt;h2 id=&quot;practical-recommendations&quot;&gt;Practical Recommendations&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;for-web-applications&quot;&gt;For Web Applications&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Recommended: Authorization Code with Form Post + PKCE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const authUrl = `https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth?` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_type=code&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_mode=form_post&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `client_id=${clientId}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `redirect_uri=${redirectUri}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `scope=openid profile email&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge=${codeChallenge}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge_method=S256&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `state=${state}`;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;for-single-page-applications&quot;&gt;For Single Page Applications&lt;&#x2F;h3&gt;
&lt;p&gt;(SPAs)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Recommended: Use Backend-for-Frontend (BFF) Pattern&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; SPA communicates with your BFF, BFF handles OAuth2&#x2F;OIDC with provider&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; BFF uses the secure web application flow:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const authUrl = `https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth?` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_type=code&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_mode=form_post&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `client_id=${clientId}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `redirect_uri=${bffRedirectUri}&amp;amp;` +  &#x2F;&#x2F; Points to BFF, not SPA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `scope=openid profile email&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge=${codeChallenge}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge_method=S256&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `state=${state}`;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Alternative: If BFF not feasible, Authorization Code + PKCE directly in SPA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const spaAuthUrl = `https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth?` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_type=code&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `response_mode=fragment&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `client_id=${clientId}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `redirect_uri=${redirectUri}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `scope=openid profile email&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge=${codeChallenge}&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `code_challenge_method=S256&amp;amp;` +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  `state=${state}`;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; For SPAs, the Backend-for-Frontend (BFF)
pattern is the recommended approach where your backend acts as the
OAuth2&#x2F;OIDC Relying Party. The BFF can safely store client secrets,
handle token exchange, and manage session state. This avoids
browser-based security limitations and provides the most secure
implementation. If BFF is not feasible, use Authorization Code + PKCE
directly in the SPA, though this may require workarounds for
provider-specific limitations like Google’s client secret
requirement.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;security-enhancements&quot;&gt;Security Enhancements&lt;&#x2F;h3&gt;
&lt;p&gt;Regardless of chosen flow, implement these security measures:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Always use PKCE&lt;&#x2F;strong&gt; for code-based flows
(OAuth2&#x2F;OIDC)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implement state parameter&lt;&#x2F;strong&gt; for CSRF protection&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use nonce parameter&lt;&#x2F;strong&gt; for OIDC ID token replay
protection&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Validate redirect URIs&lt;&#x2F;strong&gt; strictly&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep authorization codes short-lived&lt;&#x2F;strong&gt; (&amp;lt; 10
minutes)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Verify ID token signatures&lt;&#x2F;strong&gt; and claims (OIDC)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Validate token audiences&lt;&#x2F;strong&gt; and issuers&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;response-mode-comparison&quot;&gt;Response Mode Comparison&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Response Mode&lt;&#x2F;th&gt;&lt;th&gt;Security&lt;&#x2F;th&gt;&lt;th&gt;Reliability&lt;&#x2F;th&gt;&lt;th&gt;Use Case&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;form_post&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;✅ Highest&lt;&#x2F;td&gt;&lt;td&gt;✅ Excellent&lt;&#x2F;td&gt;&lt;td&gt;Web applications&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fragment&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;⚠️ Medium&lt;&#x2F;td&gt;&lt;td&gt;✅ Good&lt;&#x2F;td&gt;&lt;td&gt;SPAs, mobile apps&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;query&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;❌ Lowest&lt;&#x2F;td&gt;&lt;td&gt;✅ Good&lt;&#x2F;td&gt;&lt;td&gt;Legacy systems only&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;testing-your-own&quot;&gt;Testing Your Own&lt;&#x2F;h2&gt;
&lt;p&gt;OAuth2&#x2F;OIDC Implementation&lt;&#x2F;p&gt;
&lt;p&gt;The testing framework can be adapted for other OAuth2&#x2F;OIDC
providers:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Configuration for different providers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROVIDERS = {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;#39;google&amp;#39;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;#39;auth_endpoint&amp;#39;: &amp;#39;https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;#39;token_endpoint&amp;#39;: &amp;#39;https:&#x2F;&#x2F;oauth2.googleapis.com&#x2F;token&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;#39;microsoft&amp;#39;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;#39;auth_endpoint&amp;#39;: &amp;#39;https:&#x2F;&#x2F;login.microsoftonline.com&#x2F;common&#x2F;oauth2&#x2F;v2.0&#x2F;authorize&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;#39;token_endpoint&amp;#39;: &amp;#39;https:&#x2F;&#x2F;login.microsoftonline.com&#x2F;common&#x2F;oauth2&#x2F;v2.0&#x2F;token&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This systematic analysis reveals that OAuth2&#x2F;OIDC flow selection
significantly impacts both security and implementation complexity. Key
takeaways:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Form Post mode&lt;&#x2F;strong&gt; provides the best security profile
for both OAuth2 and OIDC flows&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authorization code flows&lt;&#x2F;strong&gt; remain the gold standard
for secure authentication and authorization&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implicit flows&lt;&#x2F;strong&gt; should be avoided in favor of
code-based alternatives (deprecated in OAuth 2.1)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OIDC scope normalization&lt;&#x2F;strong&gt; means most flows become
OpenID Connect flows automatically&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent testing&lt;&#x2F;strong&gt; is essential for understanding
provider-specific behavior&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The OAuth2&#x2F;OIDC landscape continues evolving, with new security
enhancements like PKCE and PAR (Pushed Authorization Requests) becoming
standard. However, the fundamental principles revealed through this
testing remain relevant: prioritize security, minimize token exposure,
understand the difference between OAuth2 authorization and OIDC
authentication, and thoroughly test your chosen configuration.&lt;&#x2F;p&gt;
&lt;p&gt;For production deployments, always combine empirical testing with
security best practices to ensure robust authentication and
authorization flows that protect both your application and your
users.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;The complete testing framework and detailed results are available
in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ktaka-ccmp&#x2F;915a3680f04f1704742f13e898ca668d?permalink_comment_id=5665842#gistcomment-5665842&quot;&gt;Gist
page&lt;&#x2F;a&gt;. Feel free to adapt the testing methodology for your own OAuth2
implementations.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Google OAuth2&#x2F;OIDC and PKCE: Understanding Client Secret Requirements</title>
        <published>2025-07-07T00:00:00+00:00</published>
        <updated>2025-07-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2025/07/oogle-oauth2-and-pkce-understanding.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2025/07/oogle-oauth2-and-pkce-understanding.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2025/07/oogle-oauth2-and-pkce-understanding.html/">&lt;p&gt;&lt;em&gt;A systematic test of Google’s OAuth2 PKCE implementation and its
implications for different application types.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Key Finding&lt;&#x2F;strong&gt;: Google’s OAuth2 implementation requires
&lt;code&gt;client_secret&lt;&#x2F;code&gt; even when using PKCE for Web Application
client types, contrary to RFC 7636 standard expectations. This post
documents systematic testing that confirms this behavior and provides
architectural guidance for developers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;background-pkce-and-public&quot;&gt;Background: PKCE and Public&lt;&#x2F;h2&gt;
&lt;p&gt;Clients&lt;&#x2F;p&gt;
&lt;p&gt;PKCE (Proof Key for Code Exchange) was introduced in RFC 7636 to
address security concerns with public clients—applications that cannot
securely store credentials, such as mobile apps and single-page
applications (SPAs).&lt;&#x2F;p&gt;
&lt;p&gt;The standard OAuth2 flow requires a &lt;code&gt;client_secret&lt;&#x2F;code&gt;, but
PKCE provides an alternative mechanism:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Generate a random &lt;code&gt;code_verifier&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;code_challenge&lt;&#x2F;code&gt; by hashing the verifier&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Send the challenge with the authorization request&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Exchange the authorization code using the verifier&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;According to RFC 7636, this should eliminate the need for
&lt;code&gt;client_secret&lt;&#x2F;code&gt; in public clients.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing-google-s&quot;&gt;Testing Google’s&lt;&#x2F;h2&gt;
&lt;p&gt;Implementation&lt;&#x2F;p&gt;
&lt;p&gt;I conducted a systematic test to understand how Google’s OAuth2
endpoints handle PKCE requests using a Web Application client type.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;test-setup&quot;&gt;Test Setup&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Generate PKCE parameters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;code_verifier=$(openssl rand -base64 32 | tr -d &amp;quot;=+&#x2F;&amp;quot; | cut -c1-43)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;code_challenge=$(echo -n $code_verifier | openssl dgst -sha256 -binary | openssl base64 | tr -d &amp;#39;\n&amp;#39; | tr &amp;#39;+&amp;#39; &amp;#39;-&amp;#39; | tr &amp;#39;&#x2F;&amp;#39; &amp;#39;_&amp;#39; | tr -d &amp;#39;=&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;=== PKCE Parameters ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;code_verifier: $code_verifier&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;code_challenge: $code_challenge&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# OAuth2 settings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client_id=&amp;#39;[REDACTED_CLIENT_ID]&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redirect_uri=&amp;#39;https:&#x2F;&#x2F;oauth2.example.com&#x2F;result&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Generate authorization URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auth_url=&amp;quot;https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth?redirect_uri=${redirect_uri}&amp;amp;response_type=code&amp;amp;client_id=${client_id}&amp;amp;scope=openid+email+profile&amp;amp;access_type=online&amp;amp;code_challenge=${code_challenge}&amp;amp;code_challenge_method=S256&amp;amp;response_mode=fragment&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;=== Authorization URL ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;$auth_url&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;=== Token Exchange Command ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;curl -X POST \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  --data-urlencode \&amp;quot;code=\$CODE\&amp;quot; \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  --data-urlencode \&amp;quot;client_id=$client_id\&amp;quot; \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  --data-urlencode \&amp;quot;redirect_uri=$redirect_uri\&amp;quot; \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  --data-urlencode \&amp;quot;code_verifier=$code_verifier\&amp;quot; \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  -d &amp;#39;grant_type=authorization_code&amp;#39; \\&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;  https:&#x2F;&#x2F;oauth2.googleapis.com&#x2F;token&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;test-results&quot;&gt;Test Results&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Authorization Request&lt;&#x2F;strong&gt;: ✅ Successful Google accepted
the PKCE parameters (&lt;code&gt;code_challenge&lt;&#x2F;code&gt; and
&lt;code&gt;code_challenge_method=S256&lt;&#x2F;code&gt;) and returned an authorization
code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token Exchange with PKCE only&lt;&#x2F;strong&gt;: ❌ Failed&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;curl -X POST \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;code=$CODE&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;client_id=[REDACTED_CLIENT_ID]&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;redirect_uri=https:&#x2F;&#x2F;oauth2.example.com&#x2F;result&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;code_verifier=[REDACTED_VERIFIER]&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -d &amp;#39;grant_type=authorization_code&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  https:&#x2F;&#x2F;oauth2.googleapis.com&#x2F;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Response:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;error&amp;quot;: &amp;quot;invalid_request&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;error_description&amp;quot;: &amp;quot;client_secret is missing.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;community-confirmation&quot;&gt;Community Confirmation&lt;&#x2F;h2&gt;
&lt;p&gt;This limitation has been documented by the developer community:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Stack Overflow Evidence:&lt;&#x2F;strong&gt; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;76528208&#x2F;google-oauth-2-0-authorization-code-with-pkce-requires-a-client-secret&quot;&gt;Google
OAuth 2.0 Authorization Code (with PKCE) requires a client secret&lt;&#x2F;a&gt; -
Multiple developers confirm this requirement - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;78673050&#x2F;is-a-client-secret-required-for-google-oauth-2-0-using-the-pkce-authorization-fl&quot;&gt;Is
a Client Secret Required for Google OAuth 2.0 using the PKCE
Authorization Flow?&lt;&#x2F;a&gt; - Discussion of Google’s non-standard
implementation&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Google Cloud Community:&lt;&#x2F;strong&gt; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.googlecloudcommunity.com&#x2F;gc&#x2F;Developer-Tools&#x2F;Authorization-Code-Flow-without-client-secret&#x2F;m-p&#x2F;814109&quot;&gt;Authorization
Code Flow without client secret&lt;&#x2F;a&gt; - A Google representative
acknowledges: “Google’s Identity Platform as of today does not support
public applications under the ‘Web Application’ profile. Flows always
require a client_secret.”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;GitHub Issues:&lt;&#x2F;strong&gt; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;postmanlabs&#x2F;postman-app-support&#x2F;issues&#x2F;9409&quot;&gt;OAuth
2.0 with PKCE still requires client secret&lt;&#x2F;a&gt; - Tool developers
encounter this limitation&lt;&#x2F;p&gt;
&lt;h2 id=&quot;understanding-the&quot;&gt;Understanding the&lt;&#x2F;h2&gt;
&lt;p&gt;Implications&lt;&#x2F;p&gt;
&lt;h3 id=&quot;for-server-side-applications&quot;&gt;For Server-Side Applications&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Recommendation&lt;&#x2F;strong&gt;: Use the traditional OAuth2 flow with
&lt;code&gt;client_secret&lt;&#x2F;code&gt; stored securely on your server.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;curl -X POST \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;code=$code&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;client_id=$client_id&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data-urlencode &amp;quot;redirect_uri=$redirect_uri&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -d &amp;quot;client_secret=$client_secret&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -d &amp;#39;grant_type=authorization_code&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  https:&#x2F;&#x2F;oauth2.googleapis.com&#x2F;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the intended use case where &lt;code&gt;client_secret&lt;&#x2F;code&gt; can be
stored securely.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;for-single-page-applications&quot;&gt;For Single-Page Applications&lt;&#x2F;h3&gt;
&lt;p&gt;(SPAs)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation&lt;&#x2F;strong&gt;: Limit authentication to
&lt;code&gt;id_token&lt;&#x2F;code&gt; only and handle API access through your
backend.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Critical Security Warning&lt;&#x2F;strong&gt;: Embedding a
&lt;code&gt;client_secret&lt;&#x2F;code&gt; in browser code exposes it to anyone with
access to the client, which is fundamentally insecure. This is why the
OAuth2 standard forbids it for public clients.&lt;&#x2F;p&gt;
&lt;p&gt;For SPAs that cannot securely store &lt;code&gt;client_secret&lt;&#x2F;code&gt;: 1.
Use the implicit flow or authorization code flow to obtain only
&lt;code&gt;id_token&lt;&#x2F;code&gt; for user authentication 2. Send the
&lt;code&gt;id_token&lt;&#x2F;code&gt; to your backend for verification 3. Handle Google
API calls from your backend using server-stored credentials&lt;&#x2F;p&gt;
&lt;p&gt;This approach separates authentication (client-side) from API access
(server-side).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: As of this writing, Google’s official
documentation still directs SPAs toward the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;protocols&#x2F;oauth2&#x2F;javascript-implicit-flow&quot;&gt;implicit
flow&lt;&#x2F;a&gt;, which has been deprecated in OAuth 2.1 due to security
concerns. This inconsistency in guidance contributes to confusion around
best practices.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;for-mobile-and-desktop&quot;&gt;For Mobile and Desktop&lt;&#x2F;h3&gt;
&lt;p&gt;Applications&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Current Reality&lt;&#x2F;strong&gt;: Google’s implementation requires
embedding &lt;code&gt;client_secret&lt;&#x2F;code&gt; in the application code.&lt;&#x2F;p&gt;
&lt;p&gt;Google’s documentation acknowledges this: “The process results in a
client ID and, in some cases, a client secret, which you embed in the
source code of your application. (In this context, the client secret is
obviously not treated as a secret.)”&lt;&#x2F;p&gt;
&lt;p&gt;While not ideal from a security perspective, this is Google’s
intended approach for native applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;technical-implementation&quot;&gt;Technical Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;Notes&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pkce-parameter-generation&quot;&gt;PKCE Parameter Generation&lt;&#x2F;h3&gt;
&lt;p&gt;Google requires base64url encoding for the code challenge:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Correct base64url encoding for Google&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;code_challenge=$(echo -n $code_verifier | openssl dgst -sha256 -binary | openssl base64 | tr -d &amp;#39;\n&amp;#39; | tr &amp;#39;+&amp;#39; &amp;#39;-&amp;#39; | tr &amp;#39;&#x2F;&amp;#39; &amp;#39;_&amp;#39; | tr -d &amp;#39;=&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;test-configuration&quot;&gt;Test Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;This testing used: - Web Application client type in Google Cloud
Console - Scopes: &lt;code&gt;openid email profile&lt;&#x2F;code&gt; - Standard OAuth2
endpoints (&lt;code&gt;https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth&lt;&#x2F;code&gt; and
&lt;code&gt;https:&#x2F;&#x2F;oauth2.googleapis.com&#x2F;token&lt;&#x2F;code&gt;) - PKCE method S256&lt;&#x2F;p&gt;
&lt;h3 id=&quot;different-client-types&quot;&gt;Different Client Types&lt;&#x2F;h3&gt;
&lt;p&gt;Google offers various OAuth2 client types that may have different
behaviors: - &lt;strong&gt;Web Application&lt;&#x2F;strong&gt;: In our testing, always
required &lt;code&gt;client_secret&lt;&#x2F;code&gt; - &lt;strong&gt;Android&#x2F;iOS&lt;&#x2F;strong&gt;: May
have different requirements (needs further testing) -
&lt;strong&gt;Desktop&lt;&#x2F;strong&gt;: Reported to require secret but treat as
non-confidential - &lt;strong&gt;TV&#x2F;Limited Input&lt;&#x2F;strong&gt;: Similar behavior
to desktop (based on community reports)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary-standard-vs-reality&quot;&gt;Summary: Standard vs Reality&lt;&#x2F;h2&gt;
&lt;p&gt;According to OAuth2&#x2F;PKCE standards, public clients should be able to
authenticate without embedding secrets. Here’s how Google’s
implementation compares:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Client Type&lt;&#x2F;th&gt;&lt;th&gt;Standard PKCE (No Secret Needed)&lt;&#x2F;th&gt;&lt;th&gt;Google’s Reality (Secret Required)&lt;&#x2F;th&gt;&lt;th&gt;Security Impact&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Server-side&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;❌ No (secret required)&lt;&#x2F;td&gt;&lt;td&gt;❌ No (secret required)&lt;&#x2F;td&gt;&lt;td&gt;✅ Secure (secret stays on server)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SPA (Browser)&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;✅ Yes (recommended)&lt;&#x2F;td&gt;&lt;td&gt;❌ No (not supported)&lt;&#x2F;td&gt;&lt;td&gt;❌ Secret exposed to users&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Mobile&#x2F;Desktop&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;✅ Yes (recommended)&lt;&#x2F;td&gt;&lt;td&gt;❌ No (not supported)&lt;&#x2F;td&gt;&lt;td&gt;❌ Secret embedded in app&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;The Problem&lt;&#x2F;strong&gt;: Google requires secrets for all client
types, forcing developers to embed credentials in publicly distributed
code—exactly what PKCE was designed to prevent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;architectural&quot;&gt;Architectural&lt;&#x2F;h2&gt;
&lt;p&gt;Recommendations&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hybrid-approach-for-spas&quot;&gt;Hybrid Approach for SPAs&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Browser (SPA) → Authentication only (id_token)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↓&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Backend Server → API calls with client_secret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;mobile-applications&quot;&gt;Mobile Applications&lt;&#x2F;h3&gt;
&lt;p&gt;If using Google OAuth2 with mobile apps, implement additional
security measures: - Use certificate pinning - Implement runtime
application self-protection (RASP) - Monitor for application
tampering&lt;&#x2F;p&gt;
&lt;h3 id=&quot;server-side-applications&quot;&gt;Server-Side Applications&lt;&#x2F;h3&gt;
&lt;p&gt;Standard OAuth2 flow with proper secret management: - Store
&lt;code&gt;client_secret&lt;&#x2F;code&gt; in secure configuration - Use environment
variables or secret management systems - Rotate credentials
regularly&lt;&#x2F;p&gt;
&lt;h2 id=&quot;community-feedback-welcome&quot;&gt;Community Feedback Welcome&lt;&#x2F;h2&gt;
&lt;p&gt;The findings in this post are based on testing with a specific client
configuration (Web Application type) and may not represent all possible
scenarios. Google’s OAuth2 implementation is complex, with different
behaviors across client types, API versions, and configuration
options.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;If you have different results or experiences&lt;&#x2F;strong&gt;, please
share them: - Have you successfully used PKCE without client_secret with
Google OAuth2? - Do different client types (Android, iOS, Desktop)
behave differently? - Are there specific Google APIs or configurations
that work as expected? - Have there been recent changes to Google’s
implementation?&lt;&#x2F;p&gt;
&lt;p&gt;This post aims to document one specific finding to help other
developers, but the OAuth2 landscape is constantly evolving.
Contradicting evidence or alternative approaches would be valuable
additions to the community’s understanding.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Google’s OAuth2 implementation requires &lt;code&gt;client_secret&lt;&#x2F;code&gt;
even when using PKCE for Web Application client types, which differs
from the RFC 7636 standard. This finding, supported by community
reports, indicates a consistent pattern in Google’s implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Understanding this behavior helps in choosing appropriate
architectural patterns:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Server-side applications&lt;&#x2F;strong&gt;: Use standard OAuth2 with
secure secret storage&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SPAs&lt;&#x2F;strong&gt;: Limit to authentication-only flows, handle
API access server-side&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mobile&#x2F;Desktop&lt;&#x2F;strong&gt;: Accept the embedded secret
limitation or use hybrid architectures&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When implementing OAuth2 with Google, design your architecture around
these observed constraints. While other client types may behave
differently, the Web Application type consistently requires client
secrets alongside PKCE.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc7636&quot;&gt;RFC 7636 - Proof Key
for Code Exchange by OAuth Public Clients&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;protocols&#x2F;oauth2&quot;&gt;Google
OAuth 2.0 Documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;protocols&#x2F;oauth2&#x2F;native-app&quot;&gt;Google
OAuth 2.0 for Mobile &amp;amp; Desktop Apps&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;protocols&#x2F;oauth2&#x2F;javascript-implicit-flow&quot;&gt;Google
OAuth 2.0 JavaScript Implicit Flow&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.google.com&#x2F;cloud&#x2F;answer&#x2F;15549257&quot;&gt;Manage
OAuth Clients - Google Cloud Platform Console Help&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;76528208&#x2F;google-oauth-2-0-authorization-code-with-pkce-requires-a-client-secret&quot;&gt;Stack
Overflow: Google OAuth 2.0 Authorization Code (with PKCE) requires a
client secret&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.googlecloudcommunity.com&#x2F;gc&#x2F;Developer-Tools&#x2F;Authorization-Code-Flow-without-client-secret&#x2F;m-p&#x2F;814109&quot;&gt;Google
Cloud Community: Authorization Code Flow without client secret&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Implementing Passkeys Authentication in Rust with Axum</title>
        <published>2025-01-17T00:00:00+00:00</published>
        <updated>2025-01-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2025/01/implementing-passkeys-authentication-in-rust-axum.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2025/01/implementing-passkeys-authentication-in-rust-axum.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2025/01/implementing-passkeys-authentication-in-rust-axum.html/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;As a developer learning web programming and authentication in Rust, I
recently undertook the challenge of implementing WebAuthn Passkeys using
the Axum web framework. In this post, I&#x27;ll share my experience building
a basic Passkey authentication system from scratch, without relying on
full-featured WebAuthn library crates.&lt;&#x2F;p&gt;
&lt;p&gt;To keep things concise, I’ve included simplified code snippets for
key components. The full implementation is available in my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;axum-passkey&quot;&gt;GitHub
repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video width=&quot;600&quot; height=&quot;600&quot; src=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&#x2F;image&#x2F;blog-20250117-01.mp4&quot; controls autoplay loop&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;understanding-webauthn-and&quot;&gt;Understanding WebAuthn and&lt;&#x2F;h1&gt;
&lt;p&gt;Passkeys&lt;&#x2F;p&gt;
&lt;p&gt;WebAuthn is a W3C standard for passwordless authentication that uses
public-key cryptography. The private keys are stored securely on user
devices while public keys remain on servers. WebAuthn supports both
platform authenticators (like Windows Hello or Touch ID) and roaming
authenticators (like security keys).&lt;&#x2F;p&gt;
&lt;p&gt;Passkeys extend WebAuthn by adding seamless account recovery through
cloud-synced credentials. They integrate with platform authenticators
like Google Password Manager or Apple Keychain, enabling users to
authenticate using biometrics or PINs across their devices. This
implementation is built on the FIDO2 protocol, which standardizes the
authentication flow and user interface.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-webauthn-flow&quot;&gt;The WebAuthn Flow&lt;&#x2F;h1&gt;
&lt;p&gt;WebAuthn authentication involves two main phases: registration and
authentication. Let&#x27;s examine how each phase works and then implement
them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;registration-flow&quot;&gt;Registration Flow&lt;&#x2F;h2&gt;
&lt;p&gt;During registration, the server first generates a cryptographic
challenge and sends it to the client along with registration options.
The client then requests its authenticator to create a new key pair and
generate an attestation object containing the public key. This
attestation object is sent back to the server, which verifies it and
stores the public key for future authentication.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&#x2F;image&#x2F;fig-1.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;The attestation object returned by the authenticator contains
authenticator data (including the new public key) and an attestation
statement that provides information about the authenticator itself. This
allows the server to verify the authenticator&#x27;s authenticity and
securely obtain the user&#x27;s public key.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;authentication-flow&quot;&gt;Authentication Flow&lt;&#x2F;h2&gt;
&lt;p&gt;The authentication process begins with the server generating a new
challenge. The authenticator then signs this challenge using the user&#x27;s
private key, and the server verifies the signature using the stored
public key.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&#x2F;image&#x2F;fig-2.png&quot; width=&quot;80%&quot;&gt;
&lt;h1 id=&quot;client-side-implementation&quot;&gt;Client-Side Implementation&lt;&#x2F;h1&gt;
&lt;p&gt;The client-side implementation handles both registration and
authentication flows using the WebAuthn browser APIs. Let&#x27;s walk through
each process step by step.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;registration-implementation&quot;&gt;Registration Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;The registration process begins by requesting options from the
server. This establishes the parameters for creating a new
credential:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const response = await fetch(&amp;#39;&#x2F;register&#x2F;start&amp;#39;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    method: &amp;#39;POST&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application&#x2F;json&amp;#39; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body: JSON.stringify(username)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const options = await response.json();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The server responds with registration options that specify how the
credential should be created. Here are the key parameters:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;challenge&amp;quot;: &amp;quot;base64url-encoded-random-bytes&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;rp_id&amp;quot;: &amp;quot;example.com&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;user&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;id&amp;quot;: &amp;quot;user-uuid&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;name&amp;quot;: &amp;quot;username&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;authenticatorSelection&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;authenticatorAttachment&amp;quot;: &amp;quot;platform&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;residentKey&amp;quot;: &amp;quot;required&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The challenge is a one-time cryptographic value that prevents replay
attacks. The rp_id binds the credential to our domain for phishing
protection, while the user.id provides a stable identifier for the
credential. The authenticatorSelection parameters determine how the
credential will be stored and used.&lt;&#x2F;p&gt;
&lt;p&gt;With these options, we can create the credential using the WebAuthn
API:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const credential = await navigator.credentials.create({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicKey: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: base64URLToBuffer(options.challenge),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rp: { id: options.rp_id },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            id: base64URLToBuffer(options.user.id),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            name: options.user.name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code triggers the authenticator to generate a new key pair. In
principle, the private key never leaves the authenticator, while the
public key is included in the response. We then send this response back
to the server:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;await fetch(&amp;#39;&#x2F;register&#x2F;finish&amp;#39;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    method: &amp;#39;POST&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application&#x2F;json&amp;#39; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body: JSON.stringify({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: credential.id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rawId: bufferToBase64URL(credential.rawId),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        response: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            attestationObject: bufferToBase64URL(credential.response.attestationObject),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            client_data_json: bufferToBase64URL(credential.response.clientDataJSON)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user_handle: options.user.id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The server will verify this response and store the public key for
future authentications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;&#x2F;h2&gt;
&lt;p&gt;Implementation&lt;&#x2F;p&gt;
&lt;p&gt;The authentication flow follows a similar pattern but focuses on
proving possession of an existing credential. We start by requesting
authentication options:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const response = await fetch(&amp;#39;&#x2F;auth&#x2F;start&amp;#39;, { method: &amp;#39;POST&amp;#39; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const options = await response.json();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The server provides a challenge and information about accepted
credentials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;challenge&amp;quot;: &amp;quot;base64url-encoded-random-bytes&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;rp_id&amp;quot;: &amp;quot;example.com&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Sending &amp;quot;allow_credentials&amp;quot; is optional for discoverable credentials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;allow_credentials&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;type&amp;quot;: &amp;quot;public-key&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;id&amp;quot;: &amp;quot;credential-id&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using these options, we ask the authenticator to sign the challenge
with the private key:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const assertion = await navigator.credentials.get({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicKey: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: base64URLToBuffer(options.challenge),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rpId: options.rp_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        allowCredentials: options.allow_credentials.map(cred =&amp;gt; ({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            id: base64URLToBuffer(cred.id),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            type: cred.type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The authenticator will prompt the user for consent (and potentially
biometric verification) before signing. We then send the signed
assertion to the server:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;await fetch(&amp;#39;&#x2F;auth&#x2F;verify&amp;#39;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    method: &amp;#39;POST&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application&#x2F;json&amp;#39; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body: JSON.stringify({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: assertion.id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        response: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            signature: bufferToBase64URL(credential.response.signature),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            authenticator_data: bufferToBase64URL(credential.response.authenticatorData),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            client_data_json: bufferToBase64URL(credential.response.clientDataJSON),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            user_handle: bufferToBase64URL(credential.response.userHandle)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;server-implementation-in&quot;&gt;Server Implementation in&lt;&#x2F;h1&gt;
&lt;p&gt;Rust&lt;&#x2F;p&gt;
&lt;p&gt;The server side of our WebAuthn implementation handles credential
storage, challenge generation, and cryptographic verification. Our
Axum-based implementation is organized into focused modules that handle
different aspects of the authentication process:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── main.rs              # Server setup and routing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── passkey.rs           # Module definitions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── passkey&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── attestation.rs   # Attestation verification&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── auth.rs          # Authentication handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── register.rs      # Registration handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The attestation module verifies new credentials during registration,
the auth module handles login attempts, and the register module manages
the credential creation process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state-management&quot;&gt;State Management&lt;&#x2F;h2&gt;
&lt;p&gt;Before diving into the handlers, let&#x27;s look at how we manage
server-side state:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Clone)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub(crate) struct AppState {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store: ArcMutexAuthStore&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    config: AppConfig,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This structure provides thread-safe access to our storage and
configuration. The AuthStore handles both temporary challenges and
permanent credentials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Default)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;struct AuthStore {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges: HashMapString, StoredChallenge&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    credentials: HashMapString, StoredCredential&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For a production environment, you&#x27;d replace these HashMaps with
proper databases - perhaps Redis for challenges and PostgreSQL for
credentials.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;registration-handler&quot;&gt;Registration Handler&lt;&#x2F;h2&gt;
&lt;p&gt;Implementation&lt;&#x2F;p&gt;
&lt;p&gt;The registration process consists of two main functions. The
start_registration function creates a new user identity and challenge,
preparing the server side for credential creation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn start_registration(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Json(username): JsonString&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; JsonRegistrationOptions&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate challenge and create user info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let challenge = generate_challenge();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_info = PublicKeyCredentialUserEntity {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: Uuid::new_v4().to_string(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        name: username.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        display_name: username.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Store challenge for verification&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let stored_challenge = StoredChallenge {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: challenge.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user: user_info.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        timestamp: SystemTime::now()...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut store = state.store.lock().await;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .challenges&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .insert(user_info.id.clone(), stored_challenge);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Return registration options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Json(RegistrationOptions {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: URL_SAFE.encode(&amp;amp;challenge),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rp_id: state.config.rp_id.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; ...other options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The finish_registration function processes the authenticator&#x27;s
response, verifying the attestation and storing the new credential:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn finish_registration(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Json(reg_data): JsonRegisterCredential&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;#39;static str, (StatusCode, String)&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut store = state.store.lock().await;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verify the challenge and client data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verify_client_data(&amp;amp;state, &amp;amp;reg_data, &amp;amp;store).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Extract the public key from attestation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let public_key = extract_credential_public_key(&amp;amp;reg_data, &amp;amp;state)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Store credential with user info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let credential_id = base64url_decode(&amp;amp;reg_data.raw_id)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let stored_user = store.challenges.get(&amp;amp;reg_data.user_handle)?.user.clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store.credentials.insert(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        reg_data.raw_id.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        StoredCredential {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            credential_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            public_key,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            counter: 0,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            user: stored_user,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Remove used challenge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store.challenges.remove(&amp;amp;reg_data.user_handle);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(&amp;quot;Registration successful&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This function performs several critical security checks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Verifies that the client data matches expectations (challenge,
origin, operation type)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Extracts and verifies the public key from the attestation
object&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Stores the credential with associated user information&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Removes the used challenge to prevent replay attacks&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;authentication-handler&quot;&gt;Authentication Handler&lt;&#x2F;h2&gt;
&lt;p&gt;Implementation&lt;&#x2F;p&gt;
&lt;p&gt;The authentication process also uses two main functions. The
start_authentication function generates a new challenge for an
authentication attempt:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn start_authentication(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; JsonAuthenticationOptions&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate new challenge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let challenge = generate_challenge();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Create auth ID for this session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let auth_id = Uuid::new_v4().to_string();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Store challenge for verification&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let stored_challenge = StoredChallenge {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: challenge.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user: Default::default(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        timestamp: SystemTime::now()...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut store = state.store.lock().await;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store.challenges.insert(auth_id.clone(), stored_challenge);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Return auth options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Json(AuthenticationOptions {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        challenge: URL_SAFE.encode(&amp;amp;challenge),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rp_id: state.config.rp_id.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; ... other options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verify_authentication function processes the authenticator&#x27;s
signed assertion, verifying the signature and associated data:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn verify_authentication(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Json(auth_response): JsonAuthenticatorResponse&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;#39;static str, (StatusCode, String)&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verify client data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let client_data = ParsedClientData::from_base64(&amp;amp;auth_response.response.client_data_json)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    client_data.verify(&amp;amp;state, &amp;amp;stored_challenge.challenge)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verify authenticator data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let auth_data = AuthenticatorData::from_base64(&amp;amp;auth_response.response.authenticator_data)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    auth_data.verify(&amp;amp;state)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verify signature&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let credential = store.credentials.get(&amp;amp;auth_response.id)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let public_key = UnparsedPublicKey::new(verification_algorithm, &amp;amp;credential.public_key);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public_key.verify(&amp;amp;signed_data, &amp;amp;signature)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(&amp;quot;Authentication successful&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This function performs three main security checks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Verifies the client data (challenge, origin, operation type)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Validates the authenticator data (RP ID hash, user presence,
verification status)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Verifies the signature using the stored public key&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If these verifications are successful, a session can be created and
the user is regarded as logged in.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;webauthn-data&quot;&gt;WebAuthn Data&lt;&#x2F;h1&gt;
&lt;p&gt;Structures and API Formats&lt;&#x2F;p&gt;
&lt;p&gt;Having seen both the client and server implementations, it&#x27;s
important to understand how they communicate with each other. While the
WebAuthn standard precisely defines how browsers interact with
authenticators, it doesn&#x27;t specify how WebAuthn data should be
transmitted between clients and servers. This gives implementations
flexibility in designing their API formats.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;data-flow-and&quot;&gt;Data Flow and&lt;&#x2F;h2&gt;
&lt;p&gt;Transformations&lt;&#x2F;p&gt;
&lt;p&gt;The WebAuthn API deals with binary data in ArrayBuffer format, but
this needs to be transformed for client-server communication:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2025&#x2F;01&#x2F;implementing-passkeys-authentication-in-rust-axum.html&#x2F;image&#x2F;fig-3.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;Our implementation makes several key design choices for data
transport:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Uses JSON format for easy parsing and debugging&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Base64url-encodes binary data for safe transport in JSON&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Renames fields to match language conventions (camelCase in JS,
snake_case in Rust)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Omits optional fields to simplify the implementation&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Makes some optional fields required where it helps our
implementation&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;registration-data-structures&quot;&gt;Registration Data Structures&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;standard-webauthn-interfaces&quot;&gt;Standard WebAuthn Interfaces&lt;&#x2F;h3&gt;
&lt;p&gt;The browser&#x27;s &lt;code&gt;navigator.credentials.create()&lt;&#x2F;code&gt; accepts
&lt;code&gt;PublicKeyCredentialCreationOptions&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PublicKeyCredentialCreationOptions {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenge: BufferSource,    &#x2F;&#x2F; Random bytes to prevent replay attacks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rp: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: string,      &#x2F;&#x2F; Domain name for phishing protection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        name: string     &#x2F;&#x2F; Display name for the service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: BufferSource,     &#x2F;&#x2F; Stable identifier for the user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        name: string,         &#x2F;&#x2F; Username (can change)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        displayName: string   &#x2F;&#x2F; User&amp;#39;s full name or display name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Allowed public key parameters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pubKeyCredParams: [{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type: &amp;quot;public-key&amp;quot;,   &#x2F;&#x2F; Currently only &amp;quot;public-key&amp;quot; is supported&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        alg: number          &#x2F;&#x2F; Cryptographic algorithm identifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Optional authenticator preferences&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authenticatorSelection?: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        authenticatorAttachment?: &amp;quot;platform&amp;quot; | &amp;quot;cross-platform&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        residentKey?: &amp;quot;required&amp;quot; | &amp;quot;preferred&amp;quot; | &amp;quot;discouraged&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        userVerification?: &amp;quot;required&amp;quot; | &amp;quot;preferred&amp;quot; | &amp;quot;discouraged&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    timeout?: number    &#x2F;&#x2F; Operation timeout in milliseconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And returns &lt;code&gt;AuthenticatorAttestationResponse&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AuthenticatorAttestationResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    clientDataJSON: ArrayBuffer,    &#x2F;&#x2F; JSON containing challenge, origin, and type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    attestationObject: ArrayBuffer  &#x2F;&#x2F; CBOR-encoded attestation data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;our-implementation-s-api&quot;&gt;Our Implementation&#x27;s API&lt;&#x2F;h3&gt;
&lt;p&gt;Format&lt;&#x2F;p&gt;
&lt;p&gt;Our server&#x27;s &lt;code&gt;&#x2F;register&#x2F;start&lt;&#x2F;code&gt; endpoint returns:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;challenge&amp;quot;: &amp;quot;base64url-encoded-random-bytes&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;rp_id&amp;quot;: &amp;quot;example.com&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;user&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;id&amp;quot;: &amp;quot;user-uuid&amp;quot;,      &#x2F;&#x2F; String UUID for easier handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;name&amp;quot;: &amp;quot;username&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;authenticatorSelection&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;authenticatorAttachment&amp;quot;: &amp;quot;platform&amp;quot;,  &#x2F;&#x2F; Prefer platform authenticators&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;residentKey&amp;quot;: &amp;quot;required&amp;quot;               &#x2F;&#x2F; Require discoverable credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And our &lt;code&gt;&#x2F;register&#x2F;finish&lt;&#x2F;code&gt; endpoint accepts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;id&amp;quot;: &amp;quot;credential-id&amp;quot;,      &#x2F;&#x2F; Base64url credential identifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;rawId&amp;quot;: &amp;quot;base64url-encoded-credential-id&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;response&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;attestationObject&amp;quot;: &amp;quot;base64url-encoded-attestation-object&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;client_data_json&amp;quot;: &amp;quot;base64url-encoded-client-data&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;user_handle&amp;quot;: &amp;quot;user-uuid&amp;quot;  &#x2F;&#x2F; Links credential to user account&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Design choices for registration:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Base64url-encode all binary data (challenge, credential ID,
attestation object)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use string UUID for user.id instead of binary format&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Require platform authenticators and resident keys for better UX&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Add explicit user_handle to maintain credential-user connection&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Omit timeout and other optional fields for simplicity&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;authentication-data&quot;&gt;Authentication Data&lt;&#x2F;h2&gt;
&lt;p&gt;Structures&lt;&#x2F;p&gt;
&lt;h3 id=&quot;standard-webauthn&quot;&gt;Standard WebAuthn&lt;&#x2F;h3&gt;
&lt;p&gt;Interfaces&lt;&#x2F;p&gt;
&lt;p&gt;The browser&#x27;s &lt;code&gt;navigator.credentials.get()&lt;&#x2F;code&gt; accepts
&lt;code&gt;PublicKeyCredentialRequestOptions&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PublicKeyCredentialRequestOptions {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenge: BufferSource,    &#x2F;&#x2F; Random bytes to prevent replay attacks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rpId?: string,          &#x2F;&#x2F; Optional domain name restriction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    allowCredentials?: [{   &#x2F;&#x2F; Optional list of allowed credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type: &amp;quot;public-key&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id: BufferSource    &#x2F;&#x2F; Credential identifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Optional user verification requirement&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    userVerification?: &amp;quot;required&amp;quot; | &amp;quot;preferred&amp;quot; | &amp;quot;discouraged&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    timeout?: number    &#x2F;&#x2F; Operation timeout in milliseconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And returns &lt;code&gt;AuthenticatorAssertionResponse&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AuthenticatorAssertionResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    clientDataJSON: ArrayBuffer,    &#x2F;&#x2F; JSON containing challenge, origin, and type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authenticatorData: ArrayBuffer, &#x2F;&#x2F; CBOR-encoded authenticator data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    signature: ArrayBuffer,         &#x2F;&#x2F; Cryptographic signature&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    userHandle?: ArrayBuffer        &#x2F;&#x2F; Optional user identifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;our-implementation-s-api-1&quot;&gt;Our Implementation&#x27;s API&lt;&#x2F;h3&gt;
&lt;p&gt;Format&lt;&#x2F;p&gt;
&lt;p&gt;Our server&#x27;s &lt;code&gt;&#x2F;auth&#x2F;start&lt;&#x2F;code&gt; endpoint returns:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;challenge&amp;quot;: &amp;quot;base64url-encoded-random-bytes&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;rp_id&amp;quot;: &amp;quot;example.com&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Optional for discoverable credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;allow_credentials&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;type&amp;quot;: &amp;quot;public-key&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;id&amp;quot;: &amp;quot;credential-id&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And our &lt;code&gt;&#x2F;auth&#x2F;verify&lt;&#x2F;code&gt; endpoint accepts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;id&amp;quot;: &amp;quot;credential-id&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;response&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;signature&amp;quot;: &amp;quot;base64url-encoded-signature&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;authenticator_data&amp;quot;: &amp;quot;base64url-encoded-authenticator-data&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;client_data_json&amp;quot;: &amp;quot;base64url-encoded-client-data&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;user_handle&amp;quot;: &amp;quot;base64url-encoded-user-handle&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Design choices for authentication:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Base64url-encode all binary data for transport&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use snake_case in API for consistency with Rust&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make user_handle required to simplify user lookup&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Support discoverable credentials by making allow_credentials
optional&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Omit timeout and user verification preferences for simplicity&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The client-side JavaScript handles all necessary conversions between
WebAuthn&#x27;s ArrayBuffer format and our API&#x27;s JSON format, using base64url
encoding for binary data. This separation of concerns keeps our API
clean while maintaining compatibility with the WebAuthn standard.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-s-next&quot;&gt;What&#x27;s Next&lt;&#x2F;h1&gt;
&lt;p&gt;While this basic implementation demonstrates the core concepts of
WebAuthn Passkeys, several enhancements would make it
production-ready:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;session-management&quot;&gt;Session management&lt;&#x2F;h2&gt;
&lt;p&gt;In production session management using session cookie or
&quot;Authentication: bearer token&quot; header. This will enable us to identify
access from authenticated users.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;oauth2-oidc-integration&quot;&gt;OAuth2&#x2F;OIDC integration&lt;&#x2F;h2&gt;
&lt;p&gt;The system could integrate with OAuth2&#x2F;OIDC providers like Google or
Apple, enabling single sign-on and unified account management. This
would allow users to seamlessly link their Passkey credentials with
existing accounts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;storage&quot;&gt;Storage&lt;&#x2F;h2&gt;
&lt;p&gt;The current in-memory storage would need to be replaced with proper
databases - SQL for user credentials and Redis for temporary challenge
states. This would provide the scalability and persistence needed for
production use.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;Building a WebAuthn Passkey implementation from scratch was an
enlightening experience that provided deep insights into both modern
authentication and Rust web development. The experience showed how
standards like WebAuthn and tools like Rust can make secure
authentication more accessible to developers, while still demanding
careful attention to security considerations.&lt;&#x2F;p&gt;
&lt;p&gt;While implementing core functionality from scratch proved to be an
invaluable learning experience, production systems should rely on
established, well-tested WebAuthn libraries that have undergone security
audits. The insights gained from this exercise, however, will prove
valuable when working with these production libraries, as understanding
WebAuthn&#x27;s internals helps make better architectural decisions.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;resources&quot;&gt;Resources&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;w3c.github.io&#x2F;webauthn&#x2F;&quot;&gt;WebAuthn Specification&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Official W3C standard&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;webauthn.guide&#x2F;&quot;&gt;WebAuthn Guide&lt;&#x2F;a&gt; - A practical
guide to implementing WebAuthn&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;passkeys.dev&#x2F;&quot;&gt;Passkeys.dev&lt;&#x2F;a&gt; - Best practices
for Passkey implementation&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;webauthn.io&#x2F;&quot;&gt;WebAuthn.io&lt;&#x2F;a&gt; - Interactive demo
and debugging tool&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Axum Google OAuth2&#x2F;OIDC implementation </title>
        <published>2024-12-05T00:00:00+00:00</published>
        <updated>2024-12-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation.html/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Modern web applications often rely on OAuth2&#x2F;OIDC for secure user
authentication. As part of a recent exploration into Rust and Axum, I
implemented a login system that integrates Google OAuth2. In this post,
I’ll walk through the details of the implementation, covering both the
theoretical aspects and practical steps involved in building a secure
authentication system.&lt;&#x2F;p&gt;
&lt;p&gt;To keep things concise, I’ve included simplified code snippets for
key components. The full implementation is available in my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;axum-google-oauth2&quot;&gt;GitHub
repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video width=&quot;600&quot; height=&quot;600&quot; src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;blog-20241206-02.mp4&quot; controls autoplay loop&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;what-are-oauth2-and-openid&quot;&gt;What Are OAuth2 and OpenID&lt;&#x2F;h3&gt;
&lt;p&gt;Connect?&lt;&#x2F;p&gt;
&lt;p&gt;OAuth2 and OpenID Connect (OIDC) are key to modern authentication
systems, and understanding how they fit together can make implementing
secure authentication easier.&lt;&#x2F;p&gt;
&lt;p&gt;OAuth2 serves as a foundation, allowing users to grant applications
access to their resources without sharing credentials. Applications
interact with these resources through access tokens. For this
implementation, I used the authorization code flow, a secure and widely
adopted approach, to retrieve user information from the identity
provider.&lt;&#x2F;p&gt;
&lt;p&gt;OIDC builds on OAuth2, adding a standardized layer for
authentication. While OAuth2 focuses on “what can this app access?”,
OIDC answers “who is this user?” It introduces the ID token, a JSON Web
Token (JWT) that contains verified user identity information. This makes
it possible to authenticate users while managing access permissions in a
single, unified flow.&lt;&#x2F;p&gt;
&lt;p&gt;In a nutshell, OAuth2 becomes more secure when extended with the ID
token under the OIDC standard.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-authentication-works&quot;&gt;How Authentication Works:&lt;&#x2F;h3&gt;
&lt;p&gt;Key Concepts&lt;&#x2F;p&gt;
&lt;h4 id=&quot;basic-authentication-flow&quot;&gt;Basic Authentication Flow&lt;&#x2F;h4&gt;
&lt;p&gt;This implementation follows a well-defined sequence for
authentication:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;fig-1.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;The process begins when a user clicks the login button, which opens a
popup and redirects to Google’s authentication page. After a successful
login, Google returns an authorization code that the server exchanges
for tokens. The server verifies ID token, creates a user session, and
sets a session cookie in the response to the browser, completing the
authentication flow. The user is subsequently identified by this cookie
in all future requests.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-session-cookies-work&quot;&gt;How Session Cookies Work&lt;&#x2F;h4&gt;
&lt;p&gt;Session cookies play a central role in maintaining authenticated
access. Once the server sets a session cookie during login, it is
automatically included in future browser requests. To ensure secure
session management, I used several measures:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HttpOnly flag&lt;&#x2F;strong&gt;: Prevents client-side script access
to cookies.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure flag&lt;&#x2F;strong&gt;: Ensures cookies are only transmitted
over HTTPS.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SameSite settings&lt;&#x2F;strong&gt;: Protects against CSRF
attacks.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;__Host-&lt;&#x2F;code&gt; prefix:&lt;&#x2F;strong&gt; Enforces HTTPS and
host-specific restrictions.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These settings work together to maintain secure authentication
states, even across multiple tabs.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;oauth2-parameters&quot;&gt;OAuth2 Parameters&lt;&#x2F;h4&gt;
&lt;p&gt;OAuth2 and OIDC define several parameters critical to the
authentication process. Here’s how I approached configuring some of the
key parameters:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;response_type&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Set to
&lt;code&gt;code&lt;&#x2F;code&gt;, as it securely delivers an authorization code.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;response_mode&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Used
&lt;code&gt;form_post&lt;&#x2F;code&gt; for better security by avoiding sensitive data in
URLs.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;scope&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Requested &lt;code&gt;openid&lt;&#x2F;code&gt;,
&lt;code&gt;email&lt;&#x2F;code&gt;, and &lt;code&gt;profile&lt;&#x2F;code&gt; for user identity and basic
information.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;state&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Contains encoded security
tokens (CSRF token, nonce ID, and PKCE ID) to prevent CSRF attacks and
maintain session state.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;code_challenge&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; and
&lt;strong&gt;&lt;code&gt;code_challenge_method&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Implements PKCE for
secure code exchange.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;nonce&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: Uniquely identifies the
authentication request and prevents replay attacks.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These parameters are essential for controlling the authentication
flow and ensuring security.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;&#x2F;h2&gt;
&lt;p&gt;The following sections break down the implementation into key
components, explaining how the OAuth2 authentication flow integrates
with session management and security mechanisms.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;authentication-flow&quot;&gt;Authentication Flow&lt;&#x2F;h3&gt;
&lt;p&gt;Our implementation uses a popup window for authentication to keep the
main page responsive. This approach:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Handles the auth flow in a separate window&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Maintains login state using shared cookies across the windows&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Updates the main page automatically when complete&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The flow coordinates between four components: browser, server,
Google, and session store. The session store manages login sessions and
security tokens (CSRF, nonce, PKCE verifier).&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;fig-2.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;This diagram captures the flow of data and interactions at each
step.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;route-structure&quot;&gt;Route Structure&lt;&#x2F;h3&gt;
&lt;p&gt;The application defines routes to manage each step of the
authentication and session flow:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let app = Router::new()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;&amp;quot;, get(index))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;auth&#x2F;google&amp;quot;, get(google_auth))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;auth&#x2F;authorized&amp;quot;, get(get_authorized).post(post_authorized))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;popup_close&amp;quot;, get(popup_close))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;logout&amp;quot;, get(logout))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;protected&amp;quot;, get(protected));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;main-page-behavior&quot;&gt;Main Page Behavior&lt;&#x2F;h3&gt;
&lt;p&gt;The main page dynamically adjusts its content based on the user’s
authentication status:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn index(user: OptionUser&amp;gt;) -&amp;gt; impl IntoResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    match user {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some(u) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let message = format!(&amp;quot;Hey {}! You&amp;#39;re logged in!&amp;quot;, u.name);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let template = IndexTemplateUser { message: &amp;amp;message };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (StatusCode::OK, Html(template.render().unwrap())).into_response()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        None =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let message = &amp;quot;You&amp;#39;re not logged in.\nClick the Login button below.&amp;quot;.to_string();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let template = IndexTemplateAnon { message: &amp;amp;message };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (StatusCode::OK, Html(template.render().unwrap())).into_response()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For authenticated users: Displays a personalized greeting.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;For anonymous users: Displays a login button to trigger the
popup-based authentication flow.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;initiating-the-oauth2-flow&quot;&gt;Initiating the OAuth2 Flow&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;&#x2F;auth&#x2F;google&lt;&#x2F;code&gt; endpoint initiates the OAuth2 flow:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Generates security tokens (CSRF and nonce).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Stores these tokens in the session.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Redirects the browser to Google’s authentication page.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn google_auth(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(params): StateOAuth2Params&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(store): StateMemoryStore&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers: HeaderMap,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate and store security tokens&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (csrf_token, csrf_id) =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        generate_store_token(&amp;quot;csrf_session&amp;quot;, expires_at, Some(user_agent), &amp;amp;store).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (nonce_token, nonce_id) =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        generate_store_token(&amp;quot;nonce_session&amp;quot;, expires_at, None, &amp;amp;store).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (pkce_token, pkce_id) =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        generate_store_token(&amp;quot;pkce_session&amp;quot;, expires_at, None, &amp;amp;store).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate PKCE challenge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let pkce_challenge = URL_SAFE_NO_PAD.encode(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Sha256::digest(pkce_token.as_bytes())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Combine tokens into a state parameter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let encoded_state = encode_state(csrf_token, nonce_id, pkce_id);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Construct the Google OAuth2 URL with required parameters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let auth_url = format!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;{}?{}&amp;amp;client_id={}&amp;amp;redirect_uri={}&amp;amp;state={}&amp;amp;nonce={}\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;code_challenge={}&amp;amp;code_challenge_method=S256&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        OAUTH2_AUTH_URL,         &#x2F;&#x2F; e.g., https:&#x2F;&#x2F;accounts.google.com&#x2F;o&#x2F;oauth2&#x2F;v2&#x2F;auth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        OAUTH2_QUERY_STRING,     &#x2F;&#x2F; e.g., response_type=code&amp;amp;scope=openid+email+profile...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        params.client_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        params.redirect_uri,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        encoded_state,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nonce_token,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pkce_challenge,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Set security cookie and prepare the redirect response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut headers = HeaderMap::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    header_set_cookie(&amp;amp;mut headers, CSRF_COOKIE_NAME, csrf_id, expires_at)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok((headers, Redirect::to(&amp;amp;auth_url)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;state-parameter&quot;&gt;State Parameter&lt;&#x2F;h4&gt;
&lt;p&gt;The state parameter combines:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CSRF token: Protects against cross-site request forgery.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Nonce ID: Validates the ID token’s authenticity.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;PKCE ID: Identifies the PKCE verifier of the request&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Base64URL encoding: Embeds multiple parameters in a URL safe single
parameter.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn encode_state(csrf_token: String, nonce_id: String, pkce_id: String) -&amp;gt; String {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let state_params = StateParams {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        csrf_token,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nonce_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pkce_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    URL_SAFE.encode(serde_json::json!(state_params).to_string())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Google preserves and returns this state parameter unchanged, enabling
security validations in the callback.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;handling-oauth2-callback&quot;&gt;Handling OAuth2 Callback&lt;&#x2F;h3&gt;
&lt;p&gt;After the user authenticates with Google, the application must
process the callback to complete the authentication process. This
includes exchanging the authorization code for tokens and validating
their authenticity.&lt;&#x2F;p&gt;
&lt;p&gt;Google returns the user’s authentication data via the
&lt;code&gt;&#x2F;auth&#x2F;authorized&lt;&#x2F;code&gt; endpoint. This endpoint supports two
modes:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;form-post-mode-recommended&quot;&gt;Form Post Mode(Recommended)&lt;&#x2F;h4&gt;
&lt;p&gt;Google returns the authorization code and state to the browser. A
Google-provided javascript sends them to the endpoint as POST body. They
are processed by:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn post_authorized(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Form(form): FormAuthResponse&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    validate_origin(&amp;amp;headers, &amp;amp;state.oauth2_params.auth_url).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authorized(&amp;amp;form, state).await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;query-mode&quot;&gt;Query Mode&lt;&#x2F;h4&gt;
&lt;p&gt;Google returns a redirect response with the authorization code and
state as URL query parameters. They are processed by:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn get_authorized(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Query(query): QueryAuthResponse&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypedHeader(cookies): TypedHeaderheaders::Cookie&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    csrf_checks(cookies.clone(), &amp;amp;state.store, &amp;amp;query, headers).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authorized(&amp;amp;query, state).await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both callback modes eventually process the authentication response
through the authorized function. This function exchanges the code for
tokens, verifies their authenticity, and establishes a user session.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn authorized(auth_response: &amp;amp;AuthResponse, state: AppState) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (access_token, id_token) = exchange_code_for_token(...).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_data = user_from_verified_idtoken(id_token, &amp;amp;state, auth_response).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Optional check for user data from userinfo endpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_data_userinfo = fetch_user_data_from_google(access_token).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if user_data.id != user_data_userinfo.id {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return Err(anyhow::anyhow!(&amp;quot;ID mismatch&amp;quot;).into());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let session_id = create_and_store_session(user_data, ...).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok((set_cookie_header(session_id), Redirect::to(&amp;quot;&#x2F;popup_close&amp;quot;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;managing-user-sessions&quot;&gt;Managing User Sessions&lt;&#x2F;h3&gt;
&lt;p&gt;Sessions ensure secure, consistent authentication across requests.
Upon successful login, a session is created and securely stored:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn create_and_store_session(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_data: User,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store: &amp;amp;MemoryStore,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expires_at: DateTimeUtc&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; ResultString, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut session = Session::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.insert(&amp;quot;user&amp;quot;, &amp;amp;user_data)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.set_expiry(expires_at);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let session_id = store.store_session(session).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(session_id)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To protect sensitive routes, the function arguments include
&lt;code&gt;user: User&lt;&#x2F;code&gt;. The &lt;code&gt;User&lt;&#x2F;code&gt; extractor automatically
verifies the session cookie and retrieves the user data for subsequent
requests:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; The &amp;quot;user: User&amp;quot; argument ensures access to authenticated user data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn protected(user: User) -&amp;gt; impl IntoResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    format!(&amp;quot;Welcome, {}!&amp;quot;, user.name)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; The User extractor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Extract cookie from the request, and retrieve user data from the session store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[async_trait]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;implS&amp;gt; FromRequestPartsS&amp;gt; for User&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MemoryStore: FromRefS&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    S: Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    async fn from_request_parts(parts: &amp;amp;mut Parts, state: &amp;amp;S) -&amp;gt; ResultSelf, Self::Rejection&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let store = MemoryStore::from_ref(state);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let session_cookie = get_session_cookie(parts)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let user = load_user_from_session(store, session_cookie).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Ok(user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Having covered the implementation details, let’s examine the security
mechanisms that protect our authentication flow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;security-considerations&quot;&gt;Security Considerations&lt;&#x2F;h2&gt;
&lt;p&gt;Our authentication implementation relies on several security
mechanisms working together. Since we use ID token claims for
authentication, these mechanisms focus on protecting the authentication
process and verifying token authenticity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nonce-validation&quot;&gt;Nonce Validation&lt;&#x2F;h3&gt;
&lt;p&gt;The nonce mechanism is crucial for verifying that the ID token we’ll
use for authentication was issued specifically for this request.&lt;&#x2F;p&gt;
&lt;p&gt;Nonce validation confirms the ID token’s authenticity by comparing
two values:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nonce in the ID token:&lt;&#x2F;strong&gt; Embedded by Google in the
signed token.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nonce from the session store:&lt;&#x2F;strong&gt; Retrieved using the
&lt;code&gt;nonce_id&lt;&#x2F;code&gt; from the state parameter.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This prevents replay attacks and ensures the token is tied to the
current authentication request.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;fig-3.png&quot; width=&quot;80%&quot;&gt;
&lt;h3 id=&quot;csrf-protection&quot;&gt;CSRF Protection&lt;&#x2F;h3&gt;
&lt;p&gt;Cross-Site Request Forgery (CSRF) protection ensures that
authentication callbacks come from legitimate auth flows initiated by
our application. Without it, malicious sites could trick authenticated
users into unwanted auth requests.&lt;&#x2F;p&gt;
&lt;p&gt;The security mechanism differs between response modes due to how
browsers handle redirects versus direct POST requests:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Query Mode Flow:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This mode requires cookie-based CSRF validation because the callback
comes as a browser redirect, which could originate from any site. The
CSRF token ensures the request chain started with our application:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;fig-4.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;&lt;strong&gt;Form Post Mode:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this mode, we can’t use CSRF cookie validation because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The callback comes as a cross-origin POST request from Google’s
domain&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Browser security blocks our &lt;code&gt;__Host-CsrfId&lt;&#x2F;code&gt; cookie from
being sent with such requests&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Instead, we rely on two security measures:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nonce validation:&lt;&#x2F;strong&gt; Confirms the ID token was issued
for our specific auth request&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Origin validation:&lt;&#x2F;strong&gt; Ensures the POST request comes
from Google’s domain&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This combination ensures that only Google can respond to our original
authentication request, preventing any malicious sites from initiating
or hijacking the authentication flow.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pkce-validation&quot;&gt;PKCE Validation&lt;&#x2F;h3&gt;
&lt;p&gt;PKCE (Proof Key for Code Exchange) is a security extension to OAuth
2.0 that protects authorization codes from being intercepted or
injected. Unlike CSRF and nonce validation which protect the
authentication flow, PKCE specifically secures the code exchange
process.&lt;&#x2F;p&gt;
&lt;p&gt;PKCE ensures that only the client that initiated the authentication
flow can exchange the authorization code for tokens:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&#x2F;image&#x2F;fig-5.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;The implementation generates a random verifier and creates a
challenge using SHA-256:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let (pkce_token, pkce_id) = generate_store_token(&amp;quot;pkce_session&amp;quot;, expires_at, None, &amp;amp;store).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let pkce_challenge = URL_SAFE_NO_PAD.encode(Sha256::digest(pkce_token.as_bytes()));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When exchanging the code for tokens, we include the original
verifier:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn exchange_code_for_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    params: OAuth2Params,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    code: String,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    code_verifier: String,  &#x2F;&#x2F; Original PKCE verifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result(String, String), AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let response = reqwest::Client::new()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .post(params.token_url)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .form(&amp;amp;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Other parameters...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (&amp;quot;code_verifier&amp;quot;, code_verifier),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This mechanism prevents:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Authorization code interception&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Code injection attempts&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Replay attacks&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Man-in-the-middle attacks during code exchange&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cookie-security&quot;&gt;Cookie Security&lt;&#x2F;h3&gt;
&lt;p&gt;All cookies use comprehensive security settings:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;{name}={value}; SameSite=Lax; Secure; HttpOnly; Path=&#x2F;; Max-Age={max_age}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;HttpOnly:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; Prevents JavaScript access
to cookies.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Secure:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; Ensures transmission occurs
only over HTTPS.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;SameSite=Lax:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; Guards against CSRF
while allowing same-origin navigation.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;__Host-&lt;&#x2F;code&gt; prefix:&lt;&#x2F;strong&gt; Enforces HTTPS and
host-specific restrictions.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These settings ensure cookies are protected from common attack
vectors.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;response-mode-security&quot;&gt;Response Mode Security&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Form Post Mode (Recommended)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Authorization code is included in the POST body, keeping it hidden
from URLs and logs.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Security relies on &lt;strong&gt;origin validation&lt;&#x2F;strong&gt; and
&lt;strong&gt;nonce verification&lt;&#x2F;strong&gt; .&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The most secure option for production use.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Query Mode&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Authorization code is visible in the URL, making it easier to debug
but more prone to exposure (e.g., logs, bookmarks).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Offers full CSRF protection but carries a higher risk of leakage in
environments where URLs are recorded.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;authentication-with&quot;&gt;Authentication with&lt;&#x2F;h3&gt;
&lt;p&gt;Authorization Code Flow&lt;&#x2F;p&gt;
&lt;p&gt;The authorization code flow (&lt;code&gt;response_type=code&lt;&#x2F;code&gt;) offers
key security advantages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure Token Exchange:&lt;&#x2F;strong&gt; Tokens are obtained through
secure server-to-server communication&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security Best Practice:&lt;&#x2F;strong&gt; Recommended approach for
production applications&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;id-token-validation&quot;&gt;ID Token Validation&lt;&#x2F;h3&gt;
&lt;p&gt;The ID token, a cryptographically signed JWT, provides secure
authentication through its claims:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;aud&lt;&#x2F;code&gt;: Ensures token was issued for our application&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;iss&lt;&#x2F;code&gt;: Verifies Google as the token issuer&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;exp&lt;&#x2F;code&gt; and &lt;code&gt;iat&lt;&#x2F;code&gt;: Prevent token reuse and
replay attacks&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;nonce&lt;&#x2F;code&gt;: Binds token to our specific auth request&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While Google’s userinfo endpoint provides similar data, we rely on ID
token validation because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Claims are cryptographically secured by Google’s signature&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Validation is faster than additional userinfo requests&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Userinfo endpoint is better suited for fetching optional profile
data&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this implementation, I’ve walked through building a secure
OAuth2&#x2F;OIDC authentication system with Axum. While implementing auth can
be complex, breaking it down into manageable components helped create a
system that’s both secure and maintainable. The code demonstrates
practical patterns that you might find useful in your own projects
for:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Token validation and CSRF protection&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;PKCE implementation for code exchange security&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Comprehensive session management&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’ve posted the complete implementation on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;axum-google-oauth2&quot;&gt;GitHub&lt;&#x2F;a&gt;. Take
a look if you’re interested in the implementation details - I’m
particularly curious about your thoughts on the security measures and
session handling approach. If you spot any potential improvements or
have questions about specific design choices, I’d love to hear your
feedback!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>AxumでGoogle OAuth2&#x2F;OIDC認証を実装する</title>
        <published>2024-12-05T00:00:00+00:00</published>
        <updated>2024-12-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation_0937899567.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation_0937899567.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2024/12/axum-google-oauth2oidc-implementation_0937899567.html/">&lt;p&gt;この記事は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;qiita.com&#x2F;advent-calendar&#x2F;2024&#x2F;rust&quot;&gt;Rust
Advent Calendar 2024&lt;&#x2F;a&gt; シリーズ2の6日目の記事です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;RustとAxumを使って、Google
OAuth2でのログイン機能を実装しました。OAuth2とOIDCを使った認証は現代のWebアプリケーションでは一般的な方法です。この記事では、安全な認証システムを作るために必要な基礎知識と、具体的な実装方法を説明します。&lt;&#x2F;p&gt;
&lt;p&gt;ソースコードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;axum-google-oauth2&quot;&gt;GitHubリポジトリ&lt;&#x2F;a&gt;で公開しています。記事中のコードは理解のために簡略化していますので、完全な実装はリポジトリをご覧ください。
(本稿は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation.html&quot;&gt;英語版&lt;&#x2F;a&gt;からの翻訳記事です。)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video width=&quot;600&quot; height=&quot;600&quot; src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation_0937899567.html&#x2F;image&#x2F;blog-20241206-02.mp4&quot; controls autoplay loop&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gai-yao&quot;&gt;概要&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;oauth2toopenid-connecttoha&quot;&gt;OAuth2とOpenID Connectとは&lt;&#x2F;h3&gt;
&lt;p&gt;OAuth2とOpenID
Connect（OIDC）は、現代のWebアプリケーションの認証を支える重要な技術です。&lt;&#x2F;p&gt;
&lt;p&gt;OAuth2は認証の基盤となる技術で、ユーザーが自分の認証情報を直接渡すことなく、アプリケーションに特定の機能へのアクセス権を与えることができます。アプリケーションはアクセストークン（access
token）を使ってこれらの機能を利用します。この実装では、広く使われている安全な方法である認可コードフロー（authorization
code flow）を使って、ユーザー情報を取得しています。&lt;&#x2F;p&gt;
&lt;p&gt;OpenID
Connect（OIDC）は、OAuth2を拡張して標準的な認証の仕組みを追加したものです。OAuth2が「アプリケーションに何を許可するか」を扱うのに対し、OIDCは「このユーザーは誰か」を確認することを主な目的としています。OIDCでは、ユーザー情報をJSON
Web Token（JWT）形式のIDトークン（ID
token）として提供します。これにより、ユーザーの認証とアクセス権限の管理を一度に行えます。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、OIDCを使うことで、OAuth2をより安全に使えるようになります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ren-zheng-noshi-zu-mi&quot;&gt;認証の仕組み&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;ji-ben-de-naren-zheng-huro&quot;&gt;基本的な認証フロー&lt;&#x2F;h4&gt;
&lt;p&gt;この実装での認証は、以下のような手順で行われます：&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation_0937899567.html&#x2F;image&#x2F;fig-1.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;認証の流れを詳しく説明します：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ユーザーがログインボタンを押すと、ポップアップウィンドウが開きます&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ポップアップウィンドウがGoogleの認証ページに移動します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ユーザーがGoogleアカウントでログインし、アプリケーションへの権限を承認します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Googleが認可コード（authorization code）を返します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;この認可コードを使って、サーバーがトークンを取得します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバーがIDトークンを検証し、ユーザーセッションを作成します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;セッションCookieをブラウザに設定して認証を完了します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以降、ユーザーはこのセッションCookieを使って認証済みユーザーとして識別されます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;setusiyoncookienoshi-zu-mi&quot;&gt;セッションCookieの仕組み&lt;&#x2F;h4&gt;
&lt;p&gt;セッションCookieはユーザーの認証状態を維持するために使われます。ログイン時にサーバーが設定したCookieは、その後のすべてのリクエストに自動的に含まれます。セキュリティを確保するため、以下の設定を使用しています：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HttpOnly&lt;&#x2F;strong&gt;:
JavaScriptからCookieを読み取れないようにし、XSS攻撃から保護します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure&lt;&#x2F;strong&gt;:
HTTPS接続でのみCookieを送信し、通信の安全性を確保します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SameSite&lt;&#x2F;strong&gt;:
同じサイトからのリクエストのみCookieを送信可能にし、CSRF攻撃を防ぎます&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;__Host-&lt;&#x2F;code&gt;プレフィックス&lt;&#x2F;strong&gt;:
CookieをHTTPSと特定のホストに限定し、セキュリティを強化します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;oauth2noshe-ding&quot;&gt;OAuth2の設定&lt;&#x2F;h4&gt;
&lt;p&gt;認証プロセスでは、以下のパラメータを使用します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;static OAUTH2_QUERY_STRING: &amp;amp;str = &amp;quot;response_type=code\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;amp;scope=openid+email+profile\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;amp;response_mode=form_post\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;amp;access_type=online\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;amp;prompt=consent&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これらのパラメータの役割は：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;response_type=code&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:
認可コードを使用した安全な認証方式を指定します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;scope=openid email profile&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:
アプリケーションが必要とするユーザー情報の範囲を指定します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;response_mode=form_post&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:
認証情報をURLに露出せず、POSTリクエストで送信します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-zhuang-noxiang-xi&quot;&gt;実装の詳細&lt;&#x2F;h2&gt;
&lt;p&gt;ここからは、OAuth2認証フローの具体的な実装方法について説明します。認証フロー、セッション管理、セキュリティ機能がどのように連携しているかを見ていきましょう。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ren-zheng-huronoshi-zhuang&quot;&gt;認証フローの実装&lt;&#x2F;h3&gt;
&lt;p&gt;この実装では、ユーザー体験を向上させるため、ポップアップウィンドウで認証を行います：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;メインページは操作可能なまま、別ウィンドウで認証処理を実行&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Cookieを使ってウィンドウ間で認証状態を共有&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;認証完了後、自動的にメインページを更新&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;システムは以下の4つのコンポーネントで構成されています：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ブラウザ: ユーザーインターフェースを提供&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバー: 認証フローを制御&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Google: 認証サービスを提供&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;セッションストア: セッションとセキュリティトークンを管理&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation_0937899567.html&#x2F;image&#x2F;fig-2.png&quot; width=&quot;80%&quot;&gt;
&lt;h3 id=&quot;apurikesiyonnogou-zao&quot;&gt;アプリケーションの構造&lt;&#x2F;h3&gt;
&lt;p&gt;認証フローの各段階を処理するため、以下のようなルート構造を実装しています：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let app = Router::new()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;&amp;quot;, get(index))                    &#x2F;&#x2F; メインページ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;auth&#x2F;google&amp;quot;, get(google_auth))   &#x2F;&#x2F; Google認証の開始&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;auth&#x2F;authorized&amp;quot;, get(get_authorized).post(post_authorized))  &#x2F;&#x2F; 認証後のコールバック&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;popup_close&amp;quot;, get(popup_close))   &#x2F;&#x2F; ポップアップの終了&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;logout&amp;quot;, get(logout))             &#x2F;&#x2F; ログアウト&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .route(&amp;quot;&#x2F;protected&amp;quot;, get(protected));      &#x2F;&#x2F; 認証必須ページ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;meinpezinoshi-zhuang&quot;&gt;メインページの実装&lt;&#x2F;h3&gt;
&lt;p&gt;メインページは、ユーザーの認証状態に応じて表示を切り替えます：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn index(user: OptionUser&amp;gt;) -&amp;gt; impl IntoResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    match user {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; 認証済みの場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some(u) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let message = format!(&amp;quot;ようこそ、{}さん！&amp;quot;, u.name);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let template = IndexTemplateUser { message: &amp;amp;message };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (StatusCode::OK, Html(template.render().unwrap())).into_response()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; 未認証の場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        None =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let message = &amp;quot;ログインボタンをクリックしてください。&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let template = IndexTemplateAnon { message: &amp;amp;message };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (StatusCode::OK, Html(template.render().unwrap())).into_response()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;ren-zheng-huronokai-shi&quot;&gt;認証フローの開始&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;&#x2F;auth&#x2F;google&lt;&#x2F;code&gt;エンドポイントでは、以下の3つの処理を行います：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;セキュリティトークンの生成&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;セッションへの保存&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Google認証ページへのリダイレクト&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn google_auth(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(params): StateOAuth2Params&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(store): StateMemoryStore&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers: HeaderMap,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; セキュリティトークンを生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (csrf_token, csrf_id) = generate_store_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;csrf_session&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expires_at,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some(user_agent)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (nonce_token, nonce_id) = generate_store_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;nonce_session&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expires_at,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Google認証URLの生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let encoded_state = encode_state(csrf_token, nonce_id);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let auth_url = format!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;{}?{}&amp;amp;client_id={}&amp;amp;redirect_uri={}&amp;amp;state={}&amp;amp;nonce={}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        OAUTH2_AUTH_URL,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        OAUTH2_QUERY_STRING,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        params.client_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        params.redirect_uri,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        encoded_state,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nonce_token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; CSRFトークンをCookieに設定してリダイレクト&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut headers = HeaderMap::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    header_set_cookie(&amp;amp;mut headers, CSRF_COOKIE_NAME, csrf_id, expires_at)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok((headers, Redirect::to(&amp;amp;auth_url)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;korubatukuchu-li&quot;&gt;コールバック処理&lt;&#x2F;h3&gt;
&lt;p&gt;Googleからの認証データは、2つの方法で受け取ることができます：&lt;&#x2F;p&gt;
&lt;h4 id=&quot;huomuposutomodo-tui-jiang&quot;&gt;フォームポストモード（推奨）&lt;&#x2F;h4&gt;
&lt;p&gt;Google提供のJavaScriptがPOSTリクエストで認証データを送信します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn post_authorized(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Form(form): FormAuthResponse&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; リクエスト元の確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    validate_origin(&amp;amp;headers, &amp;amp;state.oauth2_params.auth_url).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 認証データの処理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authorized(&amp;amp;form, state).await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;kuerimodo&quot;&gt;クエリモード&lt;&#x2F;h4&gt;
&lt;p&gt;認証データがURLパラメータとして送信されます：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn get_authorized(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Query(query): QueryAuthResponse&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    State(state): StateAppState&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypedHeader(cookies): TypedHeaderheaders::Cookie&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; CSRFトークンの検証&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    csrf_checks(cookies.clone(), &amp;amp;state.store, &amp;amp;query, headers).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 認証データの処理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    authorized(&amp;amp;query, state).await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;どちらのモードでも、最終的に&lt;code&gt;authorized&lt;&#x2F;code&gt;関数で認証処理を完了します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn authorized(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    auth_response: &amp;amp;AuthResponse,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state: AppState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Resultimpl IntoResponse, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 認可コードをトークンに交換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (access_token, id_token) = exchange_code_for_token(...).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; IDトークンを検証してユーザー情報を取得&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_data = user_from_verified_idtoken(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id_token,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;state,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        auth_response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ユーザー情報の追加確認（オプション）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_data_userinfo = fetch_user_data_from_google(access_token).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if user_data.id != user_data_userinfo.id {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return Err(anyhow::anyhow!(&amp;quot;IDが一致しません&amp;quot;).into());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; セッションの作成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let session_id = create_and_store_session(user_data, ...).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        set_cookie_header(session_id),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Redirect::to(&amp;quot;&#x2F;popup_close&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;setusiyonguan-li&quot;&gt;セッション管理&lt;&#x2F;h3&gt;
&lt;p&gt;認証後のユーザー情報は、セッションに保存して管理します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn create_and_store_session(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_data: User,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store: &amp;amp;MemoryStore,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expires_at: DateTimeUtc&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; ResultString, AppError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut session = Session::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.insert(&amp;quot;user&amp;quot;, &amp;amp;user_data)?;      &#x2F;&#x2F; ユーザー情報を保存&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.set_expiry(expires_at);           &#x2F;&#x2F; セッション有効期限を設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let session_id = store.store_session(session).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(session_id)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;認証が必要なページは、&lt;code&gt;User&lt;&#x2F;code&gt;エクストラクタを使って保護します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; 認証が必要なページの例&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async fn protected(user: User) -&amp;gt; impl IntoResponse {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    format!(&amp;quot;ようこそ、{}さん！&amp;quot;, user.name)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Userエクストラクタの実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[async_trait]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;implS&amp;gt; FromRequestPartsS&amp;gt; for User&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MemoryStore: FromRefS&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    S: Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    async fn from_request_parts(parts: &amp;amp;mut Parts, state: &amp;amp;S) -&amp;gt; ResultSelf, Self::Rejection&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let store = MemoryStore::from_ref(state);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let session_cookie = get_session_cookie(parts)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let user = load_user_from_session(store, session_cookie).await?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Ok(user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;sekiyuriteidui-ce-noxiang-xi&quot;&gt;セキュリティ対策の詳細&lt;&#x2F;h2&gt;
&lt;p&gt;この実装では、複数のセキュリティメカニズムを組み合わせて認証の安全性を確保しています。IDトークンを用いた認証では、これらのメカニズムが認証プロセスの保護とトークンの正当性の検証に重要な役割を果たします。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nonceniyorujian-zheng&quot;&gt;Nonceによる検証&lt;&#x2F;h3&gt;
&lt;p&gt;nonceメカニズムは、IDトークンが特定のリクエストのために発行されたものであることを検証するために重要です。&lt;&#x2F;p&gt;
&lt;p&gt;Nonce検証は以下の2つの値を比較することでIDトークンの真正性を確認します：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IDトークン内のnonce:&lt;&#x2F;strong&gt;
Googleによって署名されたトークンに埋め込まれます&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;セッションストアからのnonce:&lt;&#x2F;strong&gt;
stateパラメータの&lt;code&gt;nonce_id&lt;&#x2F;code&gt;を使用して取得します&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これによりリプレイ攻撃を防ぎ、トークンが現在の認証リクエストに紐付けられていることを確認します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation_0937899567.html&#x2F;image&#x2F;fig-3.png&quot; width=&quot;80%&quot;&gt;
&lt;h3 id=&quot;csrfbao-hu&quot;&gt;CSRF保護&lt;&#x2F;h3&gt;
&lt;p&gt;クロスサイトリクエストフォージェリ（CSRF）保護は、認証コールバックが我々のアプリケーションから開始された正当な認証フローからのものであることを確保します。これがないと、悪意のあるサイトが認証済みユーザーを望まない認証リクエストに誘導する可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;セキュリティメカニズムは、ブラウザがリダイレクトと直接のPOSTリクエストをどのように扱うかの違いにより、レスポンスモードによって異なります：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;クエリモードフロー：&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;このモードではCookieベースのCSRF検証が必要です。コールバックはブラウザのリダイレクトとして来るため、任意のサイトから発生する可能性があるためです。CSRFトークンは、リクエストチェーンが我々のアプリケーションから開始されたことを確認します：&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;12&#x2F;axum-google-oauth2oidc-implementation_0937899567.html&#x2F;image&#x2F;fig-4.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;&lt;strong&gt;フォームポストモード：&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;このモードではCSRF Cookie検証を使用できません。理由は：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;コールバックはGoogleのドメインからのクロスオリジンPOSTリクエストとして来る&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ブラウザのセキュリティにより、そのようなリクエストで&lt;code&gt;__Host-CsrfId&lt;&#x2F;code&gt;
Cookieが送信されることがブロックされる&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;代わりに、以下の2つのセキュリティ対策に依存します：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nonce検証：&lt;&#x2F;strong&gt;
IDトークンが我々の特定の認証リクエストのために発行されたことを確認&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Origin検証：&lt;&#x2F;strong&gt;
POSTリクエストがGoogleのドメインから来ることを確認&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この組み合わせにより、Googleのみが我々の元の認証リクエストに応答できることを確保し、悪意のあるサイトが認証フローを開始または乗っ取ることを防ぎます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cookienosekiyuritei&quot;&gt;Cookieのセキュリティ&lt;&#x2F;h3&gt;
&lt;p&gt;すべてのCookieは包括的なセキュリティ設定を使用します：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;{name}={value}; SameSite=Lax; Secure; HttpOnly; Path=&#x2F;; Max-Age={max_age}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;HttpOnly:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;
JavaScriptからのCookieへのアクセスを防止&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Secure:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;
HTTPS経由でのみ送信されることを確保&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;SameSite=Lax:&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;
同一オリジンのナビゲーションを許可しながらCSRFを防止&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;__Host-&lt;&#x2F;code&gt;プレフィックス:&lt;&#x2F;strong&gt;
HTTPSとホスト固有の制限を強制&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの設定により、Cookieが一般的な攻撃ベクトルから保護されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;resuponsumodonosekiyuritei&quot;&gt;レスポンスモードのセキュリティ&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;フォームポストモード（推奨）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;認可コードがPOSTボディに含まれ、URLやログから隠される&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;セキュリティは&lt;strong&gt;オリジン検証&lt;&#x2F;strong&gt;と&lt;strong&gt;nonce検証&lt;&#x2F;strong&gt;に依存&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;本番環境での使用に最も安全なオプション&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;クエリモード&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;認可コードがURLに表示され、デバッグは容易だが露出のリスクが高い（ログ、ブックマークなど）&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;完全なCSRF保護を提供するが、URLが記録される環境では漏洩のリスクが高い&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;ren-ke-kodohuroniyoruren-zheng&quot;&gt;認可コードフローによる認証&lt;&#x2F;h3&gt;
&lt;p&gt;認可コードフロー（&lt;code&gt;response_type=code&lt;&#x2F;code&gt;）は重要なセキュリティ上の利点を提供します：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;セキュアなトークン交換：&lt;&#x2F;strong&gt;
トークンはセキュアなサーバー間通信を通じて取得&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;セキュリティのベストプラクティス：&lt;&#x2F;strong&gt;
本番アプリケーションに推奨されるアプローチ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;idtokunnojian-zheng&quot;&gt;IDトークンの検証&lt;&#x2F;h3&gt;
&lt;p&gt;IDトークンは暗号的に署名されたJWTで、そのクレームを通じてセキュアな認証を提供します：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;aud&lt;&#x2F;code&gt;:
トークンが我々のアプリケーションのために発行されたことを確認&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;iss&lt;&#x2F;code&gt;: Googleをトークン発行者として検証&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;exp&lt;&#x2F;code&gt;と&lt;code&gt;iat&lt;&#x2F;code&gt;:
トークンの再利用とリプレイ攻撃を防止&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;nonce&lt;&#x2F;code&gt;:
トークンを我々の特定の認証リクエストに紐付け&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Googleのuserinfoエンドポイントでも同様のデータが提供されますが、IDトークン検証を採用する理由は：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;クレームがGoogleの署名により暗号的に保護されている&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;userinfoリクエストよりも検証が高速&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;userinfoエンドポイントはオプションのプロフィールデータの取得に適している&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;owarini&quot;&gt;おわりに&lt;&#x2F;h2&gt;
&lt;p&gt;本記事では、Axumを用いたセキュアなOAuth2&#x2F;OIDC認証システムの構築方法について説明しました。認証の実装は複雑になりがちですが、機能を管理可能なコンポーネントに分割することで、セキュアで保守性の高いシステムを実現することができました。この実装は、トークンの検証、CSRF保護、セッション管理といった実践的なパターンを示しており、ご自身のプロジェクトに応用できるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;完全な実装コードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;axum-google-oauth2&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開しています。詳細に興味のある方はぜひご覧ください。特に、セキュリティ対策やセッション管理の設計に関するご意見をお聞かせいただければ幸いです。さらに改善の余地や特定の設計選択についての質問があれば、ぜひフィードバックをお寄せください！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Sign in with Google vs OpenID Connect: Understanding the difference</title>
        <published>2024-10-28T00:00:00+00:00</published>
        <updated>2024-10-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2024/10/sign-in-with-google-vs-openid-connect.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2024/10/sign-in-with-google-vs-openid-connect.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2024/10/sign-in-with-google-vs-openid-connect.html/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;Third-party authentication has become ubiquitous in modern web
applications, allowing users to sign in using existing accounts from
major providers. While OAuth 2.0 and OpenID Connect (OIDC) are the
standard protocols for implementing such authentication, Google offers
two distinct approaches - the standard OIDC implementation and Sign in
with Google - whose relationship is often misunderstood. The similarity
between Sign in with Google and OIDC’s implicit flow can be particularly
misleading. Though they share some characteristics, such as direct ID
token delivery, they are fundamentally different implementations with
distinct capabilities and limitations.&lt;&#x2F;p&gt;
&lt;p&gt;This confusion is understandable. Sign in with Google’s token
delivery mechanism resembles OIDC’s implicit flow
(response_type=id_token), leading developers to assume it’s simply a
wrapper around OIDC. However, this surface-level similarity masks
significant differences in protocol implementation, security models, and
available features.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on Documentation&lt;&#x2F;strong&gt;: Google’s own &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;gsi&#x2F;web&#x2F;guides&#x2F;overview&quot;&gt;documentation&lt;&#x2F;a&gt;
states that “Sign in with Google is based on OAuth 2.0”. However, the
same documentation describes it as a proprietary SDK that “aims to offer
an easier and more secure experience for developers than the standard
OAuth and OpenID Connect protocols”. This mixed messaging has
contributed to developer confusion. While Sign in with Google might be
inspired by OAuth 2.0 concepts, its actual implementation is a
proprietary protocol that diverges significantly from standard OAuth
2.0&#x2F;OIDC flows.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;technical-relationship&quot;&gt;Technical Relationship&lt;&#x2F;h1&gt;
&lt;p&gt;The resemblance between Sign in with Google and OIDC is apparent when
examining OIDC’s implicit flow configuration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response_type=id_token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response_mode=query&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both approaches deliver ID tokens directly to the frontend. However,
this architectural similarity obscures fundamental differences in
implementation, security considerations, and extensibility. While Sign
in with Google provides a streamlined, Google-specific authentication
solution, OIDC offers a comprehensive, standardized protocol with
multiple flows and security options.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;implementation-comparison&quot;&gt;Implementation Comparison&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;sign-in-with-google&quot;&gt;Sign in with Google&lt;&#x2F;h2&gt;
&lt;p&gt;Sign in with Google provides a simplified implementation through its
Identity Services API:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Simple initialization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;google.accounts.id.initialize({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  client_id: &amp;#39;YOUR_CLIENT_ID&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  callback: handleCredentialResponse,  &#x2F;&#x2F; for popup mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  login_uri: &amp;#39;YOUR_LOGIN_URI&amp;#39;         &#x2F;&#x2F; for redirect mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Callback receives:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  credential: &amp;quot;eyJhbGci...&amp;quot; &#x2F;&#x2F; JWT ID token containing user information&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Google Sign in page (loaded either in a popup window or
redirected main window) receives an ID token from &#x2F;gsi&#x2F;issue endpoint
and then: In popup mode: passes it to the main window’s callback
function via gsi_client.js In redirect mode: posts it to the specified
login_uri&lt;&#x2F;p&gt;
&lt;h2 id=&quot;standard-oidc&quot;&gt;Standard OIDC&lt;&#x2F;h2&gt;
&lt;p&gt;OIDC provides multiple implementation options, accommodating
different security needs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Implicit Flow (Similar to Sign in with Google)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;authorize?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response_type=id_token&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response_mode=query&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client_id=...&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scope=openid profile&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redirect_uri=...&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nonce=...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Code Flow (More secure alternative)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;authorize?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response_type=code&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client_id=...&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scope=openid profile&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redirect_uri=...&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;state=...&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nonce=...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The client (on the web browser) can receive an ID token or
authorization code as parameters in the redirect URL.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;authentication-flows&quot;&gt;Authentication Flows&lt;&#x2F;h1&gt;
&lt;p&gt;The flow differences reveal the architectural distinctions between
these approaches. Sign in with Google implements a flow similar to
OIDC’s implicit flow. However, OIDC also provides the code flow, which
offers enhanced security through backend token exchange.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sign-in-with-google-flow&quot;&gt;Sign in with Google Flow&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+-------------+  1. Init Sign-in   +----------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|   Web App   | ----------------&amp;gt;  |                |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|  (Browser)  |                    |  Google Auth   |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|             |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sign in with Google implements a straightforward flow focused on ID
token delivery. While this approach simplifies implementation, it comes
with security considerations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Applications typically need to establish sessions with their backend
servers, requiring the ID token to be transmitted from the frontend to
the backend&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ID tokens contain sensitive user information and are meant for
authentication&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ID tokens are not designed to be passed between different parties -
they should ideally only flow from the authentication provider to the
intended recipient&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In contrast, authorization codes in OIDC’s code flow are specifically
designed for such transmission through the frontend.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;oidc-code-flow&quot;&gt;OIDC Code Flow&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+-------------+  1. Init Auth      +----------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|   Web App   | ----------------&amp;gt;  |                |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|  (Browser)  |                    |  Google Auth   |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|             |  |                |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|   Server    | code + client_id       | Google&amp;#39;s       |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|             |      + client_secret   | Token endpoint |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|             |                        |                |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|             |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The OIDC code flow demonstrates the protocol’s flexibility, offering
enhanced security through backend token exchange and supporting
additional features like refresh tokens.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;implementation-distinctions&quot;&gt;Implementation Distinctions&lt;&#x2F;h1&gt;
&lt;p&gt;The divergence between these approaches manifests in several key
areas:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protocol-implementation&quot;&gt;Protocol Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;Sign in with Google employs a proprietary implementation that, while
similar to OIDC’s implicit flow, uses custom mechanisms and focuses
solely on authentication. This specialization allows for a simpler
developer experience but limits flexibility and provider
portability.&lt;&#x2F;p&gt;
&lt;p&gt;Standard OIDC, conversely, implements a complete authentication and
authorization protocol. It supports multiple flows, token types, and
security models, enabling developers to choose the most appropriate
approach for their specific requirements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;security-considerations&quot;&gt;Security Considerations&lt;&#x2F;h2&gt;
&lt;p&gt;The security models reflect different priorities. Sign in with Google
optimizes for simplicity, handling tokens in the frontend with a
predetermined security model. OIDC provides more options, including the
secure code flow that keeps sensitive tokens server-side and supports
various security configurations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;feature-scope&quot;&gt;Feature Scope&lt;&#x2F;h2&gt;
&lt;p&gt;Sign in with Google’s focused approach provides efficient
authentication but limits additional capabilities. OIDC’s comprehensive
protocol supports various authentication and authorization scenarios,
multiple token types, and standardized endpoints.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;choosing-the-right-approach&quot;&gt;Choosing the Right Approach&lt;&#x2F;h1&gt;
&lt;p&gt;The selection between Sign in with Google and OIDC should be guided
by specific project requirements:&lt;&#x2F;p&gt;
&lt;p&gt;Sign in with Google excels in scenarios requiring quick
implementation of Google-specific authentication, particularly when
additional OAuth features aren’t needed. Its simplified approach can
accelerate development for straightforward authentication needs.&lt;&#x2F;p&gt;
&lt;p&gt;Standard OIDC becomes essential when projects require provider
flexibility, enhanced security options, or additional OAuth features.
Its standardized approach supports long-term maintainability and
compliance requirements, though at the cost of increased implementation
complexity.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;While Sign in with Google shares surface similarities with OIDC’s
implicit flow, understanding their distinct implementations is crucial
for informed architectural decisions. The resemblance in token delivery
mechanisms can mask significant differences in protocol implementation,
security models, and available features.&lt;&#x2F;p&gt;
&lt;p&gt;Developers should consider carefully whether their projects benefit
more from Sign in with Google’s streamlined, focused approach or OIDC’s
comprehensive, standardized protocol. This decision impacts not only
initial implementation but also long-term maintenance, security posture,
and provider flexibility.&lt;&#x2F;p&gt;
&lt;p&gt;Remember: The similarity between Sign in with Google and OIDC’s
implicit flow can be misleading. While they share some characteristics,
they are different implementations with distinct capabilities and
limitations.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Sign in with Google in HTMX+FastAPI</title>
        <published>2024-02-02T00:00:00+00:00</published>
        <updated>2024-02-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2024/02/sign-in-with-google-in-htmxfastapi.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2024/02/sign-in-with-google-in-htmxfastapi.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2024/02/sign-in-with-google-in-htmxfastapi.html/">&lt;h1 id=&quot;tl-dr&quot;&gt;TL;DR&lt;&#x2F;h1&gt;
&lt;p&gt;The “Sign in with Google” feature has been integrated into a sample
HTMX+FastAPI web application. Either an HTML or JavaScript version of a
code snippet from Google’s code generator is included in the HTML to
display the button. The FastAPI backend has been configured to create a
session from the JWT and set “Set-Cookie: session_id” in the header,
enabling subsequent communications to maintain the login status through
a session cookie. Thanks to HTMX functionality, the application page can
dynamically fetch the navigation bar upon a change in login status,
indicating whether the user is logged in.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;As an aspiring full-stack software developer, I’ve been teaching
myself various front-end web technologies recently. These include
React.js, Svelte, and other shiny new JavaScript frameworks, which can
sometimes be overwhelming. I was considering settling on Svelte, thanks
to its simplicity in state management, when I discovered a concept
called Hypermedia as the Engine of Application State (HATEOAS) and a
library named htmx.js.&lt;&#x2F;p&gt;
&lt;p&gt;Initially, I didn’t quite grasp how it differed from other
technologies. However, after creating several web pages for practice, I
realized I didn’t need to switch into a dedicated front-end programming
mode. I felt liberated from the struggle of forcing myself into the
React mental model, which always seemed nonsensical to me. I often
questioned, ‘Why must I change my mental model every time I create a
small piece of a web page?’&lt;&#x2F;p&gt;
&lt;p&gt;With htmx.js, I can simply create a page, and when I need to change
parts of it, I just fire an AJAX request using hx-get and swap the DOM
elements with HTML fragments in the response. I understand that as a web
application becomes more complex, there might be situations where more
feature-rich technologies are necessary. But now, I’m no longer
intimidated by the overwhelming ecosystems of each technology.&lt;&#x2F;p&gt;
&lt;p&gt;Now, I wanted to explore how I could implement a login feature in a
web application, specifically using the ‘Sign in with Google’ feature on
a web page developed with HTMX and FastAPI. So, I did a bit of research
and figured out how to do it. Noticing a lack of use cases on the web
for this particular combination of technologies, I decided to share my
findings.&lt;&#x2F;p&gt;
&lt;p&gt;While integrating the ‘Sign in with Google’ button into an HTMX page
isn’t much different from incorporating it into a standard HTML page,
the following aspects seemed particularly noteworthy:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;How to display the status after a successful login or logout using
HTMX.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The handling of the JWT after a successful login on Google’s
side.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;How to maintain a session via a cookie generated upon successful JWT
verification, rather than solely relying on the JWT for session
management.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These points are especially relevant for beginners like myself.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-i-implemented&quot;&gt;What I Implemented&lt;&#x2F;h1&gt;
&lt;p&gt;The webpage I developed using FastAPI and HTMX is shown in the figure
below. This page integrates a ‘Sign in with Google’ option, enhancing
user experience and offering a secure login method.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;02&#x2F;sign-in-with-google-in-htmxfastapi.html&#x2F;image&#x2F;FastAPI-HTMX-Google-OAuth043.gif&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;The process begins when a user clicks on the Google logo. A pop-up
window appears, guiding them through the Google account selection and
authentication process, which is then executed seamlessly in the
background.&lt;&#x2F;p&gt;
&lt;p&gt;After logging in, the webpage dynamically updates the navigation bar
to include the user’s Google account icon. Additionally, menu elements
like ‘Secret#1’ become accessible, revealing exclusive content with a
single click.&lt;&#x2F;p&gt;
&lt;p&gt;Logging out is just as intuitive. Clicking the ‘Exit’ icon signs the
user out, reverting the navigation bar to its default state for
anonymous visitors.&lt;&#x2F;p&gt;
&lt;p&gt;The source code is available on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;fastapi-htmx-google-oauth&#x2F;tree&#x2F;v1.0.0&quot;&gt;my
GitHub repo.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;anonymous-user-page&quot;&gt;Anonymous User Page&lt;&#x2F;h2&gt;
&lt;p&gt;The figure below shows a screenshot of the anonymous user page, which
will be explained in more detail. The page consists of a navigation bar
and a content section. On the navigation bar, an anonymous user icon,
menus including the ones to secret pages, and a Google Sign-in button
are shown. In this example, the ‘Secret#1’ menu is disabled. The
‘Secret#2’ menu is not disabled; however, clicking it will return an
access forbidden error.&lt;&#x2F;p&gt;
&lt;p&gt;The section below the navigation bar is the content section showing
the “Incremental hx-get demo” page, which is accessible by both
anonymous and authenticated users.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;02&#x2F;sign-in-with-google-in-htmxfastapi.html&#x2F;image&#x2F;page1.drawio.png&quot; width=&quot;90%&quot;&gt;
&lt;h2 id=&quot;authenticated-user-page&quot;&gt;Authenticated User Page&lt;&#x2F;h2&gt;
&lt;p&gt;The figure below shows a screenshot of the authenticated user page,
which also consists of a navigation bar and content section. Shown on
the navigation bar are the user’s Google account icon, menus including
the ones to secret pages, and a Sign-out button. When the user is
authenticated, the menus to the secret pages are both accessible and
return the contents.&lt;&#x2F;p&gt;
&lt;p&gt;The section below the navigation bar is the content section showing
the content of the ‘Secret#1’ page, which is accessible only by
authenticated users.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;02&#x2F;sign-in-with-google-in-htmxfastapi.html&#x2F;image&#x2F;page2.drawio.png&quot; width=&quot;90%&quot;&gt;
&lt;h1 id=&quot;htmx-with-fastapi&quot;&gt;HTMX with FastAPI&lt;&#x2F;h1&gt;
&lt;p&gt;FastAPI can respond with an HTML page generated from a Jinja
template. The following code specifies that when the FastAPI server
receives a GET request to &lt;code&gt;&#x2F;spa&lt;&#x2F;code&gt;, it will respond with an
HTML page generated from the Jinja template &lt;code&gt;spa.j2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;router = APIRouter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;templates = Jinja2Templates(directory=&amp;#39;templates&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;spa&amp;quot;, response_class=HTMLResponse)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def spa(request: Request):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    context = {&amp;quot;request&amp;quot;: request}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return templates.TemplateResponse(&amp;quot;spa.j2&amp;quot;, context)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Shown below is what the template &lt;code&gt;spa.j2&lt;&#x2F;code&gt; looks like.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{% include &amp;#39;head.j2&amp;#39; %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {# Header #}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {# Content #}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the body section, there are two sub-sections: one is wrapped by
&lt;code&gt;&amp;lt;header&amp;gt;&amp;lt;&#x2F;header&amp;gt;&lt;&#x2F;code&gt;, and the other is wrapped by
&lt;code&gt;&amp;lt;div&amp;gt;&amp;lt;&#x2F;div&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The section wrapped by &lt;code&gt;&amp;lt;header&amp;gt;&amp;lt;&#x2F;header&amp;gt;&lt;&#x2F;code&gt;
loads the navigation bar in a responsive manner. Within this section, we
encounter unfamiliar attributes: hx-get, hx-target, hx-swap, and
hx-trigger. These attributes are interpreted by the HTMX JavaScript
library loaded in &lt;code&gt;head.j2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The meanings of the attributes are summarized as follows:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Attribute&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;hx-get&lt;&#x2F;td&gt;&lt;td&gt;issues a GET request to the given URL&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hx-target&lt;&#x2F;td&gt;&lt;td&gt;specifies an element for swapping&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hx-swap&lt;&#x2F;td&gt;&lt;td&gt;specifies how content is swapped&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hx-trigger&lt;&#x2F;td&gt;&lt;td&gt;specifies the event that triggers the request&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;In this case, the HTMX library will
issue a GET request to the &lt;code&gt;&#x2F;auth&#x2F;auth_navbar&lt;&#x2F;code&gt; endpoint upon
this section’s first load and when the page receives a response with
“HX-Trigger: LoginStatusChange” in the header for an HTMX AJAX request.
The HTMX library will then replace the content inside the
&lt;code&gt;&amp;lt;div&amp;gt;&lt;&#x2F;code&gt; section with &lt;code&gt;id=&quot;auth_navbar&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;div&amp;gt;&lt;&#x2F;code&gt; section just below the
&lt;code&gt;{# Content #}&lt;&#x2F;code&gt; is there to load the main contents of the
page dynamically. It also has the same set of HTMX attributes summarized
in the table above. In this case, the HTMX library will issue a GET
request to the &lt;code&gt;&#x2F;htmx&#x2F;content.top&lt;&#x2F;code&gt; endpoint only upon this
section’s first load. The HTMX library will then replace the content
inside the &lt;code&gt;&amp;lt;div&amp;gt;&lt;&#x2F;code&gt; section with
&lt;code&gt;id=&quot;content_section&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To have the HTMX attribute properly interpreted, we need to add a
&lt;code&gt;&amp;lt;script&amp;gt;&lt;&#x2F;code&gt; tag in the document head, like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The document head is included from the file &lt;code&gt;head.j2&lt;&#x2F;code&gt; in
the same directory as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{% include &amp;#39;head.j2&amp;#39; %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These examples illustrate the basic usage of HTMX and FastAPI with
Jinja templating.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sign-in&quot;&gt;Sign In&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;&#x2F;h2&gt;
&lt;p&gt;The figure below shows a schematic diagram depicting the flow of the
authentication process.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;02&#x2F;sign-in-with-google-in-htmxfastapi.html&#x2F;image&#x2F;htmx-fastapi01.drawio.png&quot; width=&quot;80%&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When a user clicks ‘Sign in with Google’, an authentication request
is sent to Google.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Upon successful authentication, the user’s credentials are returned
as a JSON Web Token (JWT) to the page.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;JavaScript code on the page forwards the JWT to
&lt;code&gt;&#x2F;auth&#x2F;login&lt;&#x2F;code&gt;, an authentication endpoint prepared using
FastAPI.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The JWT is then verified using a certificate fetched from
Google.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A user corresponding to the JWT is created in the SQLite database,
if one does not already exist.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A new session is also created and stored in the database.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;FastAPI sends a response with a header containing the entry
“Set-Cookie: session_id=xxxxxx.”&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thereafter, “Cookie: session_id=xxxxxx” is always set in subsequent
communications, until the cookie expires or until the user explicitly
hits the logout button on the web page.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frontend-auth&quot;&gt;Frontend Auth&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;sign-in-with-google-button&quot;&gt;Sign in with Google button&lt;&#x2F;h3&gt;
&lt;p&gt;To display a &lt;code&gt;Sign in with Google&lt;&#x2F;code&gt; button, we need to use
a JavaScript library provided by Google and place a code snippet
somewhere in the HTML.&lt;&#x2F;p&gt;
&lt;p&gt;To load the JavaScript library, add the following
&lt;code&gt;&amp;lt;script&amp;gt;&lt;&#x2F;code&gt; tag in the document head:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inside the navigation bar, we place a code snippet to show the “Sign
in with Google” button. This code snippet is available in two versions:
JavaScript and HTML. Either version can be used.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;javascript-version&quot;&gt;JavaScript Version&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.initialize({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        client_id: &amp;quot;{{ client_id }}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        callback: onSignIn,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ux_mode: &amp;quot;popup&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.renderButton(document.getElementById(&amp;quot;signInDiv&amp;quot;), {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        theme: &amp;quot;outline&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        size: &amp;quot;large&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        shape: &amp;quot;circle&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type: &amp;quot;icon&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {# google.accounts.id.prompt(); #}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;div id=&amp;quot;signInDiv&amp;quot;&amp;gt;div&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;google.accounts.id.initialize&lt;&#x2F;code&gt; function defines the
initialization and behavior of the sign-in process:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;client_id&lt;&#x2F;code&gt; specifies the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;gsi&#x2F;web&#x2F;guides&#x2F;get-google-api-clientid&quot;&gt;OAuth
2.0 Client ID&lt;&#x2F;a&gt;, which is necessary.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;callback&lt;&#x2F;code&gt; defines a JavaScript callback function for
a successful sign-in on Google’s side.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;ux_mode&lt;&#x2F;code&gt; sets Google’s sign-in page mode, preferred
to be ‘popup’ instead of ‘redirect’.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;google.accounts.id.renderButton&lt;&#x2F;code&gt; function defines the
presentation style of the Sign in with Google button:&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;google.accounts.id.prompt&lt;&#x2F;code&gt; method displays the One
Tap prompt (and is disabled in this particular case).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;html-version&quot;&gt;HTML Version&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; src=&amp;quot;https:&#x2F;&#x2F;accounts.google.com&#x2F;gsi&#x2F;client&amp;quot; async&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; id=&amp;quot;g_id_onload&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-client_id=&amp;quot;{{ client_id }}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-context=&amp;quot;signin&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-ux_mode=&amp;quot;popup&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-callback=onSignIn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-close_on_tap_outside=&amp;quot;true&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-itp_support=&amp;quot;true&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-auto_prompt=&amp;quot;false&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; class=&amp;quot;g_id_signin&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-type=&amp;quot;icon&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-shape=&amp;quot;square&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-theme=&amp;quot;outline&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     data-size=&amp;quot;large&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;div id=&quot;g_id_onload&quot;&amp;gt;&lt;&#x2F;code&gt; element initializes and
configures the sign-in process:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;data-client_id=&quot;{{ client_id }}&quot;&lt;&#x2F;code&gt; specifies the
necessary &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;identity&#x2F;gsi&#x2F;web&#x2F;guides&#x2F;get-google-api-clientid&quot;&gt;OAuth
2.0 Client ID&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;data-ux_mode=&quot;popup&quot;&lt;&#x2F;code&gt; sets the mode of Google’s sign-in
page to ‘popup’ instead of the more intrusive ‘redirect’.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;data-callback=onSignIn&lt;&#x2F;code&gt; specifies a JavaScript callback
function for a successful sign-in on Google’s side.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Setting &lt;code&gt;data-auto_prompt=&quot;false&quot;&lt;&#x2F;code&gt; determines whether to
display One Tap or not.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;div id=&quot;g_id_sigin&quot;&amp;gt;&lt;&#x2F;code&gt; division defines the
presentation style of the Sign in with Google button.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-callback-function&quot;&gt;The Callback Function&lt;&#x2F;h3&gt;
&lt;p&gt;Below is an implementation of the callback function to forward the
JWT to the backend:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function onSignIn(response) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        htmx.ajax(&amp;#39;POST&amp;#39;, &amp;#39;{{ login_url }}&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            { values: { &amp;#39;credential&amp;#39;: response.credential }, swap: &amp;#39;none&amp;#39; })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;onSignIn&lt;&#x2F;code&gt; function sends the JWT received from
Google’s sign-in page to &lt;code&gt;{{ login_url }}&lt;&#x2F;code&gt;, a backend
endpoint designed to handle the received JWT.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;backend-auth&quot;&gt;Backend Auth&lt;&#x2F;h2&gt;
&lt;p&gt;The backend endpoint receives the JWT, verifies it using Google’s
public certificate, and then creates a session to maintain a logged-in
status in subsequent communications.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the code snippet of the backend endpoint, which performs the
following operations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;VerifyToken&lt;&#x2F;code&gt;: Verifies the JWT.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GetOrCreateUser&lt;&#x2F;code&gt;: Creates the user in the database if
they don’t already exist.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;create_session&lt;&#x2F;code&gt;: Creates a session and stores it in a
session database.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;response.set_cookie&lt;&#x2F;code&gt;: Sets the session_id in the
cookie.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Returns the response to the frontend.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.post(&amp;quot;&#x2F;login&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def login(request: Request, ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body = await request.body()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    jwt = dict(urllib.parse.parse_qsl(body.decode(&amp;#39;utf-8&amp;#39;))).get(&amp;#39;credential&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    idinfo = await VerifyToken(jwt)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not idinfo:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = await GetOrCreateUser(idinfo, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to GetOrCreateUser&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: Failed to GetOrCreateUser for the JWT&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session_id = create_session(user, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session_id:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to create session for&amp;quot;, user.name)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: Failed to create session for&amp;quot;+user.name)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    max_age = 600&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expires = datetime.now(timezone.utc) + timedelta(seconds=max_age)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response = JSONResponse({&amp;quot;Authenticated_as&amp;quot;: user.name})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response.set_cookie(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        key=&amp;quot;session_id&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        value=session_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        httponly=True,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        samesite=&amp;quot;lax&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        max_age=max_age,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expires=expires,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response.headers[&amp;quot;HX-Trigger&amp;quot;] = &amp;quot;LoginStatusChange&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Please note that there is a line setting “HX-Trigger:
LoginStatusChange” in the response header. This triggers an hx-get to
The VerifyToken function below verifies the JWT from the frontend
using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;google-auth.readthedocs.io&#x2F;en&#x2F;stable&#x2F;reference&#x2F;google.oauth2.id_token.html&quot;&gt;Google
OAuth2 Python library&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from google.oauth2 import id_token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from google.auth.transport import requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def VerifyToken(jwt: str):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    try:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        idinfo = id_token.verify_oauth2_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jwt,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            requests.Request(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            settings.google_oauth2_client_id)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    except ValueError:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token with GOOGLE_OAUTH2_CLIENT_ID=&amp;quot; + settings.google_oauth2_client_id +&amp;quot;.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;idinfo: &amp;quot;, idinfo)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return idinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;sign-out&quot;&gt;Sign Out&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;overview-1&quot;&gt;Overview&lt;&#x2F;h2&gt;
&lt;p&gt;The figure below shows a schematic diagram depicting the flow of the
sign out process.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;02&#x2F;sign-in-with-google-in-htmxfastapi.html&#x2F;image&#x2F;htmx-fastapi02.drawio.png&quot; width=&quot;80%&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When a user clicks the ‘Sign-out’ button, an hx-get request is sent
to &#x2F;auth&#x2F;logout, an endpoint prepared using FastAPI.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The session associated with the session_id is deleted in the
database.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;FastAPI sends a response with a header containing the entry
&lt;code&gt;Set-Cookie: session_id=&quot;&quot;, max_age=0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thereafter, the browser unsets the &lt;code&gt;session_id&lt;&#x2F;code&gt; in the
Cookie header and will no longer send the &lt;code&gt;session_id&lt;&#x2F;code&gt; cookie
in subsequent requests.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frontend&quot;&gt;Frontend&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a snippet of the Jinja template, which shows a logout button
for authenticated users in the navigation bar.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             class=&amp;quot;navbar-nav me-auto mb-2 mb-lg-0&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 hx-get=&amp;quot;{{logout_url}}&amp;quot; hx-trigger=&amp;quot;click&amp;quot; hx-target=&amp;quot;#content_section&amp;quot; hx-swap=&amp;quot;innerHTML&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                     class=&amp;quot;rounded-circle&amp;quot; src=&amp;quot;{{icon_url}}&amp;quot; alt=&amp;quot;logout&amp;quot; name=&amp;quot;logout&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        style=&amp;quot;width:2rem;height:2rem;border-radius:2rem&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;{{ logout_url }}&lt;&#x2F;code&gt; and &lt;code&gt;{{icon_url}}&lt;&#x2F;code&gt; will
returned to the client browsers.&lt;&#x2F;p&gt;
&lt;p&gt;Upon a click, the logout button fires an hx-get request to
&lt;code&gt;{{ logout_url }}&lt;&#x2F;code&gt;, which translates to
&lt;code&gt;&#x2F;auth&#x2F;logout&lt;&#x2F;code&gt;, an endpoint of the backend server. The
attributes &lt;code&gt;hx-target=&quot;#content_section&quot;&lt;&#x2F;code&gt; and
&lt;code&gt;hx-swap=&quot;innerHTML&quot;&lt;&#x2F;code&gt; will cause the HTMX libray to replace
the content in inside the
&lt;code&gt;&amp;lt;div id=&quot;content_section&quot;&amp;gt;&amp;lt;&#x2F;div&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;backend&quot;&gt;Backend&lt;&#x2F;h2&gt;
&lt;p&gt;The backend endpoint receives an AJAX get request, deletes the
session associated with the session_id from the database, and instructs
the browser to unset the ‘Cookie: session_id’.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the code snippet of the backend endpoint, which performs the
following operations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;delete_session&lt;&#x2F;code&gt;: delete the session from the session
database.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;response.delete_cookie&lt;&#x2F;code&gt;: Causes the browser to delete
the &lt;code&gt;session_id&lt;&#x2F;code&gt; cookie from the Cookie header by setting
&lt;code&gt;Set-Cookie: session_id=&quot;&quot;, max-age=0&lt;&#x2F;code&gt; in the response
header(see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fastapi.tiangolo.com&#x2F;reference&#x2F;response&#x2F;#fastapi.Response.delete_cookie&quot;&gt;explanation&lt;&#x2F;a&gt;
and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;encode&#x2F;starlette&#x2F;blob&#x2F;master&#x2F;starlette&#x2F;responses.py#L130&quot;&gt;source
code&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;logout&amp;quot;, response_class=HTMLResponse)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def logout(request: Request, response: Response, hx_request: Optional[str] = Header(None), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not hx_request:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_400_BAD_REQUEST,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;Only HX request is allowed to this end point.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    req_session_id = request.cookies.get(&amp;quot;session_id&amp;quot;) # get session_id from cookie of request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if req_session_id:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        delete_session(req_session_id, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        response.delete_cookie(&amp;quot;session_id&amp;quot;) # delete key=&amp;quot;session_id&amp;quot; from cookie of response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    context = {&amp;quot;request&amp;quot;: request, &amp;quot;message&amp;quot;: &amp;quot;User logged out&amp;quot;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response = templates.TemplateResponse(&amp;quot;content.error.j2&amp;quot;, context)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response.headers[&amp;quot;HX-Trigger&amp;quot;] = &amp;quot;LoginStatusChange&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Please also note that there is a line setting “HX-Trigger:
LoginStatusChange” in the response header as same as the case for
&#x2F;auth&#x2F;login endpoint. This triggers an hx-get to&lt;&#x2F;p&gt;
&lt;h1 id=&quot;switch-navbar&quot;&gt;Switch Navbar&lt;&#x2F;h1&gt;
&lt;p&gt;The following code snippet returns the partial HTML content to
display the navigation bar. Depending on the existence of the valid
session_id in the Cookie header, the code returns the different HTMLs.
When there is a valid session_id in the Cookie header, it returns the
HTML generated from a Jinja template &lt;code&gt;auth_navbar.logout.j2&lt;&#x2F;code&gt;
for authenticated users with the user’s Google account icon and logout
button. When there isn’t a valid session_id in the Cookie header, it
returns the HTML generated from a Jinja template
&lt;code&gt;auth_navbar.login.j2&lt;&#x2F;code&gt; for anonymous users with a “Sign in
with Google” button.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;auth_navbar&amp;quot;, response_class=HTMLResponse)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def auth_navbar(request: Request, hx_request: Optional[str] = Header(None), ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not hx_request:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_400_BAD_REQUEST,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;Only HX request is allowed to this end point.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # For authenticated users, return the menu.logout component.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    try:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        session_id = request.cookies.get(&amp;quot;session_id&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user = await get_current_user(session_id=session_id, cs=cs, ds=ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        logout_url = settings.origin_server + &amp;quot;&#x2F;auth&#x2F;logout&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        icon_url = settings.origin_server + &amp;quot;&#x2F;img&#x2F;logout.png&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        context = {&amp;quot;request&amp;quot;: request, &amp;quot;session_id&amp;quot;: session_id, &amp;quot;logout_url&amp;quot;:logout_url, &amp;quot;icon_url&amp;quot;: icon_url,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                   &amp;quot;name&amp;quot;: user.name, &amp;quot;picture&amp;quot;: user.picture, &amp;quot;email&amp;quot;: user.email}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return templates.TemplateResponse(&amp;quot;auth_navbar.logout.j2&amp;quot;, context)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    except:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;User not logged-in.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # For unauthenticated users, return the menu.login component.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    client_id = settings.google_oauth2_client_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    login_url = settings.origin_server + &amp;quot;&#x2F;auth&#x2F;login&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    icon_url = settings.origin_server + &amp;quot;&#x2F;img&#x2F;icon.png&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    context = {&amp;quot;request&amp;quot;: request, &amp;quot;client_id&amp;quot;: client_id, &amp;quot;login_url&amp;quot;: login_url, &amp;quot;icon_url&amp;quot;: icon_url}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return templates.TemplateResponse(&amp;quot;auth_navbar.login.j2&amp;quot;, context)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;settings.origin_server&lt;&#x2F;code&gt; and
&lt;code&gt;settings.google_oauth2_client_id&lt;&#x2F;code&gt; are defined else where in
the code tree to provied necessary information from a &lt;code&gt;.env&lt;&#x2F;code&gt;
file.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;protecting-routes&quot;&gt;Protecting Routes&lt;&#x2F;h1&gt;
&lt;p&gt;Access to the secret pages is controlled through the
&lt;code&gt;auth.is_authenticated&lt;&#x2F;code&gt; dependency, as shown in the following
code snippet. If the &lt;code&gt;auth.is_authenticated&lt;&#x2F;code&gt; does not raise
an exception, it allows access to the routes defined in
&lt;code&gt;htmx&#x2F;htmx_secret.py&lt;&#x2F;code&gt;; otherwise, it disallows it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from htmx import htmx_secret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app = FastAPI()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app.include_router(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    htmx_secret.router,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prefix=&amp;quot;&#x2F;htmx&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags=[&amp;quot;htmx&amp;quot;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dependencies=[Depends(auth.is_authenticated)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;auth.is_authenticated&lt;&#x2F;code&gt; is defined as the
following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the function &lt;code&gt;get_current_user&lt;&#x2F;code&gt;, the user’s email is
retrieved from the session database, and then the other information is
retrieved from the user database.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The function &lt;code&gt;is_authenticated&lt;&#x2F;code&gt; raises an HTTPException
when there is no user information returned by the
&lt;code&gt;get_current_user&lt;&#x2F;code&gt; or the &lt;code&gt;user.disabled&lt;&#x2F;code&gt; is
true.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_current_user(session_id: str, ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session_id:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session = get_session_by_session_id(session_id, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_dict = get_user_by_email(session[&amp;quot;email&amp;quot;], ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user=UserBase(**user_dict)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;is_authenticated&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def is_authenticated(session_id: Annotated[str | None, Cookie()] = None, ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = await get_current_user(session_id=session_id, cs=cs, ds=ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_401_UNAUTHORIZED,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;NotAuthenticated&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    elif user.disabled:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_403_FORBIDDEN,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;Disabled user&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Authenticated.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return JSONResponse({&amp;quot;message&amp;quot;: &amp;quot;Authenticated&amp;quot;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;In this post, I’ve shared what I learned about integrating the Sign
in with Google feature with an HTMX+FastAPI web application. The “Sign
in with Google” button has been successfully integrated into a sample
HTMX+FastAPI web application. We included either an HTML or JavaScript
version of a code snippet from Google’s code generator in the HTML to
display the button. The FastAPI backend has been configured to create a
session from the JWT and set “Set-Cookie: session_id” in the header,
allowing subsequent communications to maintain the login status through
a session cookie. Thanks to HTMX functionality, the application page can
dynamically update the navigation bar upon a change in login status,
clearly indicating whether the user is logged in.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;seeking-oppotunities&quot;&gt;Seeking Oppotunities&lt;&#x2F;h1&gt;
&lt;p&gt;I’m based in Japan and am seeking remote work opportunities overseas.
I’m also open to on-site positions in North America, Australia, the EU,
etc., if visa support is available. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;ktaka-phd&#x2F;&quot;&gt;LinkedIn&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Google OAuth2 in Svelte + FastAPI: Create a Session Cookie from JWT</title>
        <published>2024-01-09T00:00:00+00:00</published>
        <updated>2024-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2024/01/svelte-fastapi-session-cookie-jwt-01.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2024/01/svelte-fastapi-session-cookie-jwt-01.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2024/01/svelte-fastapi-session-cookie-jwt-01.html/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I have implemented Google Sign-In functionality in a sample website
built using Svelte and FastAPI. There are various methods to
authenticate users in the backend API server after a successful Google
Sign In. One common approach is to send the JWT received from Google in
the request header as &lt;code&gt;Authorization: &quot;Bearer: JWT&quot;,&lt;&#x2F;code&gt; and if
the JWT is valid, authorization to access resources is granted. Another
typical method involves issuing a JWT on the backend and using it for
user authentication in the &lt;code&gt;Authorization&lt;&#x2F;code&gt; header. However,
using JWT directly for session management poses a challenge in immediate
invalidation if the JWT is leaked. Reference: &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;cryto.net&#x2F;~joepie91&#x2F;blog&#x2F;2016&#x2F;06&#x2F;13&#x2F;stop-using-jwt-for-sessions&#x2F;&quot;&gt;Stop
using JWT for sessions&lt;&#x2F;a&gt; . Therefore, I implemented a method in which,
following the receipt of the JWT from Google, FastAPI assigns a new
session_id. This session_id is set in a cookie to maintain the
session.&lt;&#x2F;p&gt;
&lt;p&gt;The session information is managed in FastAPI’s session database,
allowing administrators to invalidate sessions anytime. Additionally, by
adding Secure and HttpOnly attributes to the cookies, interception
during transmission and access from JavaScript are prevented, enabling
the development of a more secure website.&lt;&#x2F;p&gt;
&lt;p&gt;Note: I am self-taught in both Svelte and FastAPI, so I would
appreciate any advice on improving anything.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-i-implement&quot;&gt;What I Implement&lt;&#x2F;h2&gt;
&lt;p&gt;With authentication implemented, unauthenticated access will redirect
to the login page, where you can log in with a Google account.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;01&#x2F;svelte-fastapi-session-cookie-jwt-01.html&#x2F;image&#x2F;AuthLogin3-2.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;The Customer page can only be displayed after successful
authentication.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;01&#x2F;svelte-fastapi-session-cookie-jwt-01.html&#x2F;image&#x2F;AuthCustomer.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;In FastAPI, the Swagger UI automatically generates a documentation
page.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2024&#x2F;01&#x2F;svelte-fastapi-session-cookie-jwt-01.html&#x2F;image&#x2F;fastapi01.png&quot; width=&quot;80%&quot;&gt;
&lt;h2 id=&quot;frontend-implementation&quot;&gt;Frontend implementation&lt;&#x2F;h2&gt;
&lt;p&gt;with Svelte&lt;&#x2F;p&gt;
&lt;p&gt;I implemented the frontend JavaScript application using Svelte. It
includes authentication functionality using Google OAuth2 and retrieves
customer data from the backend to display in a table.&lt;&#x2F;p&gt;
&lt;p&gt;Upon successful Google Sign-In, the obtained JWT is sent to the
backend API server. The backend verifies the JWT, creates a user
account, sets the session_id in a cookie, and returns a response.
Thereafter, the session_id is always sent in the cookie to maintain a
session.&lt;&#x2F;p&gt;
&lt;p&gt;The code for this implementation is available in the following
repository:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;google-oauth2-example&#x2F;tree&#x2F;v2.1.1&#x2F;google-oauth&#x2F;frontend-svelte&quot;&gt;frontend-svelte
code&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I will explain the key points of implementing the login functionality
below.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;routing&quot;&gt;Routing&lt;&#x2F;h3&gt;
&lt;p&gt;We use &lt;code&gt;svelete-routing&lt;&#x2F;code&gt; to set up routing as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&#x2F;customer&lt;&#x2F;strong&gt; : Displays the Customer component.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&#x2F;login&lt;&#x2F;strong&gt; : Displays the LoginPage component.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sample code for &lt;code&gt;App.svelte&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { Router, Link, Route } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import Top from &amp;quot;.&#x2F;components&#x2F;Top.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import Customer from &amp;quot;.&#x2F;components&#x2F;Customer.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import NoMatch from &amp;quot;.&#x2F;components&#x2F;NoMatch.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import LoginPage from &amp;quot;.&#x2F;components&#x2F;LoginPage.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  export let url = &amp;quot;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Top&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Customer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;login-page&quot;&gt;Login Page&lt;&#x2F;h3&gt;
&lt;p&gt;We display Google’s Sign-In button and also use the OneTap interface.
After signing in with Google, the callback function
&lt;code&gt;backendAuth&lt;&#x2F;code&gt; is called. &lt;code&gt;backendAuth&lt;&#x2F;code&gt; sends the
response obtained from Google Sign-In to
&lt;code&gt;http:&#x2F;&#x2F;localhost&#x2F;api&#x2F;login&lt;&#x2F;code&gt;. The response includes the JWT
token. If the backend login is successful, it redirects to the previous
page. If it fails, the error is handled and “navigated” back to the
login page.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;LoginPage.svelte&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { useLocation, navigate } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { jwtDecode } from &amp;quot;jwt-decode&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let location = useLocation();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let origin = $location.state?.from;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const backendAuth = (response) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    const data = JSON.stringify(response, null, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    console.log(&amp;quot;JWT fed to backendAuth:\n&amp;quot;, data);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .post(`&#x2F;api&#x2F;login&#x2F;`, data)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;Navigate back to: &amp;quot;, origin);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        navigate(origin, { replace: true });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;backendAuth failed. Redirecting to &#x2F;login... &amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const onLogin = backendAuth;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(() =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.initialize({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &#x2F;* global google *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      client_id: import.meta.env.VITE_APP_GOOGLE_OAUTH2_CLIENT_ID,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      callback: (r) =&amp;gt; onLogin(r),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ux_mode: &amp;quot;popup&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &#x2F;&#x2F;        ux_mode: &amp;quot;redirect&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.renderButton(document.getElementById(&amp;quot;signInDiv&amp;quot;), {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      theme: &amp;quot;filled_blue&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      size: &amp;quot;large&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      shape: &amp;quot;circle&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.prompt();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Login page&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;setup-of-axios-instance&quot;&gt;Setup of Axios Instance&lt;&#x2F;h3&gt;
&lt;p&gt;By setting &lt;code&gt;withCredentials: true&lt;&#x2F;code&gt;, axios will send
cookies. Axios’s interceptors are used for error handling. If
&lt;code&gt;401 Unauthorized&lt;&#x2F;code&gt; or &lt;code&gt;403 Forbidden&lt;&#x2F;code&gt; are returned
from the backend, it navigates to &lt;code&gt;&#x2F;login&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;apiAxios.js&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import axios from &amp;quot;axios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import { navigate } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export const apiAxios = axios.create({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  baseURL: `${import.meta.env.VITE_APP_API_SERVER}`,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  withCredentials: true,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;apiAxios.interceptors.response.use(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (response) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return response;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (error) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if (error.response.status === 401 || error.response.status === 403) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      console.log(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;apiAxios failed. Redirecting to &#x2F;login... from&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        location.pathname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      navigate(&amp;quot;&#x2F;login&amp;quot;, { state: { from: location.pathname }, replace: true });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return Promise.reject(error);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;logoutbutton-component&quot;&gt;LogoutButton Component&lt;&#x2F;h3&gt;
&lt;p&gt;This component displays a Logout button. On mount, it accesses the
backend server to get information about the logged-in user. If there is
no session_id in the cookie, meaning the user is not logged in, the
attempt to get user information fails, and the user is redirected to the
&lt;code&gt;&#x2F;login&lt;&#x2F;code&gt; page due to the error handling in
&lt;code&gt;apiAxios.interceptor&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios.js&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let user;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(() =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    console.log(&amp;quot;Logout Component Mounted&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    getUser();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const handleLogout = () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = null;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;logout&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;backendLogout&amp;quot;, res);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        getUser();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(&amp;quot;Logout failed: &amp;quot;, error));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const getUser = () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;user&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user = res.data;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;getUser: user:&amp;quot;, user);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(&amp;quot;getUser failed: &amp;quot;, error.response));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const onLogout = handleLogout;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Authenticated as {user?.username} &amp;amp;nbsp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Sign Out&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;customer-component&quot;&gt;Customer Component&lt;&#x2F;h3&gt;
&lt;p&gt;This component retrieves data from the backend server and displays it
in a table. Since the &lt;code&gt;LogoutButton&lt;&#x2F;code&gt; component is placed on
the page, if the user is not logged in, it redirects to the
&lt;code&gt;&#x2F;login&lt;&#x2F;code&gt; page.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import LogoutButton from &amp;quot;.&#x2F;LogoutButton.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let customers = [];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let Loading = true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(async () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    await new Promise((r) =&amp;gt; setTimeout(r, 1000));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;customer&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; (customers = res.data.results))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(error))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .finally(() =&amp;gt; Loading = false);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is Customer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{#if Loading}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Loading ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{:else}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {#each customers as cs}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.id}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.name}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.email}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&#x2F;each}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&#x2F;if}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;backend-implementation-with&quot;&gt;Backend implementation with&lt;&#x2F;h2&gt;
&lt;p&gt;FastAPI&lt;&#x2F;p&gt;
&lt;p&gt;I implemented the backend API server using FastAPI. It verifies the
JWT received from the frontend Javascript apps, creates a user account,
issues a session_id, and registers it in the session database. The
created session_id is set in a cookie and returned in the response. The
backend API server creates a new user if a user corresponding to the JWT
does not exist in the database.&lt;&#x2F;p&gt;
&lt;p&gt;When a request to an endpoint that requires authentication is
received, FastAPI checks the session_id set in the cookie against the
session database and returns the requested data if valid session
information exists.&lt;&#x2F;p&gt;
&lt;p&gt;The code for this implementation is available in the following
repository:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;google-oauth2-example&#x2F;tree&#x2F;v2.1.1&#x2F;google-oauth&#x2F;backend-fastapi&quot;&gt;backend-fastapi
code&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I will explain the key points of implementing the login functionality
below.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;api-login-endpoint&quot;&gt;&#x2F;api&#x2F;login Endpoint&lt;&#x2F;h3&gt;
&lt;p&gt;The frontend app sends the JWT, and then the backend FastAPI app
verifies it using Google’s public certificates. If verification is
successful, the backend FastAPI app registers the user using the email
address in the JWT as the username in the user database. The information
of the newly created user and the session_id are registered in the
session database, and the session_id is set in a cookie in the
response.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;auth&#x2F;auth.py&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def VerifyToken(jwt: str):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    try:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        idinfo = id_token.verify_oauth2_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jwt,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            requests.Request(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            settings.google_oauth2_client_id)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    except ValueError:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token with GOOGLE_OAUTH2_CLIENT_ID=&amp;quot; + settings.google_oauth2_client_id +&amp;quot;.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;idinfo: &amp;quot;, idinfo)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return idinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.post(&amp;quot;&#x2F;login&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def login(request: Request, response: Response, ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body = await request.body()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    jwt = json.loads(body)[&amp;quot;credential&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if jwt == None:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: No JWT found&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;JWT token: &amp;quot; + jwt)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    idinfo = await VerifyToken(jwt)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not idinfo:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = await GetOrCreateUser(idinfo, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user_dict = get_user_by_name(user.name, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if not user_dict:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            raise HTTPException(status_code=HTTP_500_INTERNAL_SERVER_ERROR, detail=&amp;quot;Error: User not exist in User table in DB.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user = UserBase(**user_dict)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        session_id = create_session(user, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        response.set_cookie(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            key=&amp;quot;session_id&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            value=session_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            httponly=True,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            max_age=1800,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            expires=1800,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return Response(&amp;quot;Error: Auth failed&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return {&amp;quot;Authenticated_as&amp;quot;: user.name}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;function-to-determine-active&quot;&gt;Function to Determine Active&lt;&#x2F;h3&gt;
&lt;p&gt;Users&lt;&#x2F;p&gt;
&lt;p&gt;In the &lt;code&gt;get_current_user&lt;&#x2F;code&gt; function, FastAPI extracts the
session_id from the cookie of the received request and considers the
user logged in if it matches an entry in the session database. The
&lt;code&gt;get_current_active_user&lt;&#x2F;code&gt; checks whether the user is
disabled, and the &lt;code&gt;get_admin_user&lt;&#x2F;code&gt; checks whether the user
has admin privileges.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;auth&#x2F;auth.py&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_current_user(ds: Session = Depends(get_db), cs: Session = Depends(get_cache), session_id: str = Depends(oauth2_scheme)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session_id:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session = get_session_by_session_id(session_id, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    username = session[&amp;quot;name&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_dict = get_user_by_name(username, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user=UserBase(**user_dict)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_401_UNAUTHORIZED,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;Invalid authentication credentials&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_current_active_user(current_user: User = Depends(get_current_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not current_user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail=&amp;quot;NotAuthenticated&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if current_user.disabled:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_403_FORBIDDEN, detail=&amp;quot;Inactive user&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return current_user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_admin_user(current_user: User = Depends(get_current_active_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;CurrentUser: &amp;quot;, current_user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not current_user.admin:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_403_FORBIDDEN, detail=&amp;quot;Admin Privilege Required&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return current_user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;protecting-various-endpoints&quot;&gt;Protecting Various Endpoints&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;&#x2F;api&#x2F;user&#x2F;&lt;&#x2F;code&gt; endpoint is accessible only to logged-in
users due to &lt;code&gt;Depends(get_current_active_user)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;auth&#x2F;auth.py&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;user&#x2F;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_user(user: UserBase = Depends(get_current_active_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return {&amp;quot;username&amp;quot;: user.name, &amp;quot;email&amp;quot;: user.email,}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Routes defined in &lt;code&gt;customer&#x2F;customer.py&lt;&#x2F;code&gt; are accessible
only to authenticated users, and those in &lt;code&gt;admin&#x2F;user.py&lt;&#x2F;code&gt; are
accessible only to Admin users.&lt;&#x2F;p&gt;
&lt;p&gt;Sample code for &lt;code&gt;main.py&lt;&#x2F;code&gt; is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import admin.debug, admin.user, auth.auth, auth.debug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import customer.customer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app = FastAPI()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app.include_router(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    customer.customer.router,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prefix=&amp;quot;&#x2F;api&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags=[&amp;quot;CustomerForAuthenticatedUser&amp;quot;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dependencies=[Depends(auth.auth.get_current_active_user)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app.include_router(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    admin.user.router,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prefix=&amp;quot;&#x2F;api&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags=[&amp;quot;AdminOnly&amp;quot;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dependencies=[Depends(auth.auth.get_admin_user)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I have implemented Google Sign-In functionality in a sample website
built using Svelte and FastAPI. After receiving the JWT from Google,
FastAPI issues a new session_id and maintains the session through
cookies. The session information is managed in FastAPI’s Session
database, allowing administrators to invalidate sessions anytime.
Additionally, adding Secure and HttpOnly attributes to the cookies can
prevent interception and JavaScript access, enabling a more secure
website development.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Svelte+FastAPIでSign in with Googleを試してみた</title>
        <published>2023-12-25T00:00:00+00:00</published>
        <updated>2023-12-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2023/12/sveltefastapisign-in-with-google.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2023/12/sveltefastapisign-in-with-google.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2023/12/sveltefastapisign-in-with-google.html/">&lt;h1 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h1&gt;
&lt;p&gt;SvelteとFastAPIを使用して構築したサンプルウェブサイトにGoogleのサインイン機能を実装しました。
Google Sign
Inに成功した後、バックエンドのAPIサーバーにログインするためには、様々な方法が考えられます。
Googleから受け取ったJWTを、Requestヘッダに&lt;code&gt;Authorization: &quot;Bearer: JWT&quot;&lt;&#x2F;code&gt;として送信し、正しいJWTであれば、認証されます。
また、バックエンドでJWTを発行し、&lt;code&gt;Authorization&lt;&#x2F;code&gt;ヘッダにセットして認証済みユーザーを識別する方法も一般的です。
しかし、JWTをそのままログインユーザーの識別に利用する場合、JWTの漏洩時に即時の無効化が難しい問題があります。
参考：&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;cryto.net&#x2F;~joepie91&#x2F;blog&#x2F;2016&#x2F;06&#x2F;13&#x2F;stop-using-jwt-for-sessions&#x2F;&quot;&gt;Stop
using JWT for sessions&lt;&#x2F;a&gt;。
そこで、GoogleからJWTを受け取った後、FastAPI側で新たにsession_idを発行し、Cookieを介してセッションを維持する方法で実装しました。&lt;&#x2F;p&gt;
&lt;p&gt;セッション情報はFastAPIのセッションデータベースで管理されており、管理者がいつでもセッションを無効にできます。
また、CookieにSecure属性とHttpOnly属性を付与することで、経路での盗聴防止やJavaScriptからのアクセス防止が可能になり、より安全なWebサイトの構築が可能です。&lt;&#x2F;p&gt;
&lt;p&gt;なお、SvelteもFastAPIも独学で学習中ですので、おかしな点があれば、アドバイスいただけると嬉しいです。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;shi-zhuang-surumono&quot;&gt;実装するもの&lt;&#x2F;h1&gt;
&lt;p&gt;認証が実装されると、未ログイン時のアクセスはログインページにリダイレクトされ、そこでGoogleアカウントでログインできます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;12&#x2F;sveltefastapisign-in-with-google.html&#x2F;image&#x2F;AuthLogin3-2.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;Customerページは、認証に成功した場合にのみ表示できます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;12&#x2F;sveltefastapisign-in-with-google.html&#x2F;image&#x2F;AuthCustomer.png&quot; width=&quot;80%&quot;&gt;
&lt;p&gt;FastAPIではSwagger UIによるドキュメントページが自動生成されます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;12&#x2F;sveltefastapisign-in-with-google.html&#x2F;image&#x2F;fastapi01.png&quot; width=&quot;80%&quot;&gt;
&lt;h1 id=&quot;sveltedenohurontoendonoshi-zhuang&quot;&gt;Svelteでのフロントエンドの実装&lt;&#x2F;h1&gt;
&lt;p&gt;Svelteを使用してフロントエンドを実装します。
バックエンドからcustomerデータを取得し、テーブル表示するページにGoogle
OAuth2を利用した認証機能を実装します。&lt;&#x2F;p&gt;
&lt;p&gt;Google Sign
Inに成功し、取得したJWTをバックエンドのAPIサーバーに送信します。
バックエンド側では、JWTをベリファイしユーザーアカウントを作成し、session_idをCookieにセットしてレスポンスを返信します。
これ以降、バックエンドへのリクエスト時には、常にCookieにsession_idをセットして送信します。&lt;&#x2F;p&gt;
&lt;p&gt;実装したコードは以下のリポジトリにあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;google-oauth2-example&#x2F;tree&#x2F;v2.1.1&#x2F;google-oauth&#x2F;frontend-svelte&quot;&gt;frontend-svelteのコード&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ログイン機能の実装ポイントを以下に説明します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ruteingu&quot;&gt;ルーティング&lt;&#x2F;h2&gt;
&lt;p&gt;svelete-routingを利用し、以下のようにルーティングを設定します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&#x2F;customer&lt;&#x2F;strong&gt;:
Customerコンポーネントを表示します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&#x2F;login&lt;&#x2F;strong&gt;: LoginPageコンポーネントを表示します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;App.svelte&lt;&#x2F;code&gt;のサンプルコードは次の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { Router, Link, Route } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import Top from &amp;quot;.&#x2F;components&#x2F;Top.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import Customer from &amp;quot;.&#x2F;components&#x2F;Customer.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import NoMatch from &amp;quot;.&#x2F;components&#x2F;NoMatch.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import LoginPage from &amp;quot;.&#x2F;components&#x2F;LoginPage.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  export let url = &amp;quot;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Top&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Customer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;roguinpezi&quot;&gt;ログインページ&lt;&#x2F;h2&gt;
&lt;p&gt;GoogleのSign Inボタンを表示し、OneTapインターフェースも利用します。
GoogleでSign
In後、コールバックファンクション&lt;code&gt;backendAuth&lt;&#x2F;code&gt;を呼び出します。
&lt;code&gt;backendAuth&lt;&#x2F;code&gt;では、Google Sign
Inで得られたレスポンスを&lt;code&gt;http:&#x2F;&#x2F;localhost&#x2F;api&#x2F;login&lt;&#x2F;code&gt;に送信します。
レスポンスにはJWTトークンが含まれます。
バックエンドでのログインが成功した場合、直前にいたページにリダイレクトします。
失敗した場合、エラー処理が行われ、再度ログインページにリダイレクトされます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;LoginPage.svelte&lt;&#x2F;code&gt;のサンプルコードは次の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { useLocation, navigate } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { jwtDecode } from &amp;quot;jwt-decode&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let location = useLocation();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let origin = $location.state?.from;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const backendAuth = (response) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    const data = JSON.stringify(response, null, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    console.log(&amp;quot;JWT fed to backendAuth:\n&amp;quot;, data);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .post(`&#x2F;api&#x2F;login&#x2F;`, data)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;Navigate back to: &amp;quot;, origin);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        navigate(origin, { replace: true });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;backendAuth failed. Redirecting to &#x2F;login... &amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const onLogin = backendAuth;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(() =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.initialize({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &#x2F;* global google *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      client_id: import.meta.env.VITE_APP_GOOGLE_OAUTH2_CLIENT_ID,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      callback: (r) =&amp;gt; onLogin(r),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ux_mode: &amp;quot;popup&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &#x2F;&#x2F;        ux_mode: &amp;quot;redirect&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.renderButton(document.getElementById(&amp;quot;signInDiv&amp;quot;), {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      theme: &amp;quot;filled_blue&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      size: &amp;quot;large&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      shape: &amp;quot;circle&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    google.accounts.id.prompt();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Login page&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;axiosinsutansunosetutoatupu&quot;&gt;axiosインスタンスのセットアップ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;withCredentials: true&lt;&#x2F;code&gt;をセットすることでaxiosはCookieを送信するようになります。
axiosのinterceptorsでエラー処理を行い、バックエンドから&lt;code&gt;401 Unauthorized&lt;&#x2F;code&gt;、&lt;code&gt;403 Forbidden&lt;&#x2F;code&gt;が返ってきた場合、&lt;code&gt;&#x2F;login&lt;&#x2F;code&gt;へリダイレクトします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;apiAxios.js&lt;&#x2F;code&gt;のサンプルコードは次の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import axios from &amp;quot;axios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import { navigate } from &amp;quot;svelte-routing&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export const apiAxios = axios.create({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  baseURL: `${import.meta.env.VITE_APP_API_SERVER}`,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  withCredentials: true,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;apiAxios.interceptors.response.use(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (response) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return response;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (error) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if (error.response.status === 401 || error.response.status === 403) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      console.log(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;apiAxios failed. Redirecting to &#x2F;login... from&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        location.pathname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      navigate(&amp;quot;&#x2F;login&amp;quot;, { state: { from: location.pathname }, replace: true });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return Promise.reject(error);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;logoutbuttonkonponento&quot;&gt;LogoutButtonコンポーネント&lt;&#x2F;h2&gt;
&lt;p&gt;Logoutボタンを表示するコンポーネントです。
onMount時に、バックエンドサーバにアクセスし、ログインしているユーザーの情報を取得します。
Cookieにsession_idが無い場合、すなわち未ログインの場合にはユーザー情報取得に失敗し、apiAxios.interceptorのエラー処理により、&lt;code&gt;&#x2F;login&lt;&#x2F;code&gt;ページにリダイレクトされます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios.js&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let user;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(() =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    console.log(&amp;quot;Logout Component Mounted&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    getUser();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const handleLogout = () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = null;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;logout&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;backendLogout&amp;quot;, res);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        getUser();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(&amp;quot;Logout failed: &amp;quot;, error));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const getUser = () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;user&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user = res.data;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console.log(&amp;quot;getUser: user:&amp;quot;, user);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(&amp;quot;getUser failed: &amp;quot;, error.response));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const onLogout = handleLogout;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Authenticated as {user?.username} &amp;amp;nbsp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Sign Out&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;customerkonponento&quot;&gt;Customerコンポーネント&lt;&#x2F;h2&gt;
&lt;p&gt;バックエンドサーバからデータを取得し、テーブル表示するコンポーネントです。&lt;code&gt;LogoutButton&lt;&#x2F;code&gt;
コンポーネントがページ内に配置されているので、未ログインの場合には、&lt;code&gt;&#x2F;login&lt;&#x2F;code&gt;
ページにリダイレクトされます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { onMount } from &amp;quot;svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import { apiAxios } from &amp;quot;..&#x2F;lib&#x2F;apiAxios&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  import LogoutButton from &amp;quot;.&#x2F;LogoutButton.svelte&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let customers = [];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let Loading = true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  onMount(async () =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    await new Promise((r) =&amp;gt; setTimeout(r, 1000));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apiAxios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .get(`&#x2F;api&#x2F;customer&#x2F;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .then((res) =&amp;gt; (customers = res.data.results))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .catch((error) =&amp;gt; console.log(error))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      .finally(() =&amp;gt; Loading = false);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is Customer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{#if Loading}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Loading ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{:else}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {#each customers as cs}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.id}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.name}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {cs.email}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&#x2F;each}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&#x2F;if}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;fastapidenobatukuendoshi-zhuang&quot;&gt;FastAPIでのバックエンド実装&lt;&#x2F;h1&gt;
&lt;p&gt;FastAPIを使用して、バックエンドのAPIサーバを実装します。
フロントエンドから受け取ったJWTを検証し、ユーザーアカウントを作成して、session_idを発行しセッションデータベースに登録します。
作成したsession_idをCookieにセットしてレスポンスを返信します。
受け取ったJWTに対応するユーザーがデータベースに存在しない場合、新たにユーザーを作成します。&lt;&#x2F;p&gt;
&lt;p&gt;認証で保護されたエンドポイントへのリクエストを受け取った場合、Cookieにセットされたsession_idとセッションデータベースを照合し、有効なセッション情報が存在している場合のみ、要求されたデータを返信します。&lt;&#x2F;p&gt;
&lt;p&gt;実装したコードは以下のリポジトリにあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;google-oauth2-example&#x2F;tree&#x2F;v2.1.1&#x2F;google-oauth&#x2F;backend-fastapi&quot;&gt;backend-fastapiのコード&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ログイン機能の実装ポイントについて以下に説明します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;api-loginendopointo&quot;&gt;&#x2F;api&#x2F;loginエンドポイント&lt;&#x2F;h2&gt;
&lt;p&gt;フロントエンドからJWTを受け取り、Googleの公開証明書を使用してJWTを検証します。
検証に成功すると、JWT内のemailアドレスを使用してユーザーデータベースにユーザーを登録します。
新しく作成したユーザーの情報とsession_idをセッションデータベースに登録し、Cookieにsession_idをセットしてレスポンスを返します。&lt;&#x2F;p&gt;
&lt;p&gt;auth&#x2F;auth.py&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def VerifyToken(jwt: str):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    try:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        idinfo = id_token.verify_oauth2_token(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jwt,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            requests.Request(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            settings.google_oauth2_client_id)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    except ValueError:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token with GOOGLE_OAUTH2_CLIENT_ID=&amp;quot; + settings.google_oauth2_client_id +&amp;quot;.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;idinfo: &amp;quot;, idinfo)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return idinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.post(&amp;quot;&#x2F;login&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def login(request: Request, response: Response, ds: Session = Depends(get_db), cs: Session = Depends(get_cache)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    body = await request.body()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    jwt = json.loads(body)[&amp;quot;credential&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if jwt == None:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: No JWT found&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;JWT token: &amp;quot; + jwt)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    idinfo = await VerifyToken(jwt)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not idinfo:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        print(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return  Response(&amp;quot;Error: Failed to validate JWT token&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user = await GetOrCreateUser(idinfo, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user_dict = get_user_by_name(user.name, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if not user_dict:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            raise HTTPException(status_code=HTTP_500_INTERNAL_SERVER_ERROR, detail=&amp;quot;Error: User not exist in User table in DB.&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user = UserBase(**user_dict)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        session_id = create_session(user, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        response.set_cookie(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            key=&amp;quot;session_id&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            value=session_id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            httponly=True,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            max_age=1800,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            expires=1800,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return Response(&amp;quot;Error: Auth failed&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return {&amp;quot;Authenticated_as&amp;quot;: user.name}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;akuteibuyuzawopan-bie-suruguan-shu&quot;&gt;アクティブユーザーを判別する関数&lt;&#x2F;h2&gt;
&lt;p&gt;FastAPIが受け取ったリクエストのCookieからsession_idを取り出し、セッションデータベース内のエントリと一致すればログイン済みとみなします。
&lt;code&gt;get_current_active_user&lt;&#x2F;code&gt;では、disabledのフラグが立っていないか判別し、&lt;code&gt;get_admin_user&lt;&#x2F;code&gt;では、adminのフラグが立っているかどうか判別します。&lt;&#x2F;p&gt;
&lt;p&gt;auth&#x2F;auth.py&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_current_user(ds: Session = Depends(get_db), cs: Session = Depends(get_cache), session_id: str = Depends(oauth2_scheme)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session_id:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session = get_session_by_session_id(session_id, cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not session:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    username = session[&amp;quot;name&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_dict = get_user_by_name(username, ds)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user=UserBase(**user_dict)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            status_code=status.HTTP_401_UNAUTHORIZED,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            detail=&amp;quot;Invalid authentication credentials&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_current_active_user(current_user: User = Depends(get_current_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not current_user:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail=&amp;quot;NotAuthenticated&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if current_user.disabled:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_403_FORBIDDEN, detail=&amp;quot;Inactive user&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return current_user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_admin_user(current_user: User = Depends(get_current_active_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    print(&amp;quot;CurrentUser: &amp;quot;, current_user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if not current_user.admin:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        raise HTTPException(status_code=HTTP_403_FORBIDDEN, detail=&amp;quot;Admin Privilege Required&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return current_user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;ge-zhong-endopointonobao-hu&quot;&gt;各種エンドポイントの保護&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Depends(get_current_active_user)&lt;&#x2F;code&gt;により、&lt;code&gt;&#x2F;api&#x2F;user&#x2F;&lt;&#x2F;code&gt;エンドポイントはログインユーザーのみがアクセスできます。&lt;&#x2F;p&gt;
&lt;p&gt;auth&#x2F;auth.py&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@router.get(&amp;quot;&#x2F;user&#x2F;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;async def get_user(user: UserBase = Depends(get_current_active_user)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return {&amp;quot;username&amp;quot;: user.name, &amp;quot;email&amp;quot;: user.email,}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;customer&#x2F;customer.py&lt;&#x2F;code&gt;で定義されたルートは認証済みユーザーのみ、&lt;code&gt;admin&#x2F;user.py&lt;&#x2F;code&gt;で定義されたルートはAdminユーザーのみがアクセスできます。&lt;&#x2F;p&gt;
&lt;p&gt;main.py&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import admin.debug, admin.user, auth.auth, auth.debug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import customer.customer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app = FastAPI()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app.include_router(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    customer.customer.router,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prefix=&amp;quot;&#x2F;api&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags=[&amp;quot;CustomerForAuthenticatedUser&amp;quot;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dependencies=[Depends(auth.auth.get_current_active_user)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app.include_router(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    admin.user.router,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prefix=&amp;quot;&#x2F;api&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags=[&amp;quot;AdminOnly&amp;quot;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dependencies=[Depends(auth.auth.get_admin_user)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h1&gt;
&lt;p&gt;SvelteとFastAPIを用いて構築したサンプルウェブサイトにGoogleのサインイン機能を実装しました。
GoogleからJWTを受け取った後、FastAPI側で新たにsession_idを発行し、Cookieを介してセッションを維持する方法で実装しました。
セッション情報はFastAPIのセッションデータベースで管理されており、いつでも管理者がセッションを無効にできます。
また、CookieにSecure属性とHttpOnly属性を付与することで、経路での盗聴防止やJavaScriptからのアクセス防止が可能になり、より安全なWebサイトの構築が可能です。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>UEFI&#x2F;BIOSのどちらでもGRUB起動可能なUSBメモリを作る</title>
        <published>2023-04-08T00:00:00+00:00</published>
        <updated>2023-04-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2023/04/uefibiosgrubusb.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2023/04/uefibiosgrubusb.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2023/04/uefibiosgrubusb.html/">&lt;h2 id=&quot;yao-zhi&quot;&gt;要旨&lt;&#x2F;h2&gt;
&lt;p&gt;UEFIモードとBIOSモードのどちらでもGRUBを起動可能なUSBメモリの作成を試みた。
どちらの場合でもGRUBの起動が可能であるはずのUSBメモリを作成した。
SupermicroワークステーションとIntel
NUCで実機検証したところ、Supermicroのワークステーションでは、どちらのモードでもブート可能であったが、Intel
NUCはそうではなかった。
ハードウェアによってはBIOSブート時にパーティションにbootable(active)フラグが必要であるものがあり、その場合は、UEFIブートと両立できないことがわかった。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;USBメモリからLinuxが起動できると便利である。サーバのメンテナンスや新規OSインストールなどの様々な場面で、ディスクレスなLinuxをUSBメモリから起動し役立てることができる。私の場合、自宅や会社のルータとして、USBから起動したDebian
Linuxを利用している。ファイルシステムをメモリ(tmpfs)上に展開しディスクレスで運用しているので、なにか設定をしくじった場合にも再起動すればもとの状態に戻すことができるし、ハードウェアが故障してしまった場合などは別のマシンにUSBメモリを差し替えれば簡単に復旧できるので大変重宝している。&lt;&#x2F;p&gt;
&lt;p&gt;Linuxを起動するにはGRUBというブートローダを利用することが多い。GRUBはLinuxカーネルのロードが可能なだけでなく、Windowsのチェインロードも可能である。
かつてのPCは、BIOSというファームウェアがドライブの先頭にあるGRUBをロードしていたが、最近のPCではUEFIがESPにあるGRUBをロードするように仕様に変わった。
BIOSとUEFIではブート仕様が異なるので、GRUBのインストールの方式も異なっていて、一方の方式でLinux及びGRUBインストールしたドライブをもう一方の方式のPCで利用することができない。通常は、HDDやSSD等の起動ドライブをPC間で移動することはあまりないのでそれぞれのPCにそれぞれ適した方式でインストールすれば問題ない。&lt;&#x2F;p&gt;
&lt;p&gt;しかしメンテナンス用のUSBメモリは、できれば、古いBIOS方式でも新しいUEFI方式でも、どちらでも使えるようにしておきたい。
そこで、今回、UEFIモードでもBIOSモードでも、GRUBを起動することができるUSBメモリの作成を試みた。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;yarifang&quot;&gt;やり方&lt;&#x2F;h2&gt;
&lt;p&gt;LinuxパソコンにUSBメモリを挿したとき、&#x2F;dev&#x2F;sdaとして認識されているとし、そこにパーティションテーブルを作成しGRUBのインストールを行う。
以下の手順は、ストレージのパーティションを操作するので、&#x2F;dev&#x2F;sdaが確かに操作しようとしているUSBメモリなのかをよく確認してから行う必要がある。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pateisiyonchu-qi-hua-tozuo-cheng&quot;&gt;パーティション初期化と作成&lt;&#x2F;h3&gt;
&lt;p&gt;Linuxのルートパーティション、ESPパーティション、BIOSブートパーティションを作成する。ESPパーティションは先頭から512Mbyte、Linuxルートパーティションは残り全部を割り当てる。最近のパーティションツールは、先頭の先頭に2047セクタ分の空きを残すようなので、そこにBIOSブートパーティションを作成する。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOP_DIR=.&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dev=&#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Clear partition table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -Z $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Create ESP partition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -n 2::+512M  $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -t 2:ef00 $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Create Linux partition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -n 1:: $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Create BIOS boot partition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -a 1 -n 3:34:2047 $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -t 3:ef02 $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Change the GPT name of each partition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -c 1:Linux -c 2:ESP -c 3:BIOS $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Show current status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgdisk -p $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;LinuxルートパーティションとESPパーティションをフォーマットし、ファイルシステムにマウント。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Format ESP and Linux partition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkfs.fat -F32 -n ESP ${dev}2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkfs.ext4 -F -L usbdebian ${dev}1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Create mount point and mount file systems&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir -p ${TOP_DIR}&#x2F;mnt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mount -L usbdebian ${TOP_DIR}&#x2F;mnt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir -p ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mount -L ESP ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;BIOS用GRUBのインストール。MBR（ディスクの先頭512Byte）とBIOSブートパーティションにgrubをインストール。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# BIOS setup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;grub-install --target=i386-pc --boot-directory=.&#x2F;mnt&#x2F;boot&#x2F; $dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;動作確認用のGRUBメニューの設定ファイルを作成。今回はLinuxカーネルは入れず、このメニューが表示できるところまでがゴールなので、仮のもので良い。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Create minimum grub.cfg for testing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cat  ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set default=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set timeout=5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menuentry &amp;quot;Debian Linux&amp;quot; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;linux &#x2F;boot&#x2F;vmlinuz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;UEFIモードでブートするには、UEFI設定にブートするバイナリとその優先順位を登録することが一般的であるが、USBメモリの場合リームーバブルメディアであるので適さない。
UEFIブートではUEFI設定で他に指定がない場合、EFI&#x2F;boot&#x2F;bootx64.efiにフォールバックするので、grubx64.efiをその名前で置いておけば良い。grubx64.efiは同じディレクトリのgrub.cfgを参照するので、そこに&#x2F;boot&#x2F;grub&#x2F;grub.cfgを更に参照するように書いておく。&lt;&#x2F;p&gt;
&lt;p&gt;UEFIモードの場合にはセキュアブートも可能である。その場合には、shimx64.efi
-&amp;gt; grubx64.efi -&amp;gt;
grub.cfgの順で読み込ませたいので、shimx64.efiをEFI&#x2F;boot&#x2F;bootx64.efiとして置き、同じディレクトリに、grubx64.efiとgrub.cfgを置けば良い。この時、shimx64.efiとgrubx64.efiは署名済みのものを用いる必要がある。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# UEFI boot setup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir -p ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&#x2F;EFI&#x2F;boot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cp &#x2F;usr&#x2F;lib&#x2F;grub&#x2F;x86_64-efi&#x2F;monolithic&#x2F;grubx64.efi ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&#x2F;EFI&#x2F;boot&#x2F;bootx64.efi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cat  ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&#x2F;EFI&#x2F;boot&#x2F;grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;search.fs_label usbdebian root&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set prefix=($root)&amp;#39;&#x2F;boot&#x2F;grub&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;configfile $prefix&#x2F;grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Unmount filesystem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;umount ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&#x2F; &amp;amp;&amp;amp; umount ${TOP_DIR}&#x2F;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作成したUSBメモリのパーティション構成&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# sgdisk -p &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Disk &#x2F;dev&#x2F;sda: 60088320 sectors, 28.7 GiB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Model: Ultra Fit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sector size (logical&#x2F;physical): 512&#x2F;512 bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Disk identifier (GUID): 21780B2C-8682-42A0-9564-D7E7D726A7EC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Partition table holds up to 128 entries&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Main partition table begins at sector 2 and ends at sector 33&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;First usable sector is 34, last usable sector is 60088286&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Partitions will be aligned on 2-sector boundaries&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Total free space is 0 sectors (0 bytes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number  Start (sector)    End (sector)  Size       Code  Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   1         1050624        60088286   28.2 GiB    8300  Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   2            2048         1050623   512.0 MiB   EF00  ESP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   3              34            2047   1007.0 KiB  EF02  BIOS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作成したUSBメモリのファイルシステム確認（unmout前に確認）&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# tree -L 3 ${TOP_DIR}&#x2F;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── boot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── efi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── EFI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── grub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── fonts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── grubenv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── i386-pc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       └── locale&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── lost+found&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 directories, 2 files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# tree ${TOP_DIR}&#x2F;mnt&#x2F;boot&#x2F;efi&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mnt&#x2F;boot&#x2F;efi&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── EFI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── boot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ├── bootx64.efi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        └── grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 directories, 2 files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以上でGRUBまで立ち上がるUSBは完成である。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nazekonogou-cheng-debios-uefiliang-dui-ying-ninarunoka&quot;&gt;なぜこの構成でBIOS&#x2F;UEFI両対応になるのか&lt;&#x2F;h3&gt;
&lt;p&gt;BIOSブートとUEFIブートでは、GRUBが読み込まれる場所が異なる。しかし、最終的に同じ &lt;code&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt;を参照するように構成することで、両対応が可能になる。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BIOS:  MBR → BIOS boot partition → &#x2F;boot&#x2F;grub&#x2F;grub.cfg → kernel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                          ↑&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UEFI:  ESP → bootx64.efi → ESP&#x2F;grub.cfg --┘&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;BIOSブートの場合:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;BIOSがディスク先頭のMBR（Master Boot Record）を読む&lt;&#x2F;li&gt;
&lt;li&gt;MBRのブートコードがBIOS boot partition内のGRUB core.imgへジャンプ&lt;&#x2F;li&gt;
&lt;li&gt;GRUBが&lt;code&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt;を読み込み&lt;&#x2F;li&gt;
&lt;li&gt;設定に従ってカーネルをロード&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;UEFIブートの場合:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;UEFIファームウェアがGPT上のESP（EFI System Partition）を探す&lt;&#x2F;li&gt;
&lt;li&gt;デフォルトパス&lt;code&gt;&#x2F;EFI&#x2F;boot&#x2F;bootx64.efi&lt;&#x2F;code&gt;を実行（リムーバブルメディアのフォールバック）&lt;&#x2F;li&gt;
&lt;li&gt;同じディレクトリの&lt;code&gt;grub.cfg&lt;&#x2F;code&gt;を読む:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;search.fs_label usbdebian root&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set prefix=($root)&amp;#39;&#x2F;boot&#x2F;grub&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;configfile $prefix&#x2F;grub.cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ラベル&lt;code&gt;usbdebian&lt;&#x2F;code&gt;のパーティションを見つけ、&lt;code&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt;を読み込み&lt;&#x2F;li&gt;
&lt;li&gt;設定に従ってカーネルをロード&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;ポイント:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ESPの&lt;code&gt;grub.cfg&lt;&#x2F;code&gt;は&lt;strong&gt;リダイレクト役&lt;&#x2F;strong&gt;。本体の設定ファイルへ誘導するだけ&lt;&#x2F;li&gt;
&lt;li&gt;メインの&lt;code&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt;を1箇所で管理できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;search.fs_label&lt;&#x2F;code&gt;でラベル指定することで、デバイス名（&#x2F;dev&#x2F;sdaなど）に依存しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-ji-nibutodekirunoka&quot;&gt;実際にブートできるのか&lt;&#x2F;h2&gt;
&lt;p&gt;作成したUSBメモリで実際にブート可能であるかを、SupermicroのワークステーションとIntel
NUCで試してみた。
Supermicroのワークステーションでは、UEFIブートであってもBIOSブートであっても、GRUBメーニュー画面が表示できた。
Intel
NUCの場合は、UEFIモードでは無事にGRUBのメニューが表示されたが、BIOSモードでのブートができなかった。&lt;&#x2F;p&gt;
&lt;p&gt;Intel
NUCの場合には、BIOSモードでブートする場合、次の手順でPMBRのパーティションテーブルでbootable(active)フラグを立ててやる必要があった。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# sfdisk -A  &#x2F;dev&#x2F;sda 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Activation is unsupported for GPT -- entering nested PMBR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The bootable flag on partition 1 is enabled now.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The partition table has been altered.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Syncing disks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# sgdisk -O  &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Disk size is 60088320 sectors (28.7 GiB)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MBR disk identifier: 0x00000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MBR partitions:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number  Boot  Start Sector   End Sector   Status      Code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   1      *              1     60088319   primary     0xEE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;PMBRのパーティションテーブルでbootable(active)フラグを立てた場合、今度はUEFIブートができなくなってしまった。どうやらUEFIブートのUEFIブートの規格でPMBR上でそのフラグを立てることを明確に禁止しているらしい。
再度、UEFIブートするには、以下のように、bootable(active)フラグを戻す必要がある。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@dyna:~# sfdisk -A &#x2F;dev&#x2F;sda -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Activation is unsupported for GPT -- entering nested PMBR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The bootable flag on partition 1 is disabled now.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The partition table has been altered.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Syncing disks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;古いハードウェアには、bootable(active)フラグが立っているパーティションが無いとBIOSブートできないものがあり、どうやらIntel
NUCはそのようなハードウェアのひとつであるようだ。&lt;&#x2F;p&gt;
&lt;p&gt;参考&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;[Partitioning&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;wiki.archlinux.org](https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;title&#x2F;Partitioning#Tricking_old_BIOS_into_booting_from_GPT) (このやり方はうまく行かなかった)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unix.stackexchange.com&#x2F;a&#x2F;325899&quot;&gt;BIOS &#x2F; GPT: do we
need a ‘boot’ flag?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回、UEFIモードでもBIOSモードでも、GRUBを起動することができるUSBメモリの作成を試みた。
作成したUSBメモリでGRUB画面の表示までたどり着けるか試してみた。
Supermicroのワークステーションでは、BIOSブート、UEFIブートのどちらでもGRUB画面にたどり着くことができたが、Intel
NUCではPMBR上でbootable(active)フラグの切り替えが必要であった、&lt;&#x2F;p&gt;
&lt;p&gt;UEFIブートの規格でPMBR上でそのフラグを立てることを明確に禁止しているらしい。
しかし古いハードウェアにはBIOSブート時に、bootable(active)フラグが立っているパーティションが必要であるものがあることが確認された。
その場合には、ブートモードに応じて作成したUSBメモリのbootable(active)フラグを切り替えることがどうしても必要になってしまうことがわかった。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>KVM再入門：Qemuコマンドラインで仮想マシンを起動し、Windows11ゲストをセットアップする。</title>
        <published>2023-03-22T00:00:00+00:00</published>
        <updated>2023-03-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows11.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows11.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows11.html/">&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows.html&quot;&gt;前回&lt;&#x2F;a&gt;に引き続き、KVM仮想マシン上にWindows11をインストールするやり方をまとめておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Windows10の時とは以下のような違いがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows11の場合、TPMとUEFI Secure Bootが必須である。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;KVMでTPMを使うには、ホストの&#x2F;dev&#x2F;tpm0をパススルーで使う方法と、ソフトウェアのTPMデバイスエミュレーター(swtpm)を使う方法がある。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;KVMでUEFI Secure Bootするには、ovmfパッケージにより提供されるUEFI
firmwareを利用する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;window11noinsutoru&quot;&gt;Window11のインストール&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;kvmjia-xiang-masinnoqi-dong-fang-fa&quot;&gt;KVM仮想マシンの起動方法&lt;&#x2F;h3&gt;
&lt;p&gt;Windows11のインストールメディア、virtioドライバインストール用のisoイメージをダウンロードしておきます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;software-download&#x2F;windows11&quot;&gt;Download
Windows 11&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fedorapeople.org&#x2F;groups&#x2F;virt&#x2F;virtio-win&#x2F;direct-downloads&#x2F;archive-virtio&#x2F;&quot;&gt;Windows用virtioドライバのありか&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;必要パッケジージのインストール&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo apt-get install qemu-system-x86 virt-viewer ovmf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;qcow2ディスクイメージを作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-img create -f qcow2 win11pro.qcow2 40G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;書き込み用のFirmwareのローカルコピーを作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cp &#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;OVMF_VARS_4M.ms.fd .&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;hosutono-dev-tpm0wopasusurudeshi-uchang-he&quot;&gt;ホストの&#x2F;dev&#x2F;tpm0をパススルーで使う場合&lt;&#x2F;h4&gt;
&lt;p&gt;以下のコマンドで仮想マシンを起動できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -machine q35,accel=kvm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -m 8192 -cpu host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -smp 6,sockets=1,dies=1,cores=6,threads=1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -display spice-app \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=.&#x2F;win11pro.qcow2,if=virtio,format=qcow2,discard=unmap \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=~&#x2F;Downloads&#x2F;Win11_22H2_Japanese_x64v1.iso,index=0,media=cdrom \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=~&#x2F;Downloads&#x2F;virtio-win-0.1.229.iso,index=1,media=cdrom \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive if=pflash,format=raw,unit=0,file=&#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;OVMF_CODE_4M.ms.fd,readonly=on \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive if=pflash,format=raw,file=.&#x2F;OVMF_VARS_4M.ms.fd \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -tpmdev passthrough,id=tpm0,path=&#x2F;dev&#x2F;tpm0,cancel-path=&#x2F;dev&#x2F;null \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -device tpm-tis,tpmdev=tpm0 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;sohutoueanotpmdebaisuemiyuretawoshi-uchang-he&quot;&gt;ソフトウェアのTPMデバイスエミュレータを使う場合&lt;&#x2F;h4&gt;
&lt;p&gt;TPMデバイスエミュレータswtpmを起動しておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir mytpm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;swtpm socket --tpmstate dir=.&#x2F;mytpm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--tpm2 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--ctrl type=unixio,path=.&#x2F;mytpm&#x2F;swtpm-sock \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--log level=20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下のコマンドで仮想マシンを起動できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -machine q35,accel=kvm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -m 8192 -cpu host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -smp 6,sockets=1,dies=1,cores=6,threads=1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -display spice-app \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=.&#x2F;win11pro.qcow2,if=virtio,format=qcow2,discard=unmap \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=~&#x2F;Downloads&#x2F;Win11_22H2_Japanese_x64v1.iso,index=0,media=cdrom \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive file=~&#x2F;Downloads&#x2F;virtio-win-0.1.229.iso,index=1,media=cdrom \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive if=pflash,format=raw,unit=0,file=&#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;OVMF_CODE_4M.ms.fd,readonly=on \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -drive if=pflash,format=raw,file=.&#x2F;OVMF_VARS_4M.ms.fd \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -chardev socket,id=chrtpm,path=.&#x2F;mytpm&#x2F;swtpm-sock \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -tpmdev emulator,id=tpm0,chardev=chrtpm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -device tpm-tis,tpmdev=tpm0 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;jia-xiang-masingali-tishang-garuto-uefsierugaqi-dong-sitesimau&quot;&gt;仮想マシンが立ち上がると、UEFシェルが起動してしまう。&lt;&#x2F;h3&gt;
&lt;p&gt;どうやらUEFIブートの場合、UEFIの設定画面でブートデバイスの優先順位を変更してやる必要があるようです。
UEFIシェルをexitで抜けるとUEFIの設定メニューに入るので、そこでUEFIシェルの優先順位をCDROM&#x2F;DVDROMなどインストールメディアよりも低くします。
そして、RestまたはContinueで、Windowsインストール用のCDROMからブートします。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;UEFI_Interactive_Shell01.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;UEFI_Menu03_2.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;UEFI_Menu05_2.png&quot; width=&quot;30%&quot;&gt;
&lt;h3 id=&quot;insutoruxian-nodoraibugajian-enai&quot;&gt;インストール先のドライブが見えない&lt;&#x2F;h3&gt;
&lt;p&gt;E:ドライブ(virtio-win-xx)にあるドライバを読み込むと、qcow2のディスクイメージが見えるようになるので、そこにWindows11をインストールします。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer03.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer04.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer06.png&quot; width=&quot;30%&quot;&gt;
&lt;h3 id=&quot;insutorushi-nimicrosoftakauntohenosaininwoqiu-merareru&quot;&gt;インストール時にMicrosoftアカウントへのサインインを求められる&lt;&#x2F;h3&gt;
&lt;p&gt;no@thankyou.comで一度サインインに失敗すると、ローカルアカウントが作成できます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer10.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer12.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;Win11Installer13.png&quot; width=&quot;30%&quot;&gt;
&lt;h3 id=&quot;can-rinovirtiodoraibawoinsutoru&quot;&gt;残りのvirtioドライバーをインストール&lt;&#x2F;h3&gt;
&lt;p&gt;Windowsセットアップ完了後、Windows上でE:ドライブ（virtio-win-0.1.229）を開きます。そこにあるインストーラを起動し、virtioドライバをインストールしておきます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;virtio_install01.png&quot; width=&quot;30%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;virtio_install02.png&quot; width=&quot;30%&quot;&gt;
&lt;p&gt;以上で、ネットワーク関連は未設定状態ですが、Windows11がインストールされたqcow2ディスクイメージ、win11pro.qcow2ができあがります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pu-duan-shi-inotameni&quot;&gt;普段使いのために&lt;&#x2F;h2&gt;
&lt;p&gt;Windows11のインストールは、ネットワーク無しで行った。仮想マシン上のWindows11を利用するには、ネットワークが使えないと困るでしょう。
ネットワークを使えるようにするためには、次の3つの準備が必要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Linuxホスト上でのネットワーク設定&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;KVM起動コマンドをネットワークが使えるように修正&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Windows11ゲストマシン上でネットワーク設定&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;linuxhosutononetutowakusetutoatupu&quot;&gt;Linuxホストのネットワークセットアップ&lt;&#x2F;h3&gt;
&lt;p&gt;Linuxホスト上では、以下の設定を行えば十分です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brdg=kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;outif=wlan0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addr=10.0.0.254&#x2F;24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ブリッジインターフェースの準備&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brctl addbr $brdg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip add add dev $brdg $addr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip link set dev $brdg up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# IPマスカレード設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iptables -t nat -A POSTROUTING -s $addr -o $outif -j MASQUERADE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# IPフォワーディング許可&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 1 &amp;gt;  &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv4&#x2F;conf&#x2F;$outif&#x2F;forwarding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 1 &amp;gt;  &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv4&#x2F;conf&#x2F;$brdg&#x2F;forwarding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;念の為、上記で用意したものをもとに戻すのは、以下のやり方で良いでしょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# IPフォワーディング許可を取り消す&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 0 &amp;gt;  &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv4&#x2F;conf&#x2F;$outif&#x2F;forwarding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 0 &amp;gt;  &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv4&#x2F;conf&#x2F;$brdg&#x2F;forwarding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ブリッジインターフェースを消す&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip link set dev $brdg down&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brctl delbr $brdg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# IPマスカレード設定を消す&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iptables -t nat -D POSTROUTING -s $addr -o $outif -j MASQUERADE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;windowsgesutoqi-dong-komando&quot;&gt;Windowsゲスト起動コマンド&lt;&#x2F;h3&gt;
&lt;p&gt;qemuコマンドはオプションが多いのでスクリプト化しておくと良いでしょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;run.win11.sh:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -m 8192 -cpu host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -smp 6,sockets=1,dies=1,cores=6,threads=1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -drive file=.&#x2F;win11pro.qcow2,if=virtio,format=qcow2,discard=unmap \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -display spice-app \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -machine q35,accel=kvm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -rtc base=localtime,clock=host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -drive if=pflash,format=raw,unit=0,file=&#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;OVMF_CODE_4M.ms.fd,readonly=on \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -drive if=pflash,format=raw,file=.&#x2F;OVMF_VARS_4M.ms.fd \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -tpmdev passthrough,id=tpm0,path=&#x2F;dev&#x2F;tpm0,cancel-path=&#x2F;dev&#x2F;null \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -device tpm-tis,tpmdev=tpm0 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -device virtio-net-pci,netdev=dev1,mac=52:54:00:11:00:12,id=net1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -netdev tap,id=dev1,vhost=on,script=.&#x2F;qemu-ifup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;仮想マシン起動時にデバイスをホストのブリッジにアタッチします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-ifup:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bridge=kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;ip link set dev $1 up promisc off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;brctl addif $bridge $1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;windowsgesutononetutowakushe-ding&quot;&gt;Windowsゲストのネットワーク設定&lt;&#x2F;h3&gt;
&lt;p&gt;次のアドレスを設定&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IPv4アドレス: 10.0.0.1&#x2F;24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ゲートウェイ: 10.0.0.254&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DNSサーバ: 192.168.40.1(Linuxホストと同じ設定にすると良いと思う。)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows11.html&#x2F;image&#x2F;network_setup01.png&quot; width=&quot;30%&quot;&gt;
&lt;p&gt;この他に、Windows 11 Proの場合はRemote
Desktop機能があるので、利用可能にしておくと良いでしょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sonota-notips&quot;&gt;その他のTips&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;一旦ビューワーを閉じたあともう一度接続するには&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ sudo virt-viewer -c spice+unix:&#x2F;&#x2F;&#x2F;tmp&#x2F;.JVB811&#x2F;spice.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;Remote Desktop接続は、例えば次のようにする&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;user=ktaka&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;xfreerdp &#x2F;u:$user &#x2F;size:1900x1000 +fonts +clipboard  &#x2F;audio-mode:1 &#x2F;v:10.0.0.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;qemu起動時にはwindowを表示せず、rdpのみで使うには
&lt;code&gt;--display spice-app&lt;&#x2F;code&gt;を&lt;code&gt;--display none&lt;&#x2F;code&gt;にすれば良い。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;can-kao-wen-xian&quot;&gt;参考文献&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;qemudenotpmnoshi-ifang&quot;&gt;QemuでのTPMの使い方&lt;&#x2F;h3&gt;
&lt;p&gt;以下のドキュメントに十分な情報があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;qemu-project.gitlab.io&#x2F;qemu&#x2F;specs&#x2F;tpm.html&quot;&gt;QEMU
TPM Device&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;qemudenouefi-secure&quot;&gt;QEMUでのUEFI Secure&lt;&#x2F;h3&gt;
&lt;p&gt;Bootのやり方&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;SecureBoot&#x2F;VirtualMachine&quot;&gt;SecureBootVirtualMachine&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.labbott.name&#x2F;blog&#x2F;2016&#x2F;09&#x2F;15&#x2F;secure-ish-boot-with-qemu&#x2F;&quot;&gt;Secure(ish)
boot with QEMU&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;donouefi&quot;&gt;どのUEFI&lt;&#x2F;h3&gt;
&lt;p&gt;firmwareを使うべきか&lt;&#x2F;p&gt;
&lt;p&gt;Debianのドキュメントに書いてあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Secure Boot
pre-enabledな、OVMF_CODE_4M.ms.fdとOVMF_VARS_4M.ms.fdをセットで使う。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;前者はRead Onlyで、後者はコピーしたものをRead
Write可能な状態で利用する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;UEFIのメニューでSaveした設定変更は、OVMF_VARS_4M.ms.fdのコピーに書き込まれる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&#x2F;usr&#x2F;share&#x2F;doc&#x2F;ovmf&#x2F;README.Debian&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The OVMF_CODE*.fd files provide UEFI firmware for a QEMU guest that is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;intended to be read-only. The OVMF_VARS*.fd files provide UEFI variable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;template images which are intended to be read-write, and therefore each&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;guest should be given its own copy. Here&amp;#39;s an overview of each of them:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE_4M.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Use this for booting guests in non-Secure Boot mode. While this image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  technically supports Secure Boot, it does so without requiring SMM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  support from QEMU, so it is less secure. Use the OVMF_VARS.fd template&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  with this.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE_4M.ms.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  This is a symlink to OVMF_CODE_4M.secboot.fd. It is useful in the context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  of libvirt because the included JSON firmware descriptors will tell libvirt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  to pair OVMF_VARS.ms.fd with it, which has Secure Boot pre-enabled.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE_4M.secboot.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Like OVMF_CODE_4M.fd, but will abort if QEMU does not support SMM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Use this for guests for which you may enable Secure Boot. Be aware&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  that the included JSON firmware descriptors associate this with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  OVMF_CODE_4M.fd. Which means, if you specify this image in libvirt, you&amp;#39;ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  get a guest that is Secure Boot-*capable*, but has Secure Boot disabled.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  To enable it, you&amp;#39;ll need to manually import PK&#x2F;KEK&#x2F;DB keys and activate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Secure Boot from the UEFI setup menu. If you want Secure Boot active from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  the start, consider using OVMF_CODE.ms.fd instead.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_VARS_4M.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  This is an empty variable store template, which means it has no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  built-in Secure Boot keys and Secure Boot is disabled. You can use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  it with any OVMF_CODE image, but keep in mind that if you want to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  boot in Secure Boot mode, you will have to enable it manually.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_VARS_4M.ms.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  This template has distribution-specific PK and KEK1 keys, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  the default Microsoft keys in KEK&#x2F;DB. It also has Secure Boot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  already activated. Using this with OVMF_CODE.ms.fd will boot a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  guest directly in Secure Boot mode.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF32_CODE_4M.secboot.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF32_VARS_4M.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  These images are the same as their &amp;quot;OVMF&amp;quot; variants, but for 32-bit guests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE.ms.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_CODE.secboot.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_VARS.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_VARS.ms.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  These images are the same as their &amp;quot;4M&amp;quot; variants, but for use with guests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  using a 2MB flash device. 2MB flash is no longer considered sufficient for&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  use with Secure Boot. This is provided only for backwards compatibility.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OVMF_VARS_4M.snakeoil.fd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  This image is **for testing purposes only**. It includes an insecure&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;snakeoil&amp;quot; key in PK, KEK &amp;amp; DB. The private key and cert are also&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  shipped in this package as well, so that testers can easily sign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  binaries that will be considered valid. Intended for use with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  OVMF_CODE_4M.secboot.fd.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PkKek-1-snakeoil.key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PkKek-1-snakeoil.pem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  The private key and certificate for the snakeoil key. Use these&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  to sign binaries that can be verified by the key in the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  OVMF_VARS.snakeoil.fd template. The password for the key is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;#39;snakeoil&amp;#39;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -- dann frazier , Fri, 11 Dec 2020 17:30:59 -0700&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;QEMUコマンドのみでKVM仮想マシンを起動し、Windows11をインストールする方法についてまとめました。
Window10の場合との違いは、TPM及びUEFI Secure Bootが必須であることです。
Windows11の場合も、GUIプログラムvirt-managerでのインストール方法はネット上でよく見かけますが、qemuコマンドのみでのやり方はあまり多くないようです。
余計なものはなるべくインストールしたくない人、ソフトウェアスタックをミニマムに保って中身を理解しながら使いたい人の役に立てば幸いです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>KVM再入門：Qemuコマンドラインで仮想マシンを起動し、Windows10ゲストをセットアップする。</title>
        <published>2023-03-20T00:00:00+00:00</published>
        <updated>2023-03-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2023/03/kvmqemuwindows.html/">&lt;h2 id=&quot;hazimeni&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;最近Debian
Linuxをインストールしたノートパソコン上に、KVM仮想マシンのゲストOSとして、Windows10をインストールする機会がありました。
はじめはGUI形式のvirt-managerをつかって、ボタンをポチポチ押しながらゲストOSをインストールしていました。
しかし、調べていくうちに、qemuコマンドラインのみで仮想マシンを起動しWindowsをインストールする方法にたどり着いたので、それについてまとめておこうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;virt-managerは非常に便利ですが、libvirtやそれが依存する数多くのパッケージをインストールし、libvirtdなどをデーモンとして動かしておかなければなりません。
qemuコマンドラインのみでWindowsをインストールする方法をおさえておけば、本来不必要だったものをインストールしなくて済みますし、構成がシンプルであるため動作の仕組みが容易に理解でき、なにかトラブルがあった場合にも比較的容易にデバッグが可能になると期待できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;windows10insutoru&quot;&gt;Windows10インストール&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;shi-qian-zhun-bei&quot;&gt;事前準備&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;insutorumedeia-virtiodoraibanodaunrodo&quot;&gt;インストールメディア、virtioドライバのダウンロード&lt;&#x2F;h4&gt;
&lt;p&gt;まず、あらかじめ必要なものをダウンロードしておきます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows10のインストールメディアWin10_22H2_Japanese_x64.isoを、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;ja-jp&#x2F;software-download&#x2F;windows10ISO&quot;&gt;Microsoftのページ&lt;&#x2F;a&gt;からダウンロードする。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;virtioドライバをが必要になるので、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fedorapeople.org&#x2F;groups&#x2F;virt&#x2F;virtio-win&#x2F;direct-downloads&#x2F;archive-virtio&#x2F;&quot;&gt;Fedoraのページ&lt;&#x2F;a&gt;からダウンロードします。今回は、この記事の執筆時点で最新のvirtio-win-0.1.229.isoを利用しました。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;bi-yao-patukezizinoinsutoru&quot;&gt;必要パッケジージのインストール&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo apt-get install qemu-system-x86 virt-viewer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;insutoruxian-doraibunoimezihuairuzuo-cheng&quot;&gt;インストール先ドライブのイメージファイル作成&lt;&#x2F;h4&gt;
&lt;p&gt;Windowsのインストール先として、40Gbyteのqcow2イメージファイルを作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-img create -f qcow2 win10.qcow2 40G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;bu-ju-he-hui-bi&quot;&gt;不具合回避&lt;&#x2F;h4&gt;
&lt;p&gt;後述のコマンドラインで仮想マシンを起動しようとすると、以下のようなエラーメッセージが出て、仮想マシンが起動できない。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-system-x86_64: info: Launching display with URI: spice+unix:&#x2F;&#x2F;&#x2F;tmp&#x2F;.BHI811&#x2F;spice.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-system-x86_64: Failed to launch spice+unix:&#x2F;&#x2F;&#x2F;tmp&#x2F;.BHI811&#x2F;spice.sock URI: Operation not supported&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-system-x86_64: You need a capable Spice client, such as virt-viewer 8.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これを回避するために&#x2F;root&#x2F;.config&#x2F;mimeapps.listに以下の行を追加する。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Added Associations]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x-scheme-handler&#x2F;spice+unix=remote-viewer.desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;jia-xiang-masinnoqi-dong-towindowsnoinsutoru&quot;&gt;仮想マシンの起動とWindowsのインストール&lt;&#x2F;h3&gt;
&lt;p&gt;以下のコマンドで仮想マシンを起動すると、Windowsのインストーラーウィンドウが現れますので、画面の指示に従ってインストールを進めます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -machine q35,accel=kvm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -m 8192 -cpu host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -smp 6,sockets=1,dies=1,cores=6,threads=1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -display spice-app \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -rtc base=localtime,clock=host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -drive file=.&#x2F;win10pro.qcow2,if=virtio,format=qcow2,discard=unmap \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -drive file=.&#x2F;Win10_22H2_Japanese_x64.iso,index=0,media=cdrom \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -drive file=.&#x2F;virtio-win-0.1.229.iso,index=1,media=cdrom&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最初はインストール先のドライブが見えないですが、ドライバーの読み込み→E:ドライブ→amd64→win10ディレクトリを選択しOKを押すと、virtioドライバが読み込まれ、ドライブ0が見えるようになります。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Windows10のインストールメディアにはいくつかのバージョンのWindowsが入っており、プロダクトキーの入力をスキップすると、インストールするバージョンを選択できるようになります。HomeかProかをそこで選択します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Windowsのインストールを進めると、Microsoftアカウントへのサインインを求められますが、ローカルアカウントを作成し次に進めます。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ローカルアカウント作成の選択肢が提示されない場合は、メールアドレスにno@thankyou.com、パスワードに適当な文字列を入力するといったんサインインに失敗し、ローカルアカウント作成ができるようになるようです。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;上記の仮想マシン起動コマンドではネットワークの設定を行っていないので、いずれにせよWindowsサインインは行われないはずです。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Windowsセットアップ完了後、Windows上でE:ドライブ（virtio-win-0.1.229）を開きます。そこにあるインストーラを起動し、virtioドライバをインストールしておきます。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以上で、Windows10がインストールされたKVM用のqcow2イメージができあがります。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows.html&#x2F;image&#x2F;KVM_Win10pro01.png&quot; width=&quot;45%&quot;&gt;
&lt;img src=&quot;&#x2F;2023&#x2F;03&#x2F;kvmqemuwindows.html&#x2F;image&#x2F;KVM_Win10pro02.png&quot; width=&quot;45%&quot;&gt;
&lt;h2 id=&quot;jia-xiang-masinnoli-yong&quot;&gt;仮想マシンの利用&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;raisensuren-zheng&quot;&gt;ライセンス認証&lt;&#x2F;h3&gt;
&lt;p&gt;基本的に仮想マシン一台ごとにライセンスが必要ですので、仮想マシンのWindows上でプロダクトキーを入力し、ライセンス認証を行います。Windowsを消し、Linuxをインストールしたノートパソコン上では、プリインストールしてあったWindowsのプロダクトキーが利用可能であると思われます。しかし、あまり不正確なことはここに書けないので参考にしたリンクのみを以下に示します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;http:&#x2F;&#x2F;blog.yottun8.com&#x2F;archives&#x2F;794&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;https:&#x2F;&#x2F;orebibou.com&#x2F;ja&#x2F;home&#x2F;201905&#x2F;20190527_001&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;https:&#x2F;&#x2F;superuser.com&#x2F;questions&#x2F;1313241&#x2F;install-windows-10-from-an-unbooted-oem-drive-into-virtualbox&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;Informatic&#x2F;49bd034d43e054bd1d8d4fec38c305ec&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;hosutolinuxnonetutowakushe-ding&quot;&gt;ホストLinuxのネットワーク設定&lt;&#x2F;h3&gt;
&lt;p&gt;仮想マシンのネットワーク接続についてはいくつもやり方があります。私の場合、ゲストOSがWindowsであるかLinuxにあるかに関わらず、以下の方式を好んで利用しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;仮想マシン用のブリッジを予め作成しておき、仮想マシンの起動時にそこにアタッチする。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;外部へはSNAT(MASQUERADE)で接続する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ネットワークアドレスは、10.0.0.0&#x2F;24を利用する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;仮想マシン上ではその帯域の固定IPを利用する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;DNSサーバは、ホストOSが使っているのと同じもの利用する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ブリッジインターフェースの作成は、Linuxのネットワーク設定ファイルに書いておき、ノートパソコン起動時に自動的に設定が行われます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;etc&#x2F;network&#x2F;interfaces.d&#x2F;kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auto kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface kbr0 inet static&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bridge_ports none&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bridge_fd 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bridge_maxwait 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    address 10.0.0.254&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    netmask 255.255.255.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    up &#x2F;etc&#x2F;network&#x2F;masquerade.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;iptables natの設定&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;etc&#x2F;network&#x2F;masquerade.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if ! iptables -t nat -C POSTROUTING -o eth0 -j MASQUERADE &amp;gt; &#x2F;dev&#x2F;null 2&amp;gt;&amp;amp;1 ; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;仮想マシン起動時に仮想マシンのネットワークインターフェースをホストLinuxのブリッジにアタッチするためのスクリプトも用意しておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;etc&#x2F;network&#x2F;qemu-ifup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bridge=kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;ip link set dev $1 up promisc off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;brctl addif $bridge $1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;jia-xiang-masinnoqi-dong-komandorain&quot;&gt;仮想マシンの起動コマンドライン&lt;&#x2F;h3&gt;
&lt;p&gt;ネットワーク接続込のコマンドライン。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -machine q35,accel=kvm \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -m 8192 -cpu host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -smp 6,sockets=1,dies=1,cores=6,threads=1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -display spice-app \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -rtc base=localtime,clock=host \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -drive file=.&#x2F;win10pro.qcow2,if=virtio,format=qcow2,discard=unmap \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -device virtio-net-pci,netdev=dev1,mac=52:54:00:11:00:12,id=net1 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -netdev tap,id=dev1,vhost=on,script=&#x2F;etc&#x2F;network&#x2F;qemu-ifup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;そして、仮想マシンの起動後、Windows上でIPアドレス、DNSサーバー等の設定を行います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;QEMUコマンドのみでKVM仮想マシンを起動し、Windows10をインストールする方法についてまとめました。
ネット上にはvirshコマンドラインや、virt-managerのGUIでのインストール方法はよく見かけますが、qemuコマンドのみでのやり方はあまり多くないようです。
余計なものはなるべくインストールしたくない人、ソフトウェアスタックをミニマムにして中身を理解しながら使いたい人のお役に立てば幸いです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>社外からSOCKS5プロキシ経由でRemoteDesktop接続</title>
        <published>2021-01-22T00:00:00+00:00</published>
        <updated>2021-01-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2021/01/socks5remotedesktop.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2021/01/socks5remotedesktop.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2021/01/socks5remotedesktop.html/">&lt;p&gt;SOCKS5トンネル掘り &lt;&#x2F;p&gt;
&lt;p&gt;hirakegoma.sh&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while true; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;Connecting gw.example.com:22 ... &amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ssh -4ND 18888 gw.example.com -p 22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo retrying&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;xfreerdpのラッパースクリプト&lt;&#x2F;p&gt;
&lt;p&gt;社内(≈名前解決可能)なら直接、そうでないならSOCKS5プロキシ経由でRDP接続する。&lt;&#x2F;p&gt;
&lt;p&gt;rdp.sh&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;case &amp;quot;$1&amp;quot; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	host1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	user=user1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	host=host1.inside.example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	host2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	user=user2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	host=host2.inside.example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	*)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	echo Usage $1 host_nick_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;esac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if host $host ; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	echo Connecting $user@$host&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	xfreerdp &#x2F;u:$user &#x2F;size:1400x900 &#x2F;v:$host&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	echo Connecting $user@$host via SOCKS proxy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	xfreerdp &#x2F;u:$user &#x2F;size:1400x900 &#x2F;v:$host &#x2F;proxy:socks5:&#x2F;&#x2F;localhost:18888&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>SSH踏み台サーバを経由して社内サーバにアクセスする</title>
        <published>2021-01-21T00:00:00+00:00</published>
        <updated>2021-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2021/01/ssh.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2021/01/ssh.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2021/01/ssh.html/">&lt;p&gt;最近のリモートワークの状況下で自宅から職場のサーバにアクセスしなければならないことも多いと思います。&lt;&#x2F;p&gt;
&lt;p&gt;VPNを使ったり、OAuth付きのproxyサーバを立てたり、いろいろとやり方があると思います。今回はSSHの踏み台サーバ経由で職場内のWEBサーバにアクセスする方法について、やり方を記録して置こうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;昔から、1. SSHのダイナミックフォワードでトンネルを掘る、2. ブラウザにproxy.pacを読ませて特定の(社内サーバ)URLのみにそのトンネルを使わせる、といった方法は利用していましたが、あるバージョンを境にChromeでproxy.pacファイルを読まなくなってしまい、放置していました。&lt;&#x2F;p&gt;
&lt;p&gt;今回改めてやり方を調べてみたというのが背景です。&lt;&#x2F;p&gt;
&lt;p&gt;トンネル掘り&lt;&#x2F;p&gt;
&lt;p&gt;トンネルにはSSHのダイナミックフォワードを使います。例えば以下のような感じ。&lt;&#x2F;p&gt;
&lt;p&gt;hirakegoma.sh&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while true; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;Connecting gw.example.com:22 ... &amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ssh -4ND 18888 gw.example.com -p 22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo retrying&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;職場内のサーバ、xxx.inside.example.comへのアクセスを上で作ったトンネルを経由させるには、例えば以下のようにすれば良い。&lt;&#x2F;p&gt;
&lt;p&gt;proxy.pac&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function FindProxyForURL(url, host)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if (dnsDomainIs(host, &amp;quot;.inside.example.com&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (isResolvable(host))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                return &amp;quot;DIRECT&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                return &amp;quot;SOCKS5 localhost:18888&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;return &amp;quot;DIRECT&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;会社内ではサーバ名前解決ができるであろうから、名前ができないときのみトンネルを通すようになっている。&lt;&#x2F;p&gt;
&lt;p&gt;Chrome起動オプション&lt;&#x2F;p&gt;
&lt;p&gt;Chromeでproxy.pacのありかを指定するには、システムの環境設定でやればいいらしい。残念なことにLinuxの場合にはそういうわけにもいかず、Chrome起動時にオプションを引数として渡してあげる必要がある。&lt;&#x2F;p&gt;
&lt;p&gt;以前は以下のような感じでうまく行っていた。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;google-chrome %U --proxy-pac-url=file:&#x2F;&#x2F;&#x2F;home&#x2F;ktaka&#x2F;proxy.pac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最近は&quot;--proxy-pac-url=f&quot;でファイルを指定しても無視されてしまうようなので、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bugs.chromium.org&#x2F;p&#x2F;chromium&#x2F;issues&#x2F;detail?id=839566#c22&quot;&gt;ワークアラウンド&lt;&#x2F;a&gt;が必要である。&lt;&#x2F;p&gt;
&lt;p&gt;結局行き着いたのが以下のオプション。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;google-chrome %U --proxy-pac-url=&amp;#39;data:application&#x2F;x-javascript-config;base64,&amp;#39;$(base64 -w0 &#x2F;home&#x2F;me&#x2F;proxy.pac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最近のサーバやワークステーションは、BMCというミニプロセッサが載っていて、Webブラウザー経由で電源のオンオフ、ハードリセット、BIOS設定の変更などができます。&lt;&#x2F;p&gt;
&lt;p&gt;今回のような簡易プロキシを使うことによって、これらの職場内にあるサーバに、外部から簡単にアクセスすることができるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;BMC搭載の高性能なワークステーションはこちらをどうぞ→&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ccmp.jp&#x2F;hardware&#x2F;workstation&#x2F;373-amd-threadripper.html&quot;&gt;AMD Ryzen™ Threadripper™ ECCメモリ IPMI搭載 ワークステーション&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Debian Linuxのノートパソコンでハイバネート</title>
        <published>2021-01-17T00:00:00+00:00</published>
        <updated>2021-01-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2021/01/debian-linux.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2021/01/debian-linux.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2021/01/debian-linux.html/">&lt;p&gt;Linuxカーネルには、スワップ領域にメモリの内容を書き出してハイバネートする機能がある。 必要な要件等は以下の通り。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;十分な大きさのスワップデバイスまたはファイルを用意する。(メモリ容量と同じくらいあれば良いが、そこまでなくても良いという情報もある。)&lt;&#x2F;li&gt;
&lt;li&gt;カーネル起動オプションresume=デバイス名を加えカーネルを起動。&lt;&#x2F;li&gt;
&lt;li&gt;uswsuspを利用することもできるが、利用しなくても良い。その場合initrdをいじる必要は無い。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;参考文献&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.archlinux.jp&#x2F;index.php&#x2F;%E3%82%B5%E3%82%B9%E3%83%9A%E3%83%B3%E3%83%89%E3%81%A8%E3%83%8F%E3%82%A4%E3%83%90%E3%83%8D%E3%83%BC%E3%83%88&quot;&gt;https:&#x2F;&#x2F;wiki.archlinux.jp&#x2F;index.php&#x2F;サスペンドとハイバネート&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;power&#x2F;states.txt&quot;&gt;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;power&#x2F;states.txt&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;power&#x2F;basic-pm-debugging.html&quot;&gt;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;power&#x2F;basic-pm-debugging.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以下、実際の設定&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;fstab (該当部分のみ)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&#x2F;dev&#x2F;nvme0n1p7	swap    swap    defaults  0 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;swapfile	swap	swap	defaults  0 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;デバイスをスワップとして使う場合と、ファイル(&#x2F;swapfile)をスワップとして使う場合とで必要なカーネルパラメータが異なる。 後者の場合はresume_offsetも必要。オフセット値は以下のように確認可能。この場合86093824がオフセット値。&lt;&#x2F;p&gt;
&lt;p&gt;sudo filefrag -v &#x2F;swapfile&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Filesystem type is: ef53&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File size of &#x2F;swapfile is 17179869184 (4194304 blocks of 4096 bytes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ext:     logical_offset:        physical_offset: length:   expected: flags:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   0:        0..    2047:   86093824..  86095871:   2048:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   1:     2048..    4095:   86167552..  86169599:   2048:   86095872:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   2:     4096..    8191:   86155264..  86159359:   4096:   86169600:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下略&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg (該当部分のみ)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menuentry &amp;quot;Debian Linux resume-test1&amp;quot; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;linux &#x2F;boot&#x2F;vmlinuz root=&#x2F;dev&#x2F;nvme0n1p6 vga=0x305 panic=10 net.ifnames=0 biosdevname=0 resume=&#x2F;dev&#x2F;nvme0n1p7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menuentry &amp;quot;Debian Linux resume-test2&amp;quot; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;linux &#x2F;boot&#x2F;vmlinuz root=&#x2F;dev&#x2F;nvme0n1p6 vga=0x305 panic=10 net.ifnames=0 biosdevname=0 resume=&#x2F;dev&#x2F;nvme0n1p6 resume_offset=86093824&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ノートパソコンのディスプレイを閉じたときにhibernateする設定&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;acpi&#x2F;events&#x2F;lid_down&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;event=button[ &#x2F;]lid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;action=&#x2F;etc&#x2F;acpi&#x2F;lid_down.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;etc&#x2F;acpi&#x2F;lid_down.sh&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;grep -q closed &#x2F;proc&#x2F;acpi&#x2F;button&#x2F;lid&#x2F;*&#x2F;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if [ $? -eq 0 ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	echo platform &amp;gt; &#x2F;sys&#x2F;power&#x2F;disk ; echo disk &amp;gt; &#x2F;sys&#x2F;power&#x2F;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exit 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以上で、ハイバネートできることを確認した。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Debian LinuxのノートパソコンでドトールWiFiにつなぐ</title>
        <published>2021-01-15T00:00:00+00:00</published>
        <updated>2021-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2021/01/debian-linuxwifi.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2021/01/debian-linuxwifi.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2021/01/debian-linuxwifi.html/">&lt;p&gt;ドトール、エクセルシオールカフェには無料のWiFiサービスがある。Linuxで接続するのにちょっと手間取ったので、やり方をメモしておく。&lt;&#x2F;p&gt;
&lt;p&gt;設定ファイルを作成。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;etc&#x2F;network&#x2F;interfaces.d&#x2F;doutor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface dt inet dhcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	wpa-ssid &amp;quot;DOUTOR_FREE_Wi-Fi&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	wpa-key-mgmt NONE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;インターフェースをアップするとDHCP経由でアドレスの取得ができる。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ktaka@dyna:~$ sudo ifup wlan0=dt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet Systems Consortium DHCP Client 4.4.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copyright 2004-2018 Internet Systems Consortium.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;All rights reserved.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For info, please visit https:&#x2F;&#x2F;www.isc.org&#x2F;software&#x2F;dhcp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Listening on LPF&#x2F;wlan0&#x2F;3c:9c:0f:8d:c8:4a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sending on   LPF&#x2F;wlan0&#x2F;3c:9c:0f:8d:c8:4a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sending on   Socket&#x2F;fallback&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHCPOFFER of 10.68.161.211 from 10.68.128.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHCPREQUEST for 10.68.161.211 on wlan0 to 255.255.255.255 port 67&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHCPACK of 10.68.161.211 from 10.68.128.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bound to 10.68.161.211 -- renewal in 138 seconds.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このあとブラウザで任意のページを閲覧しようとするとWEBの認証ページが表示されるので、承諾すればネットワークが使用可能になる。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Dynabook GZ83&#x2F;MLにDebian Linuxをのせて使ってます。</title>
        <published>2021-01-15T00:00:00+00:00</published>
        <updated>2021-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2021/01/dynabook-gz83mldebian-linux.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2021/01/dynabook-gz83mldebian-linux.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2021/01/dynabook-gz83mldebian-linux.html/">&lt;p&gt;先日購入したノートパソコンのご紹介です。&lt;&#x2F;p&gt;
&lt;p&gt;ちまたではM1 Macbook Air&#x2F;Proの評判が高いようですが、920gの12インチMacbookが出なかったことに落胆し、軽量なノートパソコンを購入してしまいました。&lt;&#x2F;p&gt;
&lt;p&gt;M1 Macの性能がものすごく高いようなので、失敗したかなと思いつつも、でもAirといっても1.3kgもあったら持って歩けないよなぁとか、やっぱり悩みつつもLinuxを日頃から触るのは楽しいよなぁとか、自分に言い聞かせながら悶々とした日々を過ごしております。&lt;&#x2F;p&gt;
&lt;p&gt;Macbook Airとても良いんですけどね、重くなければ。&lt;&#x2F;p&gt;
&lt;p&gt;そして購入したノートパソコンがこれ。Dynabook GZ83&#x2F;ML。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dynabook.com&#x2F;direct&#x2F;pc&#x2F;catalog&#x2F;2020-spring&#x2F;gz83m&#x2F;spec.html&quot;&gt;https:&#x2F;&#x2F;dynabook.com&#x2F;direct&#x2F;pc&#x2F;catalog&#x2F;2020-spring&#x2F;gz83m&#x2F;spec.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2021&#x2F;01&#x2F;dynabook-gz83mldebian-linux.html&#x2F;image&#x2F;1610706729565933-0.png&quot; width=&quot;400&quot;&gt;
&lt;img src=&quot;&#x2F;2021&#x2F;01&#x2F;dynabook-gz83mldebian-linux.html&#x2F;image&#x2F;1610706724492470-1.png&quot; width=&quot;400&quot;&gt;
&lt;img src=&quot;&#x2F;2021&#x2F;01&#x2F;dynabook-gz83mldebian-linux.html&#x2F;image&#x2F;1610706719657116-2.png&quot; width=&quot;400&quot;&gt;
&lt;p&gt;洒落っ気も何も無いですけど、とにかく軽くて、そこそこ良いCPU積んでるんです。&lt;&#x2F;p&gt;
&lt;p&gt;仕様は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dynabook.com&#x2F;direct&#x2F;pc&#x2F;catalog&#x2F;2020-spring&#x2F;gz83m&#x2F;spec.html&quot;&gt;このページ&lt;&#x2F;a&gt;にあるとおりですが、特に気に入ってる点は、&lt;&#x2F;p&gt;
&lt;p&gt;6コアCore i7 CPU、16GBメモリ、512GB NVMe SSD、859gという軽さなどです。&lt;&#x2F;p&gt;
&lt;p&gt;あと1GNICやHDMIのコネクタが最初からついていたり、USB Type-C PDで充電できたりするのも、とても便利です。&lt;&#x2F;p&gt;
&lt;p&gt;OSはもちろん、Debian Linuxにしてるんですけど、今回はWindowsもデュアルブートできるようにしてあります。&lt;&#x2F;p&gt;
&lt;p&gt;会計ソフトやNovaのお茶の間留学のソフトなんかが、Windowsじゃないと動かないので、仕方なく残している感じです。&lt;&#x2F;p&gt;
&lt;p&gt;デュアルブートも昔からありますが、最近のノートパソコンはBiosがUEFI化されていて、ちょっと昔とは勝手が違っていたりしました。&lt;&#x2F;p&gt;
&lt;p&gt;その辺りも、追々ブログにまとめられたらと思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>pingが通らない時</title>
        <published>2020-11-25T00:00:00+00:00</published>
        <updated>2020-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2020/11/ping.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2020/11/ping.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2020/11/ping.html/">&lt;p&gt;pingができなくなるのは、うっかりファイルシステムをコピーした際にcapabilityを落としてしまったことが原因であることもあるらしい。
rsyncやtarでファイルシステムごとコピーする際は、--xattrsを忘れずに。&lt;&#x2F;p&gt;
&lt;p&gt;pingが通らない。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ ping str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ping: socket: Address family not supported by protocol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ ping -4 str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ping: socket: Operation not permitted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;capabilityの確認。何も付いてない。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ sudo getcap &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;capabilityの付与と確認。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ sudo setcap cap_net_raw=ep &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ sudo getcap &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;bin&#x2F;ping = cap_net_raw+ep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&quot;cap_net_raw+ep&quot;が付与された。&lt;&#x2F;p&gt;
&lt;p&gt;そしてping通るようになった。&lt;&#x2F;p&gt;
&lt;p&gt;   &lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ ping str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PING stretch.h.ccmp.jp (192.168.60.3) 56(84) bytes of data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64 bytes from stretch.h.ccmp.jp (192.168.60.3): icmp_seq=1 ttl=64 time=6.89 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64 bytes from stretch.h.ccmp.jp (192.168.60.3): icmp_seq=2 ttl=64 time=3.100 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64 bytes from stretch.h.ccmp.jp (192.168.60.3): icmp_seq=3 ttl=64 time=3.53 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下ちょっと実験する際などに役立つコマンド達 &lt;&#x2F;p&gt;
&lt;p&gt;capability, xattrの確認コマンド、何もない時&lt;&#x2F;p&gt;
&lt;p&gt;   &lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# getcap &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# getfattr -n security.capability &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;bin&#x2F;ping: security.capability: No such attribute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# sudo getfattr -d &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# sudo attr -l  &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;capability, xattrの確認コマンド、権限がちゃんと付与されている時&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# getcap &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;bin&#x2F;ping = cap_net_raw+ep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# attr -l  &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Attribute &amp;quot;capability&amp;quot; has a 20 byte value for &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# getfattr -n security.capability &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;getfattr: Removing leading &amp;#39;&#x2F;&amp;#39; from absolute path names&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# file: bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;xattrごと削除するコマンド&lt;&#x2F;p&gt;
&lt;p&gt;   &lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# setfattr -x security.capability &#x2F;bin&#x2F;ping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;参考文献&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man5&#x2F;attr.5.html&quot;&gt;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man5&#x2F;attr.5.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;tarの場合 --xattrsを付ける &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;tar&#x2F;manual&#x2F;html_node&#x2F;Extended-File-Attributes.html&quot;&gt;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;tar&#x2F;manual&#x2F;html_node&#x2F;Extended-File-Attributes.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;rsyncの場合も --xattrs, -Xを付ける &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;rsync.1.html&quot;&gt;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;rsync.1.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;capabilities&quot;&gt;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;capabilities&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>LinuxでのSLAAC IPv6アドレス自動設定</title>
        <published>2020-05-17T00:00:00+00:00</published>
        <updated>2020-05-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2020/05/linuxslaac-ipv6.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2020/05/linuxslaac-ipv6.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2020/05/linuxslaac-ipv6.html/">&lt;p&gt;Linuxにおいて、SLAACによるIPv6アドレスアサインにはいくつかのモードがあり、以下のカーネルパラメータをセットすることで制御できるようです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addr_gen_mode - INTEGER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Defines how link-local and autoconf addresses are generated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	0: generate address based on EUI64 (default)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	1: do no generate a link-local address, use EUI64 for addresses generated&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	   from autoconf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	2: generate stable privacy addresses, using the secret from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	   stable_secret (RFC7217)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	3: generate stable privacy addresses, using a random secret if unset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;モード２のRFC7217形式を利用するためには以下のように、stable_secretをあらかじめセットしておく必要があります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stable_secret - IPv6 address&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	This IPv6 address will be used as a secret to generate IPv6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	addresses for link-local addresses and autoconfigured&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ones. All addresses generated after setting this secret will&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	be stable privacy ones by default. This can be changed via the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	addrgenmode ip-link. conf&#x2F;default&#x2F;stable_secret is used as the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	secret for the namespace, the interface specific ones can&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	overwrite that. Writes to conf&#x2F;all&#x2F;stable_secret are refused.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	It is recommended to generate this secret during installation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	of a system and keep it stable after that.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	By default the stable secret is unset.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;networking&#x2F;ip-sysctl.txt&quot;&gt;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;networking&#x2F;ip-sysctl.txt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;modo0&quot;&gt;モード0:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc4291#appendix-A&quot;&gt;RFC4291&lt;&#x2F;a&gt;形式のアドレスを自動生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# echo 0 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0&#x2F;addr_gen_mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ifdown eth0; ifup eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ip -6 add show dev eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4: eth0: &amp;amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;amp;gt; mtu 1500 state UP qlen 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fd00::40:c23f:d5ff:fe69:4af3&#x2F;64 scope global dynamic mngtmpaddr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft 86383sec preferred_lft 14383sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fe80::c23f:d5ff:fe69:4af3&#x2F;64 scope link&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft forever preferred_lft forever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;IPv6アドレスはRAから得られたPREFIX(fd00::40&#x2F;64)と、MACアドレス(c0:3f:d5:69:4a:f3)を変換したEUI64アドレス(c23f:d5ff:fe69:4af3)から生成されていることがわかります。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;modo1&quot;&gt;モード1:&lt;&#x2F;h4&gt;
&lt;p&gt;アドレスを自動生成しません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# echo 1 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0&#x2F;addr_gen_mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ifdown eth0; ifup eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ip -6 add show dev eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;modo2&quot;&gt;モード2:&lt;&#x2F;h4&gt;
&lt;p&gt;Semantically Opaque Interface Identifiers(SOII, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc7217&quot;&gt;RFC7217&lt;&#x2F;a&gt;)形式のアドレスを自動生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# echo &amp;quot;::&amp;quot; &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0&#x2F;stable_secret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# echo 2 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0&#x2F;addr_gen_mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ifdown eth0; ifup eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ip -6 add show dev eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4: eth0:  mtu 1500 state UP qlen 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fd00::40:c81b:6763:31dc:887a&#x2F;64 scope global dynamic mngtmpaddr stable-privacy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft 86398sec preferred_lft 14398sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fe80::df74:fff4:bdf2:e8ae&#x2F;64 scope link stable-privacy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft forever preferred_lft forever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;IPv6アドレスはRAから得られたPREFIX(fd00::40&#x2F;64)と、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc7217&quot;&gt;RFC7217&lt;&#x2F;a&gt;に定められた方式で計算されるランダム識別子から生成されます。ランダム識別子は次のような関数から計算されsecret_keyに変更がなければ(すなわちstable_secretがセットされていれば)、毎回同じものになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;modo3&quot;&gt;モード3:&lt;&#x2F;h4&gt;
&lt;p&gt;Semantically Opaque Interface Identifiers(SOII, RFC7217形式のアドレスを自動生成します。stable_secretがセットされている場合にはモード2と同じアドレスを生成し、されていない場合にはrandom secretを用いアドレスを生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# echo 3 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0&#x2F;addr_gen_mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ifdown eth0; ifup eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ip -6 add show dev eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4: eth0:  mtu 1500 state UP qlen 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fd00::40:73be:87b2:8746:6bb3&#x2F;64 scope global dynamic mngtmpaddr stable-privacy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft 86395sec preferred_lft 14395sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 fe80::ddae:cc16:47e0:156d&#x2F;64 scope link stable-privacy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft forever preferred_lft forever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;モード2との違いは、stable_secretがセットされていない場合に、毎回異なるランダム識別子からIPv6アドレスが生成されるということです。&lt;&#x2F;p&gt;
&lt;p&gt;addr_gen_modeのパラメータは以下のコマンドでもセットできるようです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip link set dev eth0 addrgenmode  { eui64 | none | stable_secret | random }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;can-kao-wen-xian&quot;&gt;参考文献&lt;&#x2F;h4&gt;
&lt;p&gt;「クライアントOSのIPv6実装検証から見たネットワーク運用における課題の考察」&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ipsj.or.jp&#x2F;dp&#x2F;contents&#x2F;publication&#x2F;36&#x2F;S0904-R1701.html&quot;&gt;https:&#x2F;&#x2F;www.ipsj.or.jp&#x2F;dp&#x2F;contents&#x2F;publication&#x2F;36&#x2F;S0904-R1701.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;「TIPS: 拡張EUI-64を使わないIPv6アドレス生成」&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.drvlabo.jp&#x2F;wp&#x2F;archives&#x2F;1713&quot;&gt;http:&#x2F;&#x2F;www.drvlabo.jp&#x2F;wp&#x2F;archives&#x2F;1713&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>LinuxルーターでのDS-Lite設定</title>
        <published>2020-05-05T00:00:00+00:00</published>
        <updated>2020-05-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2020/05/linuxds-lite.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2020/05/linuxds-lite.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2020/05/linuxds-lite.html/">&lt;p&gt;昨日に引き続き、自宅のLinuxルーター上でDS-Liteの設定を行いました。&lt;&#x2F;p&gt;
&lt;p&gt;BB.exciteコネクト(IPoE接続プラン)ではIPv6回線のトンネルを通して、インターネットにIPv4接続することが可能です。&lt;&#x2F;p&gt;
&lt;p&gt;実際のサービスはtransixのDS-Liteを使うことになるのですが、この回線を使うことで混み合っているNGNの網終端を通らずに済むことになるので、快適なネットライフが待っているらしいのです。&lt;&#x2F;p&gt;
&lt;p&gt;ところが我が家ではすでにPPPoEでのIPv4の固定IP契約があり、その固定IPをVPN、DNSサーバなどいろいろなサービスに使っていて、別のIPアドレスに変わってしまって困ります。またDS-Liteの場合にはグローバルIPアドレスを複数のユーザーで共有して使うので、なおさら外部からのアクセスなどには使うことができません。
そういった理由で、IPv4に関しては既存のPPPoEのままにするつもりでいました。&lt;&#x2F;p&gt;
&lt;p&gt;しかしながらWebページの閲覧やYutubeコンテンツの視聴に使われるHTTPやHTTPSに限れば固定IPは不要です。また、Linuxルーターの場合には、宛先のIPやプロトコル、ポート番号に応じてきめ細かく接続先の経路を選ぶことができます。そこで、せっかくなので今回、HTTPとHTTPSに限って、DS-Liteの経路を利用する設定を試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;IPv4 over IPv6のトンネルセットアップ&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip -6 tunnel add dslite mode ip4ip6 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         remote 2404:8e00::feed:100 local 2409:x:x:x::1  dev eth0.10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip link set dev dslite up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;宛先が192.168.0.0&#x2F;16以外(宛先がWAN向き)で、宛先ポート80、443のパケットにマークをつける。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iptables -A PREROUTING -i eth0 -t mangle \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       ! -d 192.168.0.0&#x2F;16 -p tcp --dport 443 -j MARK --set-mark 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iptables -A PREROUTING -i eth0 -t mangle \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       ! -d 192.168.0.0&#x2F;16 -p tcp --dport 80 -j MARK --set-mark 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;マークがついているパケットだけDS-Liteのトンネルを通るようにする。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip route add default dev dslite table 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip rule add from all fwmark 1 table 100 prio 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これで自宅LAN内の任意のマシンからDS-Lite回線をHTTP、HTTPS接続できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;経路が変わっているかどうかは、WEB上にあるアクセス元IPを判別するページ(例えば&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cman.jp&#x2F;network&#x2F;support&#x2F;go_access.cgi&quot;&gt;ここ&lt;&#x2F;a&gt;)などで確認可能で、ちゃんと切り替わっていることが確認できました。&lt;&#x2F;p&gt;
&lt;p&gt;いままで回線の遅さに悩んでいましたが、これで解決されるのか楽しみです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>LinuxルーターでのIPv6 IPoE設定</title>
        <published>2020-05-04T00:00:00+00:00</published>
        <updated>2020-05-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2020/05/linuxipv6-ipoe.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2020/05/linuxipv6-ipoe.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2020/05/linuxipv6-ipoe.html/">&lt;p&gt;こんにちは、コロナの影響でステイホームでリモートワークを励行しています。多くの人たちが業務のために自宅からインターネットにアクセスしたり、外に遊びに行けず自宅でネットコンテンツを長時間視聴するためか、日時を問わずNTTフレッツ回線のネットワークが非常に遅くなっているような気がします。&lt;&#x2F;p&gt;
&lt;p&gt;フレッツ回線の混雑の情報をネットで調べてみると、もともと回線設備の容量が少なめで、主にIPv4のPPPoE接続で利用しているNTTのNGNの網終端装置で回線が混み合っているのではないかということです。&lt;&#x2F;p&gt;
&lt;p&gt;(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eng-blog.iij.ad.jp&#x2F;archives&#x2F;5536&quot;&gt;https:&#x2F;&#x2F;eng-blog.iij.ad.jp&#x2F;archives&#x2F;5536&lt;&#x2F;a&gt; &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;enog.jp&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;08&#x2F;20180720-ENOG51-Kashiwazaki.pdf&quot;&gt;http:&#x2F;&#x2F;enog.jp&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;08&#x2F;20180720-ENOG51-Kashiwazaki.pdf&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;これを回避するには比較的空いているIPv6の接続口を利用するのが良いとのことでした。NTTのNGNネットワークとインターネットの境界の設備は、NTTの方針に依存せず増強できるとのことです。&lt;&#x2F;p&gt;
&lt;p&gt;そこでIPv6 IPoE + DS-Lite なプロバイダと契約し、もともと自宅で利用していたLinuxルーターをIPv6に対応させました。&lt;&#x2F;p&gt;
&lt;p&gt;今回契約したのはBB.exciteコネクト(IPoE接続プラン)というもので、既存のフレッツ回線に月々700円(税抜)追加でIPv6のインターネット接続を利用できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bb.excite.co.jp&#x2F;norikae&#x2F;ipoe&#x2F;&quot;&gt;https:&#x2F;&#x2F;bb.excite.co.jp&#x2F;norikae&#x2F;ipoe&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ちなみに、本題から外れますが、我が家のルーターは手のひらサイズのIntelのNUCです。NICが一個しかついていないため、eth0からTag VLANを利用してeth0.10のインターフェースを仮想的に作りWAN側に用いています。eth0とeth0.10を後述のコマンド例で使いますが、前者が内側、後者が外側ということです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2020&#x2F;05&#x2F;linuxipv6-ipoe.html&#x2F;image&#x2F;2020-05-04-4.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;img src=&quot;&#x2F;2020&#x2F;05&#x2F;linuxipv6-ipoe.html&#x2F;image&#x2F;2020-05-04-5.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;ちなみに、ルーターのOSはDebian Busterをtarで固めたものをUSBメモリに入れ、起動時にtmpfsに展開して、ディスクレスで運用しています。こうすることで、万が一NUCが壊れたとしても適当なパソコンをルーターとしてブートすることが可能です。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2020&#x2F;05&#x2F;linuxipv6-ipoe.html&#x2F;image&#x2F;2020-05-04-3.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;h3 id=&quot;wanintahuesunoshe-ding&quot;&gt;WANインターフェースの設定&lt;&#x2F;h3&gt;
&lt;p&gt;IPv6の世界では、Stateless Address Auto-Configuration(SLAAC)という仕組みがあり、基本的に何もしなくてもIPv6アドレスがアサインされます。&lt;&#x2F;p&gt;
&lt;p&gt;Linuxの場合、IPv6関連のコンフィグオプションを有効にしたカーネルがあり、かつicmpv6のパケットを送受信できる環境であれば、いつの間にか勝手にIPv6アドレスが付与されます。&lt;&#x2F;p&gt;
&lt;p&gt;今回契約したのBB.exciteコネクト(IPoE接続プラン)は、transixというVirtual Network Enabler(VNE)が実際の通信サービスを提供しており、transixから払い出された&#x2F;64のプリフィックスがアドバタイズ(Router Advertisement (RA))され、それを受信したLinuxカーネルが、自動的にネットワーク設定を行います。&lt;&#x2F;p&gt;
&lt;p&gt;RAの内容はこのような感じになっています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;bin&#x2F;rdisc6 -1 -r 3 eth0.10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Soliciting ff02::2 (ff02::2) on eth0.10...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hop limit : 64 ( 0x40)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stateful address conf. : No&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stateful other conf. : Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Mobile home agent : No&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Router preference : medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Neighbor discovery proxy : No&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Router lifetime : 1800 (0x00000708) seconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Reachable time : 300000 (0x000493e0) milliseconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Retransmit time : 10000 (0x00002710) milliseconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Source link-layer address: 00:yy:yy:yy:53:C3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MTU : 1500 bytes (valid)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Prefix : 2409:x:x:x::&#x2F;64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;On-link : Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Autonomous address conf.: Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Valid time : 2592000 (0x00278d00) seconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pref. time : 604800 (0x00093a80) seconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from fe80::y:y:y:53c3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(参考: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hirose31.hatenablog.jp&#x2F;entry&#x2F;20060418&#x2F;1145354566&quot;&gt;https:&#x2F;&#x2F;hirose31.hatenablog.jp&#x2F;entry&#x2F;20060418&#x2F;1145354566&lt;&#x2F;a&gt; )&lt;&#x2F;p&gt;
&lt;p&gt;上記のRAに基づいて自動的に設定されたIPアドレスの様子。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;eth0.10@eth0:  mtu 1500 qdisc noqueue state UP group default qlen 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    link&#x2F;ether c0:3f:d5:69:6f:b0 brd ff:ff:ff:ff:ff:ff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 2409:x:x:x:y:y:y:6fb0&#x2F;64 scope global dynamic mngtmpaddr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;同時に登録されるルーティング情報。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2409:x:x:x::&#x2F;64 dev eth0.10 proto kernel metric 256 pref medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;default via fe80::y:y:y:53c3 dev eth0.10 proto ra metric 1024 expires 1784sec hoplimit 64 pref medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SLAACによりアサインされるアドレスは、transixから払い出されたプリフィックス (2409:x:x:x::&#x2F;64)とNICのMACアドレスを組み合わせたものです。&lt;&#x2F;p&gt;
&lt;p&gt;このようなIPv6アドレスを用いるとMACアドレスが一意であるため、これを用いてユーザーの行動が追跡される可能性があるなどプライバシーの上の問題があります。&lt;&#x2F;p&gt;
&lt;p&gt;この問題に対処するためにPrivacy Extensionという仕様が公開されており、これを用いると払い出されたプリフィックスとランダムな数字を組み合わせたIPv6アドレスを利用することができます。&lt;&#x2F;p&gt;
&lt;p&gt;つまりPrivacy Extensionを有効にするとMACアドレス由来でないアドレスもインターフェースにアサインすることができるのです。Linuxの場合はuse_tempaddrというパラメータを利用します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.tldp.org&#x2F;HOWTO&#x2F;Linux+IPv6-HOWTO&#x2F;ch06s05.html&quot;&gt;https:&#x2F;&#x2F;www.tldp.org&#x2F;HOWTO&#x2F;Linux+IPv6-HOWTO&#x2F;ch06s05.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;networking&#x2F;ip-sysctl.txt&quot;&gt;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;networking&#x2F;ip-sysctl.txt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use_tempaddr - INTEGER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Preference for Privacy Extensions (RFC3041).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     1 : enable Privacy Extensions and prefer temporary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          addresses over public addresses.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Default:  0 (for most devices)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   -1 (for point-to-point devices and loopback devices)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実際にパラメータを設定してみると、&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 2 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0.10&#x2F;use_tempaddr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Temporaryなアドレスもアサインされます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet6 2409:x:x:x:y:y:y:d384&#x2F;64 scope global temporary dynamic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       valid_lft 569580sec preferred_lft 50999sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(追記：最近ではSemantically Opaque Interface Identifiersと呼ばれる、よりプライバシーに考慮したアドレスアサイン方式があるようなのでそれにも&lt;a href=&quot;&#x2F;2020&#x2F;05&#x2F;linuxslaac-ipv6.html&quot;&gt;対応しました&lt;&#x2F;a&gt;。)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lanintahuesunoshe-ding&quot;&gt;LANインターフェースの設定&lt;&#x2F;h3&gt;
&lt;p&gt;次にLAN側のネットワークをどうするか考えます。まず思いつくのは以下の3通りの方法です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WANインターフェースとLANインターフェースをブリッジ接続し、WANから流れてきたRAをLANにそのまま流す。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;WAN側で受け取ったグローバルなプリフィックスを、radvdというプログラムでLANに再広報する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;WAN側とは別のプライベートなIPv6アドレス(ユニークローカルアドレス)のプリフィックスをradvdでLANに広報する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ある程度の試行錯誤の末、上記のうち3の方法を採用することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;まず1の構成では、IPv6に関してはL3レベルでネットワークが分離されていないため、やはりセキュリティ設定に不安があります。まあ要するにLAN内に自分の知らないicmpv6のパケットが入ってくること自体が気持ち悪くて受け入れられないということです。&lt;&#x2F;p&gt;
&lt;p&gt;2の構成に関しては、以下に示すような技術課題があり、とりあえず設定はできるのですが、上手いルーティング設定とSLAAC自動設定が両立できません。 &lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WANとLANで同じプリフィックスを利用すると、ゲートウェイ上でのルーティング設定がめんどう。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&#x2F;64を&#x2F;65に分割してつかうとSLAACが機能しない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;WANで受け取ったプリフィックスを利用しLAN側のeth0にアドレスをアサインすると、ルーティングテーブルが以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2409:x:x:x::&#x2F;64 dev eth0.10 proto kernel metric 256 expires 2591991sec pref medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2409:x:x:x::&#x2F;64 dev eth0 proto kernel metric 256 pref medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この場合の問題点は、2409:x:x:x::&#x2F;64宛のパケットに対するルーティング設定が2行あり、eth0側にパケットを流したくても先にあるeth0.10側にパケットが流れてしまい、通信がうまくいきません。&lt;&#x2F;p&gt;
&lt;p&gt;2409:x:x:x::&#x2F;64向けのパケットはeth0側に流したいので、1行目を削除すれば良いのですが、この1行目の設定は、WAN側のSLAACの自動設定により自動追加されるものなので、しばらくするとまた追加されてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;この問題を回避するために2409:x:x:x::&#x2F;64で許されるアドレスレンジの内半分の2409:x:x:x:8000::&#x2F;65を、LAN内プリフィックスとして利用することを試みました。ルーティングルールでは長いプリフィックスの方が優先されるので、2409:x:x:x:8000::&#x2F;65宛のパケットを必ずeth0に流すことができるというもくろみです。&lt;&#x2F;p&gt;
&lt;p&gt;この方法でルーティング自体はうまくいくのですが、SLAACによる自動アドレス設定はプリフィックスが64であることが前提であるため、各マシンに手動でIPv6アドレスを設定する必要が出てきます。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、IPoEで配布されるグローバルプリフィックスが&#x2F;64である場合、ルーティングをきれいに動かすためにLANのプリフィックスをそれより長くすると、SLAACによるLAN内の自動アドレス設定ができなくなってしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;(ひかり電話契約がある場合には&#x2F;56のプレフィックスが配布されるらしいが、我が家はひかり電話では無いので&#x2F;64で。。。みんな&#x2F;56とか、せめて&#x2F;63で配布してくれれば良いのに。)&lt;&#x2F;p&gt;
&lt;p&gt;結局、このような理由から、「2. WAN側で受け取ったグローバルなプリフィックスを、radvdというプログラムでLANに再広報する。」という方法は断念しました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lance-hapuraibetonaadoresuwoli-yong&quot;&gt;LAN側はプライベートなアドレスを利用&lt;&#x2F;h3&gt;
&lt;p&gt;仕方が無いので、LAN内ではユニークローカルアドレスfd00::&#x2F;8を利用する第３の方法を用いることにしました。具体的にはradvdでfd00:0:0:x::&#x2F;64なプリフィックスを配布します。そうするとLAN内の様々なクライアントがSLAACにより自動的にアドレスを生成し、IPv6により通信できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;radvd.confの例&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;interface eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        AdvSendAdvert on;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        MinRtrAdvInterval 30;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        MaxRtrAdvInterval 100;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        prefix fd00:0:0:x::&#x2F;64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                AdvOnLink on;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                AdvAutonomous on;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                AdvRouterAddr off;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        RDNSS fd00:0:0:x::1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この構成だとLAN内はグローバルIPではなく、外に出る際にMASQUERADEすることが必要になります。NATが必要無いというIPv6のメリットの一つを損なってしまいますが仕方が無いです。&lt;&#x2F;p&gt;
&lt;p&gt;考えようによっては、IPv4で慣れ親しんだ構成でもあるので、管理は難しく無いというメリットもあります。&lt;&#x2F;p&gt;
&lt;p&gt;外部からのL3フィルタリング設定も、慣れ親しんだiptableと同様に行うことができます。&lt;&#x2F;p&gt;
&lt;p&gt;ip6tables設定。&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;ip6t.save (使用例 &#x2F;sbin&#x2F;ip6tables-restore &amp;lt; &#x2F;etc&#x2F;ip6t.save)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*nat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:PREROUTING ACCEPT [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:INPUT ACCEPT [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:POSTROUTING ACCEPT [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:OUTPUT ACCEPT [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A POSTROUTING -o eth0.10 -j MASQUERADE  # &amp;lt;- マスカレード設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;COMMIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*filter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:INPUT DROP [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:FORWARD DROP [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:OUTPUT ACCEPT [0:0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -s fd00:0:0:x::&#x2F;64 -i eth0 -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -p udp --dport 53 -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -p tcp --dport 53 -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A INPUT -p ipv6-icmp -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A FORWARD -d fd00:0:0:x::&#x2F;64 -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A FORWARD -s fd00:0:0:x::&#x2F;64 -i eth0 -o eth0.10 -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;COMMIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;wai-bu-karanoakusesu&quot;&gt;外部からのアクセス&lt;&#x2F;h3&gt;
&lt;p&gt;SLAACにより設定されるアドレスは、NICのMACアドレスから生成されるため決して覚えやすいものではありません。&quot;プリフィックス::1&quot;という分かり易いアドレスをマニュアルアサインすることで、外部からのアクセスが僅かながら容易になります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;ip add add 2409:x:x:x::1&#x2F;64  dev eth0.10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ただしtransixから払い出されるプリフィックスは固定であるという約束はありません。プリフックス変わった場合にはそれを検知してマニュアルアサインしたアドレスも付け直し、そしてDNSなどを更新する必要があるでしょう(これについてはいまのところ未実装です) 。&lt;&#x2F;p&gt;
&lt;p&gt;固定のプリフィックスを払い出してくれるISPがあったら乗り換えたいです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&quot;&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;-1&quot;&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;ipv4wodousuruka&quot;&gt;IPv4をどうするか&lt;&#x2F;h3&gt;
&lt;p&gt;IPv4に関してはPPPoE接続の固定IPの契約が元々あるので、そのまま利用することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;今回契約した、DS-Liteのサービスでは、IPv4 NATとIPIPトンネリングを利用したIPv4 over IPv6接続が利用できます。PPPoE接続をやめてこちらの経路を利用することでIPv4回線も空いている方を利用できることになりますが、グローバルなIPv4アドレスを他のユーザと共用する必要があるため、いまのところそれほど魅力を感じていません。&lt;&#x2F;p&gt;
&lt;p&gt;transixも固定IPのサービスがあるのでそれが利用可能かつ安価なISPがあれば考えたいです。(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mfeed.ad.jp&#x2F;transix&#x2F;staticip&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.mfeed.ad.jp&#x2F;transix&#x2F;staticip&#x2F;&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;(追記：後日、ポリシールーティングを使ってHTTP、HTTPSの通信のみDS-Liteを使うようにしました。→&lt;a href=&quot;&#x2F;2020&#x2F;05&#x2F;linuxds-lite.html&quot;&gt;こちら&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;別のVNEである、JPNEからも同様な、v6オプション固定IPサービスがあるようなので、こちらも安価なISPがあれば考えたいです。(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.jpne.co.jp&#x2F;service&#x2F;v6plus-static&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.jpne.co.jp&#x2F;service&#x2F;v6plus-static&#x2F;&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sonota-nozhu-yi-dian&quot;&gt;その他の注意点&lt;&#x2F;h3&gt;
&lt;p&gt;Linuxボックスでipv6のフォワーディングを有効にするとルーティング情報が消えてしまい、これに悩まされました。&lt;&#x2F;p&gt;
&lt;p&gt;forwarding=1でもRouter Advertisement（RA）を受信できるようにするために、以下が必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 1 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;all&#x2F;forwarding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo 2 &amp;gt; &#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv6&#x2F;conf&#x2F;eth0.10&#x2F;accept_ra&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;( &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;strugglers.net&#x2F;~andy&#x2F;blog&#x2F;2011&#x2F;09&#x2F;04&#x2F;linux-ipv6-router-advertisements-and-forwarding&#x2F;&quot;&gt;http:&#x2F;&#x2F;strugglers.net&#x2F;~andy&#x2F;blog&#x2F;2011&#x2F;09&#x2F;04&#x2F;linux-ipv6-router-advertisements-and-forwarding&#x2F;&lt;&#x2F;a&gt; )&lt;&#x2F;p&gt;
&lt;h3 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h3&gt;
&lt;p&gt;IPv6 IPoE + DS-Lite なプロバイダと契約し、LinuxルーターのIPv6設定を行いました。WAN側アドレスはSLAACにより自動的に設定されるものを用いました。LAN側アドレスはユニークローカルアドレスを利用し、MASQUERADEとフィルタリングの設定を行いました。&lt;&#x2F;p&gt;
&lt;p&gt;今後の課題としては、(1)64より短いプリフィックスが得られるなら、LAN内もグローバルアドレスを利用したい、(2)LinuxのルーティングがSLAACと両立できるようになったら、LAN内もグローバルアドレスを利用したい、(３)固定プリフィックスが利用できるISPがあれば乗り換えたい、(4)固定グローバルIPのIPv4 over IPv6が利用可能かつ安価なISPがあれば乗り換えたい、などがあります。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Keepalivedで作るMySQLフェイルオーバーシステム</title>
        <published>2015-12-22T00:00:00+00:00</published>
        <updated>2015-12-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/12/keepalivedmysql.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/12/keepalivedmysql.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/12/keepalivedmysql.html/">&lt;h2 id=&quot;1-hazimeni&quot;&gt;1. はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;この記事は&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;qiita.com&#x2F;advent-calendar&#x2F;2015&#x2F;mysql-casual&quot;&gt;MySQL Casual Advent Calendar 2015&lt;&#x2F;a&gt;の22日目のエントリです。&lt;&#x2F;p&gt;
&lt;p&gt;先日、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mysql-casual.connpass.com&#x2F;event&#x2F;22334&#x2F;&quot;&gt;MySQL Casual Talks&lt;&#x2F;a&gt;という勉強会で登壇してきました。その時の内容をまとめておきたいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;MySQLデータベースサーバに障害が起きた時、サービスを続けるには幾つかの方法があります。障害発生時にSlaveサーバーを手作業でMasterに昇格させる方法、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;dev.mysql.com&#x2F;downloads&#x2F;utilities&#x2F;&quot;&gt;MySQL Utilities&lt;&#x2F;a&gt;に含まれるmysqlfailoverというユーティリティーを利用する方法などです。&lt;&#x2F;p&gt;
&lt;p&gt;今回、Keepalivedというソフトウェアと、MySQLの双方向レプリケーションを使って、ほぼ無停止でフェイルオーバーする構成を試してみたので、それについてまとめておきたいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-sisutemugou-cheng&quot;&gt;2. システム構成&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2015&#x2F;12&#x2F;keepalivedmysql.html&#x2F;image&#x2F;Fig1.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;db1、db2という二つのサーバで、それぞれmysqldとkeepalivedを動かします。mysqldはお互いがMasterとなる双方向レプリケーションを行います。keepalivedはそれぞれのサーバで&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;mysql-casual-20151220&#x2F;blob&#x2F;mysql56&#x2F;files&#x2F;etc&#x2F;keepalived&#x2F;vrrp&#x2F;mysqlchk.sh&quot;&gt;mysqldのヘルスチェック&lt;&#x2F;a&gt;を行い、どちらかがVRRPのMasterもう一方がBackupの状態となり、MasterにVirtual IP(VIP)を付与します。上の図ではdb1が現在のVRRP Masterということになります。双方向レプリケーションを行う場合に同時に両方のサーバへの書き込みを許可すると、データの不整合や、レプリケーションの停止を引き起こしてしまうことが知られています。今回VRRPスレーブに誤って書き込みが行われないようにスレーブにreadonly=1のフラグを立てておきます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2015&#x2F;12&#x2F;keepalivedmysql.html&#x2F;image&#x2F;Fig2.png&quot; width=&quot;640&quot; height=&quot;400&quot;&gt;
&lt;p&gt;もしdb1のmysqldが停止ししkeepalivedのヘルスチェックに失敗した場合、db1のkeepalivedはFAULTステートに移行します。一方db2のkeepalivedはVRRP Masterステートに移行しVIPが付与され、クライアントからのアクセスはdb2に向かうようになります。db2のkeepalivedがMasterに昇格する際には、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;mysql-casual-20151220&#x2F;blob&#x2F;mysql56&#x2F;files&#x2F;etc&#x2F;keepalived&#x2F;vrrp&#x2F;master.sh#L15&quot;&gt;スクリプトによりreadonly=0となり書き込みが可能になるようにしています&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;この構成では、Keepalivedを使うことで迅速かつ安定的にフェイルオーバーが実行できること、あらかじめ双方向レプリケーションが行われているので障害発生時にCHANGE MASTER をする必要がなくシンプルであることがメリットだと考えられます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-vrrptutenani&quot;&gt;3. VRRPってなに？&lt;&#x2F;h2&gt;
&lt;p&gt;VRRP(Virtual Router Redundancy Protocol)は、もともと2台のルーターの冗長化のために作られたプロトコルで、RFCで規定されています。。下の図は、今回利用したKeepalived v1.2.13 が準拠している&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tools.ietf.org&#x2F;rfc&#x2F;rfc3768.txt&quot;&gt;VRRP version 2&lt;&#x2F;a&gt;の動きを説明するものです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2015&#x2F;12&#x2F;keepalivedmysql.html&#x2F;image&#x2F;Fig3.png&quot; width=&quot;640&quot; height=&quot;400&quot;&gt;
&lt;p&gt;VRRP v2では、プライオリティに基づいてMasterとBackupサーバーが決定され、MasterのみがVRRPアドバタイズパケットを予め定められた間隔、例えば１秒間隔で送信します。Masterからのアドバタイズパケットが一定期間途切れると、BackupサーバがMasterサーバに状態遷移します。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;herusutietuku&quot;&gt;ヘルスチェック&lt;&#x2F;h4&gt;
&lt;p&gt;KeepalivedのVRRPデーモンには、RFCで規定されたVRRPプロコルの機能に加え、おまけとしてヘルスチェック機能があります。これによりスクリプトでmysqldの死活を監視し、監視が失敗するとKeepalivedのステータスをFAULTに遷移させることができます。この場合プライオリティ=0のVRRPアドバタイズパケットが送信され、直ちにBackupサーバがMasterに昇格します。&lt;&#x2F;p&gt;
&lt;p&gt;以下の設定は、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;mysql-casual-20151220&#x2F;blob&#x2F;mysql56&#x2F;files&#x2F;etc&#x2F;keepalived&#x2F;vrrp&#x2F;vrrp.conf&quot;&gt;keepalivedの設定ファイル&lt;&#x2F;a&gt;の一部ですが１秒に一回ヘルスチェックスクリプト&quot;&#x2F;etc&#x2F;keepalived&#x2F;vrrp&#x2F;mysqlchk.sh&quot;を実行し、二回失敗したらFAULTステートにし、２回成功するとBACKUPかMASTERに戻しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; vrrp_script mysqlchk {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     script &amp;quot;&#x2F;etc&#x2F;keepalived&#x2F;vrrp&#x2F;mysqlchk.sh&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     interval 1                    ← 1秒ごとにチェック&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     fall 2                          ← 2回失敗したらFAULT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     rise 2                         ← 2回成功でBACKUP or MASTER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ヘルスチェックファイル&quot;mysqlchk.sh&quot;の内容は、今回は次のようになっていて、ソケット経由で、&quot;show variables like &#x27;server_id&#x27;;&quot;に応答できるかどうかを確認しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mysql -S $SOCK --connect-timeout=$TIMEOUT -e &amp;quot;show variables like &amp;#39;server_id&amp;#39;;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;vrrpnohueiruobashi-jian&quot;&gt;VRRPのフェイルオーバー時間&lt;&#x2F;h4&gt;
&lt;p&gt;障害時にVRRPのフェイルオーバーにかかる時間は、大まかに以下のふた通りに分けることができます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;mysqldのみ死んだ場合&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;keepalivedがFAULTステートになりpriority=0のVRRP Advertパケットを送信します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;これを受信したBACKUPステートにいるkeepalivedは直ちにMASTERに昇格します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;フェイルオーバーにかかる時間は、FAULTステート遷移に必要な2秒程度です。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバごと死んだ場合&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;元のサーバからのVRRPパケットが途絶え、BACKUPステートにいるkeepalivedがMASTERステートに昇格します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;BACKUPステートにいるkeepalivedが状態遷移を開始する時間はVRRPプロトコルで決まっており、(3 * Advertisement_Interval) + ( (256 - Priority) &#x2F; 256 )になります。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;VRRPアドバタイズパケットの間隔、すなわちAdvertisement_Intervalが1秒の場合は４秒程度でフェイルオーバーが完了します。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以上により、この仕組みを利用する場合、2秒または4秒程度でフェイルオーバーが完了することになり、かなり速いと言って良いのではないでしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-shuang-fang-xiang-repurikesiyonnozhu-yi-dian&quot;&gt;4. 双方向レプリケーションの注意点&lt;&#x2F;h2&gt;
&lt;p&gt;今回のシステム構成では、db1とdb2の間で双方向のレプリケーション構成にしています。この構成には落とし穴があるので、まず簡単にレプリケーションの仕組みをおさらいしておきたいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;次の図で、db1でコミットされたトランザクションはbinlogに記録されます。binlogに記録されたトランザクションは、ネットワークを介してdb2に送られIOスレッドによりrelaylogに書き込まれ、SQLスレッドによりテーブルスペースに順次コミッされていきます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blogger.googleusercontent.com&#x2F;img&#x2F;b&#x2F;R29vZ2xl&#x2F;AVvXsEhIkc-k6nMbEhTcZNQZEuw-j-eZ_4ST3qYbFahEqvMQdT49_-XFPJ9X_U-IpGIhBKlOyj2ppBYfKI4UNGKHXz7WERAqiJyZfbx3LdIM0suSZRcuac4PaCPy7Onh22d7YDDcMEvQzT81v3Y&#x2F;s1600&#x2F;Fig4.png&quot;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blogger.googleusercontent.com&#x2F;img&#x2F;b&#x2F;R29vZ2xl&#x2F;AVvXsEhWdasRPYsn7I1WjYeuFJ6RIKnE5U2-E2joHNPDysaxhCjRTTyDBhHbcV5yRNwfy_7PwER8Ap04VePBCFgRwHFZdEQNydHKOuwhYy3uHeyKexGgBZM6C1QjoMkBnXv3_ajX1qqokdQ6ai0&#x2F;s1600&#x2F;Fig11.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2015&#x2F;12&#x2F;keepalivedmysql.html&#x2F;image&#x2F;Fig11.png&quot; width=&quot;640&quot; height=&quot;400&quot;&gt;
&lt;p&gt;したがって、db1で完了したコミットはすぐにSlaveのテーブルスペースに書き込まれるわけではなく、有限時間の遅延が発生します。特にレプリケーションのSQLスレッドは、mysqld-5.6までは1スキーマに対して1スレッドでしか実行できないので、SQLスレッドによるテーブルスペースへのコミットが追いつかずrelaylogにデータが溜まっていく場合が、時々見られます。&lt;&#x2F;p&gt;
&lt;p&gt;レプリケーションが遅延している時に、VRRPのフェイルオーバーが起こると以下の図のような状態になります。relaylogに溜まっているデータはSQLスレッドにより順次コミットされていきますが、同時にクライアントからの書き込みが行われると、データに不整合が起こりレプリケーションが停止する場合があります。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blogger.googleusercontent.com&#x2F;img&#x2F;b&#x2F;R29vZ2xl&#x2F;AVvXsEjZUtMebWAzyXRO15xuHfnTpyH3aIpSTsng-k6BDcm1XYK8rikPNGhFWrjXS76N15i00Y9BSo2DUC20LcK6FHNPnAttqse6RofWTkqNDHI_uGDc-nmbrpVHzyRf5ohoYHu5sG7UxdhuCXQ&#x2F;s1600&#x2F;Fig6.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2015&#x2F;12&#x2F;keepalivedmysql.html&#x2F;image&#x2F;Fig12.png&quot; width=&quot;640&quot; height=&quot;400&quot;&gt;
&lt;p&gt;今回の構成ではこれを防ぐために、フェイルオーバー時にVIPがdb2に移った時、すぐに書き込み可能な状態にするのではなく、レプリケーションの遅延がなくなるのを待っててreadonly=0をセットするようにしています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; #!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; SOCK=&#x2F;var&#x2F;run&#x2F;mysqld&#x2F;mysqld.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; while true ; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mysql -S $SOCK -e &amp;quot;show slave status\G;&amp;quot;|egrep &amp;quot;Seconds_Behind_Master: 0|Seconds_Behind_Master: NULL&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; if [ &amp;quot;$?&amp;quot; = &amp;quot;0&amp;quot; ] ; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      echo Waiting until sql thread finish.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mysql -S $SOCK -e &amp;quot;set @@global.read_only=0;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;5-matome&quot;&gt;5. まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回、keepalivedのVRRP機能と、MySQLの双方向レプリケーションを組み合わせた、MySQLサーバの冗長化について試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;良いところ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;およそ4秒以内、ほぼ瞬時にフェイルオーバーする。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;フェイルオーバー時にレプリケーション関連のオペレーションが入らないので、シンプルである。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;課題&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;マルチマスターなので不整合に気をつける&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;repが遅いとなかなか昇格できない。MySQL5.7に期待。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>マイKVM環境を晒しておきます。My Jessie on Jessie KVM environment.</title>
        <published>2015-10-29T00:00:00+00:00</published>
        <updated>2015-10-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/kvmmy-jessie-on-jessie-kvm-environment.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/kvmmy-jessie-on-jessie-kvm-environment.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/kvmmy-jessie-on-jessie-kvm-environment.html/">&lt;p&gt;皆さん、こんにちは。もうすっかり秋ですね。&lt;&#x2F;p&gt;
&lt;p&gt;最近、寒暖差が激しいので、お体には気をつけてくださいね。&lt;&#x2F;p&gt;
&lt;p&gt;さてさて、本日は、弊社で使っているDebian Jessie用のKVM環境をご紹介します。&lt;&#x2F;p&gt;
&lt;p&gt;KVMとはKernel Virtual Machineの略で、Linuxのカーネルで実装された仮想マシンハイパーバイザーのことです。一般的には、ハイパーバイザー自体を指すよりも、それを用いた仮想マシンの方式のことを指す場合も多いかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;弊社ではKVMによる仮想環境を用い、各種サーバプログラム、WEBクラスターなどの検証を行っています。最近のLinuxディストリビューションでは、すでに簡単な操作で仮想マシンを立ち上げることが可能です。しかし、kvmが最初にバニラカーネルに組み込まれたlinux-2.6.20の頃から自家製スクリプトでkvm仮想マシンを利用しており、それが使い易く、興味を持ってくれる人もいるかもしれないのでここに公開する次第です。&lt;&#x2F;p&gt;
&lt;p&gt;仮想マシンの抽象化ライブラリであるlibvirtを介さずGUIなども無いので、比較的仕組みが理解しやすくカスタマイズが簡単であることがメリットかと考えています。カーネルの最新機能や最新のqemuに追従することもたやすくできます。&lt;&#x2F;p&gt;
&lt;p&gt;それでですね、ものはここにおいてあります。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;kvm-setup-jessie&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ktaka-ccmp&#x2F;kvm-setup-jessie&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Debian jessieで以下のように、&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sudo apt-get install make aptitude git -y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; git clone git@github.com:ktaka-ccmp&#x2F;kvm-setup-jessie.git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sudo make all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;gitとmakeとaptitudeをaptでインストール&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;githubからツールをクローン&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;make allする&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;を行えばオッケーです。busyboxとkernelのコンパイル時にmenuconfig画面が表示されますが、通常はそのままExitしてください。&lt;&#x2F;p&gt;
&lt;p&gt;何か思うところがあってカスタマイズしたい場合は、そこでカスタマイズを行ってください。&lt;&#x2F;p&gt;
&lt;p&gt;仮想マシンの実行は、&#x2F;kvm&#x2F;sbin&#x2F;kvmスクリプトで行います。中身を見てもらえばわかりますが、このスクリプトでやっていることは、qemuコマンドの実行と、unix domainソケットを通してのqemuプロセスの制御です。&lt;&#x2F;p&gt;
&lt;p&gt;ではまず、v001という仮想マシンを起動してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm create v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; booting v001 ....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;v001が生きているかどうかは、次のように確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm chk v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; QEMU 2.4.0.1 monitor - type &amp;#39;help&amp;#39; for more information&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu) info status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; VM status: running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次にv002を起動し、状態を確認してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm create v002&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; booting v002 ....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm chk v002&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; QEMU 2.4.0.1 monitor - type &amp;#39;help&amp;#39; for more information&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu) info status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; VM status: running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;稼働中の仮想マシンの一覧は、以下のように確認できます。conのカラムはコンソールソケット、monのカラムはモニターソケット、imgのカラムはVMのイメージファイルの状態を表しています。v001の行を見るとv001 o o uとなっていますが、これはコンソール、モニターの両ソケットが接続可能で、イメージファイルが使用中(VMが稼働中)であることを表しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; id   con   mon   img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; test  -    -    -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v001  o    o    u&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v002  o    o    u&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;今度は、v001のコンソールに接続してみます。コンソールに接続するとログインプロンプトが表示されるのでroot&#x2F;rootでログインします。rootのパスワードはMakefileにベタ書きしてあり、イメージtemplate作成時に設定されます。コンソール接続を終了するには&quot;Ctrl+]&quot;をタイプします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm con v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Debian GNU&#x2F;Linux 8 v001 ttyS0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v001 login: root&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Password:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Linux v001 4.2.4-64kvmg01 #1 SMP Wed Oct 28 03:50:51 UTC 2015 x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; The programs included with the Debian GNU&#x2F;Linux system are free software;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; the exact distribution terms for each program are described in the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; individual files in &#x2F;usr&#x2F;share&#x2F;doc&#x2F;*&#x2F;copyright.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Debian GNU&#x2F;Linux comes with ABSOLUTELY NO WARRANTY, to the extent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; permitted by applicable law.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@v001:~# logout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Debian GNU&#x2F;Linux 8 v001 ttyS0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v001 login:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;テンプレートイメージ作成時には、&#x2F;root&#x2F;.ssh&#x2F;authorized_keysもコピーしていますので、ホストのマシンと同じ鍵でsshログインすることが可能です。&lt;&#x2F;p&gt;
&lt;p&gt;v001のIPアドレスはinitrdの中で172.16.1.1を決め打ちで設定しています。v002の場合は172.16.1.2、v250の場合は172.16.1.250が割り当てられ、v250を上限にしてあります。&lt;&#x2F;p&gt;
&lt;p&gt;これらのホスト名、IPは、セットアップ時にホストの&#x2F;etc&#x2F;hostsに追記してあります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# ssh v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; The programs included with the Debian GNU&#x2F;Linux system are free software;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; the exact distribution terms for each program are described in the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; individual files in &#x2F;usr&#x2F;share&#x2F;doc&#x2F;*&#x2F;copyright.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Debian GNU&#x2F;Linux comes with ABSOLUTELY NO WARRANTY, to the extent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; permitted by applicable law.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Last login: Thu Oct 29 16:42:31 2015 from 172.16.1.254&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@v001:~#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ゲストマシンからは、ホストマシンのNATを介して外部のネットワークと通信が可能です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@v001:~# ping yahoo.jp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; PING yahoo.jp (183.79.227.111) 56(84) bytes of data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from yjpn110.mobile.vip.ogk.yahoo.co.jp (183.79.227.111): icmp_seq=1 ttl=54 time=13.2 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from yjpn110.mobile.vip.ogk.yahoo.co.jp (183.79.227.111): icmp_seq=2 ttl=54 time=13.3 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from yjpn110.mobile.vip.ogk.yahoo.co.jp (183.79.227.111): icmp_seq=3 ttl=54 time=13.9 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ^C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; --- yahoo.jp ping statistics ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3 packets transmitted, 3 received, 0% packet loss, time 2001ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; rtt min&#x2F;avg&#x2F;max&#x2F;mdev = 13.224&#x2F;13.515&#x2F;13.986&#x2F;0.349 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;また、同じホスト上の仮想マシン間で通信することも可能です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@v001:~# ping v002&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; PING v002 (172.16.1.2) 56(84) bytes of data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from v002 (172.16.1.2): icmp_seq=1 ttl=64 time=1.33 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from v002 (172.16.1.2): icmp_seq=2 ttl=64 time=1.89 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64 bytes from v002 (172.16.1.2): icmp_seq=3 ttl=64 time=5.51 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ^C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; --- v002 ping statistics ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3 packets transmitted, 3 received, 0% packet loss, time 2003ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; rtt min&#x2F;avg&#x2F;max&#x2F;mdev = 1.331&#x2F;2.914&#x2F;5.519&#x2F;1.856 ms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;別ホストからは、直接仮想マシンにアクセスできないようになっていますので、別ホスト上の仮想マシンとは通信できません。もしそうしたい場合は、ブリッジとvlanの設定を工夫することで、通信可能になるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;仮想マシンを停止したいときは、仮想マシンにログインしpoweroffを実行するか、以下のようにshutdownコマンドを発行します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm shutdown v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; QEMU 2.4.0.1 monitor - type &amp;#39;help&amp;#39; for more information&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu) system_powerdown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (qemu)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm chk v001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2015&#x2F;10&#x2F;29 17:04:52 socat[17586] E connect(5, AF=1 &amp;quot;&#x2F;kvm&#x2F;monitor&#x2F;v001.sock&amp;quot;, 24): Connection refused&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;kvm listコマンドで見ると、停止しているv001は以下のように見えます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# kvm list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; id   con   mon   img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; test  -    -    -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v001  -    -    -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; v002  o    o    u&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;v001のイメージを完全に消したいときは、仮想マシンが停止した状態で、&#x2F;kvm&#x2F;data&#x2F;v001.imgを消してください。&lt;&#x2F;p&gt;
&lt;p&gt;だいたい使い方は以上になります。&lt;&#x2F;p&gt;
&lt;p&gt;どうぞ、よろしくお願いいたします。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Lessons of Steve Jobs: Guy Kawasaki at TEDxUCSD の要点</title>
        <published>2015-10-18T00:00:00+00:00</published>
        <updated>2015-10-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/lessons-of-steve-jobs-guy-kawasaki-at.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/lessons-of-steve-jobs-guy-kawasaki-at.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/lessons-of-steve-jobs-guy-kawasaki-at.html/">&lt;p&gt;Guy Kawasakiのもう一つのビデオ&quot;Lessons of Steve Jobs&quot; 2013年UCSDでのTEDx です。&lt;&#x2F;p&gt;
&lt;p&gt;May he rest in peace, but may his influence continue to inspire us.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Experts are clueless. Listen to your heart.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Customer cannot usually tell you what they want.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Get the next curve.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Big challenges beget the best work.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Design counts.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use big graphics and big fonts.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Changing your mind is sign of intelligence.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Value not equal to price.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A players hire A+ players.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Real CEOs demo.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Real entrepreneurs ship.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Marketing = unique value.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Bonus: Some things need to be believed to be seen.&lt;&#x2F;p&gt;
&lt;p&gt;I can tell you right now. In heaven Steve Jobs is telling God what to do.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>The art of innovation | Guy Kawasaki | TEDxBerkeley の要点メモ</title>
        <published>2015-10-18T00:00:00+00:00</published>
        <updated>2015-10-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/the-art-of-innovation-guy-kawasaki.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/the-art-of-innovation-guy-kawasaki.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/the-art-of-innovation-guy-kawasaki.html/">&lt;p&gt;こんにちは、今日はいい天気にもかかわらず、自宅に引きこもってSNS眺めたり、Youtube見てました。本当はやらなきゃいけないお仕事があったんですが ^^;)&lt;&#x2F;p&gt;
&lt;p&gt;前からちょくちょく見ていたGuy KawasakiのTalkの一つの「The art of innovation(イノベーションの技術)」分用メモです。書き出しておかないと内容忘れて何度も見る羽目になってしまうので。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Make meaning as opposed to make money. If you start off with the sole desire to make money, you won’t make money, you won’t make meaning, you won’t change the world, and you’ll probably fail. お金よりもそれをやる意味が大事。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make Mantra. Two or three explanation why your meaning should exist. Nike: authentic athletic performance, Fedex: Peace of mind, Wendy: (should be) Healthy fast food.　その意味が存在する必要を、2、３、４語のマントラにしておくと良い。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Jump to the next curve. Great innovation occurs when you get to the next curve. 10%の進歩ではなく次のカーブに乗ることが大事。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Roll the DICEE. Deep, Intelligent, Complete, Empowering, Elegant　深い進歩、賢さ（マスタングは鍵ごとに最高速がプログラムされいる）、完全さ（レクサス）、可能性を与えるもの（Macbook Air）、エレガントさなどの要素が必要。&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;alvinalexander.com&#x2F;best-practices&#x2F;guy-kawasaki-dicee-acronym&quot;&gt;参考&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Don’t worry be crappy. If you waited for perfect world, you would never ship. 完璧さを求めたらいつまでたっても出荷できない。革新的なプロダクトは多少のクラッピネスを恐れずにまず出荷することが大事。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Let 100 flowers blossom. One of the reasons why I believe in God is there is no other explanations for Apple’s continued survival than the existence of God. When the customer use your product if they say it’s the desktop publishing machine, haleluya, declare the victory, it is now a desktop publishing machine. Positioning branding ultimately comes down to what the customer decides, not to what you decides. マックはワープロ、スプレッドシート、データベースではダメだったけど、DTPマシンとして成功した。ポジショニング、ブランディングは究極的には、顧客が決めるものである。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Polarize people.The great product polarize people. Don’t be afraid of polarizing people. 偉大なプロダクトは時に敵を作るが恐れてはいけない。ただし、敵を作れと言っているのではない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Churn, baby churn. As soon as you ship the product, you need to start listening people and keep evolving the product. 出荷するまではエキスパートの声を無視しなければいけないが、出荷されたら直ちにユーザーの声に耳を傾け、商品を進化させ続けなければならない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Niche yourself. ユニーク、価値の2x2マトリックス、右上を取らなければいけない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Perfect your pitch. Customize your introduction. 10 20 30 rules of presentation. 10 slides 20 minutes 30 point fonts. ピッチのTips。イントロを聴衆に合わせてカスタマイズ。10スライド、20分のトーク、30ポイントフォント。聴衆年齢の半分のフォントサイズ。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Don’t let the bozos grind you down. “I think there is a world of market for maybe five computers. Thomas Watson, IBM, 1943” 成功したbozo達の言葉に騙されるな。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>debian jessieをdebootstrapでインストールした時のメモ</title>
        <published>2015-10-14T00:00:00+00:00</published>
        <updated>2015-10-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/debian-jessiedebootstrap.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/debian-jessiedebootstrap.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/debian-jessiedebootstrap.html/">&lt;p&gt;こんばんは。&lt;&#x2F;p&gt;
&lt;p&gt;ブログを書くのは苦手だけど、なんでもいいから書いてみようシリーズです。&lt;&#x2F;p&gt;
&lt;p&gt;会社ではディスクレスのネットブート環境を作ってあって、新しいOSをインストールする時には、まずディスクレスでOSを立ち上げそのOS上でdebootstrapやyum groupinstallなどを使ってファイルシステムの中身を作成することが多いです。あるいはディスクレスでブートして、あらかじめ作成しておいた標準システムをネットワーク越しrsyncやddでコピーしたりすることもあります。&lt;&#x2F;p&gt;
&lt;p&gt;このようにすることで、毎回ブレの少ない、あるいは全くブレのないイメージを作成することができ、非常に便利です。&lt;&#x2F;p&gt;
&lt;p&gt;今回は、ネットブートした後にDebian jessieをdebootstrapした時のメモです。&lt;&#x2F;p&gt;
&lt;p&gt;そして想定読者は、未来の自分です。（最近前にやったことをすぐに忘れてしまうので^^;）&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ネットブートしたOS上でやること。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;apt.h.ccmp.jp:3142がMIRROR元のURLに挟んであるのは、apt-cacher-ngを間に挟んでaptの転送量を節約するためです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; parted &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mkfs.ext4 &#x2F;dev&#x2F;sda1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mkswap &#x2F;dev&#x2F;sda2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mount &#x2F;dev&#x2F;sda1 &#x2F;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; apt-get install debootstrap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; time debootstrap --include=openssh-server,openssh-client,rsync,pciutils,tcpdump,strace,libpam-systemd,ntpdate,openntpd jessie &#x2F;mnt&#x2F; http:&#x2F;&#x2F;apt.h.ccmp.jp:3142&#x2F;ftp.jp.debian.org&#x2F;debian&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mount -t proc none &#x2F;mnt&#x2F;proc&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mount -t devtmpfs none &#x2F;mnt&#x2F;dev&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mount -t sysfs none &#x2F;mnt&#x2F;sys&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; rsync -av  ~&#x2F;.ssh&#x2F; &#x2F;mnt&#x2F;root&#x2F;.ssh&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; vi &#x2F;mnt&#x2F;etc&#x2F;network&#x2F;interfaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; vi &#x2F;mnt&#x2F;etc&#x2F;fstab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; echo &amp;quot;root:root&amp;quot; | chpasswd --root &#x2F;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; echo &amp;quot;Asia&#x2F;Tokyo&amp;quot; &amp;gt;  &#x2F;mnt&#x2F;etc&#x2F;timezone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; cp &#x2F;mnt&#x2F;usr&#x2F;share&#x2F;zoneinfo&#x2F;Japan &#x2F;mnt&#x2F;etc&#x2F;localtime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; chroot &#x2F;mnt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;etc&#x2F;fstabの中身&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &#x2F;dev&#x2F;sda1       &#x2F;       ext4   defaults       1   1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &#x2F;dev&#x2F;sda2       swap     swap   defaults       0   0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;etc&#x2F;network&#x2F;interfacesの中身&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auto lo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface lo inet loopback&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auto eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#iface eth0 inet dhcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface eth0 inet static&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        address         192.168.60.31&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        network         192.168.60.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        broadcast       192.168.63.255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        netmask         255.255.252.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        gateway         192.168.60.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source-directory &#x2F;etc&#x2F;network&#x2F;interfaces.d&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;chroot後にイメージ内でやること&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; apt-cache search linux-image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; apt-get install linux-image-3.16.0-4-amd64  grub-pc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; apt-get clean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; grub-install &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; update-grub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以上で、jessieのミニマム環境がインストールできます。
リブートしてちゃんと立ち上がればOKです。&lt;&#x2F;p&gt;
&lt;p&gt;そんなこんなで、立ち上がったOSの容量は。。。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; root@jessie64:~# df -h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Filesystem   Size Used Avail Use% Mounted on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &#x2F;dev&#x2F;root       107G  585M  101G   1% &#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;うーん、こんなもんかなー。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>pppoe接続のインターフェース名を変更する　How to rename pppoe interface name.</title>
        <published>2015-10-14T00:00:00+00:00</published>
        <updated>2015-10-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/pppoehow-to-rename-pppoe-interface-name.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/pppoehow-to-rename-pppoe-interface-name.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/pppoehow-to-rename-pppoe-interface-name.html/">&lt;p&gt;フレッツ回線などで、linuxルーターからpppoeセッションを張る場合、インターフェース名がppp0、ppp1などとなり、どのプロバイダへの接続なのか判別しづらく不便に感じることがあります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; # ip add show dev ppp0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 8: ppp0:  mtu 1454 qdisc pfifo_fast state UNKNOWN qlen 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   link&#x2F;ppp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   inet x.x.x.x peer x.x.x.x&#x2F;32 scope global ppp0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     valid_lft forever preferred_lft forever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ここで、ppp0の部分を任意の名前、例えば接続先のプロバイダ名などにしておけば便利でしょう。Debian Wheezyの場合は次のようにしてやれば、そういうことが可能です。&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;network&#x2F;interfaces&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; auto irevo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; iface irevo inet ppp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    provider irevo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;etc&#x2F;ppp&#x2F;peers&#x2F;irevo&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; noipdefault&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; hide-password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; lcp-echo-interval 20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; lcp-echo-failure 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; connect &#x2F;bin&#x2F;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; noauth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; persist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mtu 1492&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; noaccomp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; default-asyncmap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; linkname &amp;quot;irevo&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; plugin rp-pppoe.so eth0.10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; user &amp;quot;xxxxx@i-revonet.jp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;etc&#x2F;ppp&#x2F;ip-up.d&#x2F;02ifrename&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; #!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ifrename(){&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; if [ &amp;quot;$LINKNAME&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ip link set $IFNAME down&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ip link set $IFNAME name $LINKNAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ip link set $LINKNAME up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; if [ &amp;quot;$IFNAME&amp;quot; == &amp;quot;$(&#x2F;sbin&#x2F;ip route |grep default | cut -f 3 -d &amp;quot; &amp;quot;)&amp;quot; ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ifrename&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;sbin&#x2F;ip route add default dev $LINKNAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ifrename&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;試してみると確かにインターフェース名がirevoになっていることがわかりました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; # ip add show dev irevo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 5: irevo:  mtu 1454 qdisc pfifo_fast state UNKNOWN qlen 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   link&#x2F;ppp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   inet x.x.x.x peer x.x.x.x&#x2F;32 scope global irevo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     valid_lft forever preferred_lft forever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Debian Jessie以降ではpppdに以下のページの修正が入っていて、上記の&#x2F;etc&#x2F;ppp&#x2F;peers&#x2F;irevoで「linkname &quot;irevo&quot;」とあるところを「ifname &quot;irevo&quot;」&lt;&#x2F;p&gt;
&lt;p&gt;などに変更することで、インターフェースの名前を任意に設定することができるそうです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bugs.debian.org&#x2F;cgi-bin&#x2F;bugreport.cgi?bug=458646&quot;&gt;https:&#x2F;&#x2F;bugs.debian.org&#x2F;cgi-bin&#x2F;bugreport.cgi?bug=458646&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;おそらく、こちらの方がpppdが知っている名前を変えずに済み問題が少いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;早く、ルーターのOSをDebian jessieにしようと思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>デスクトップパソコン新調</title>
        <published>2015-10-03T00:00:00+00:00</published>
        <updated>2015-10-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2015/10/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2015/10/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2015/10/blog-post.html/">&lt;p&gt;みなさん、こんにちは。そろそろブログを書かなきゃなと思いつつ10ヶ月以上もブログ更新していないことに気づきました。もう何でもいいから書いてみようと思います(笑)&lt;&#x2F;p&gt;
&lt;p&gt;先日、会社で使っているデスクトップパソコンを新しくしました。パソコンのモデルは、Intelの&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.co.jp&#x2F;content&#x2F;www&#x2F;jp&#x2F;ja&#x2F;nuc&#x2F;nuc-kit-dn2820fykh.html&quot;&gt;NUC BOXDN2820FYKH0&lt;&#x2F;a&gt;というやつで、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ark.intel.com&#x2F;ja&#x2F;products&#x2F;79052&#x2F;Intel-Celeron-Processor-N2820-1M-Cache-up-to-2_39-GHz&quot;&gt;Celeron N2820&lt;&#x2F;a&gt;というデュアルコアHTなCPUが乗っています。このCPUはTDPがわずか7.5Wととても低消費電力で、電気代が安く済むので、各拠点のルーターとしても重宝しています。今回はルータ用に買ったあまりをデスクトップ用に転用しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2015&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;14438574284641.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;主なインターフェースは、HDMI、1G LAN(Realtek)、usb 2.0 x2 、usb 3.0 x 1などです。他にwifi&#x2F;bluetooth用のチップも内蔵しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2015&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;14438574196490.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OSはもちろんLinux。今回はDebian jessieをインストールしました。&lt;&#x2F;p&gt;
&lt;p&gt;最近のLinuxはインストールするだけで、特に苦労もせずXや日本語入力環境が使えるので、非常に助かります。(Macイラねんじゃね？とはいえMacbook Air愛用しておりますが…)&lt;&#x2F;p&gt;
&lt;p&gt;備忘録 chrome音が出ない件。&lt;&#x2F;p&gt;
&lt;p&gt;以下のコマンドで見ると、HDA Intel PCHというデバイスが搭載されており、ALC283とHDMIの２つの出力デバイスがある。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@jessie:~$ aplay -l&lt;&#x2F;p&gt;
&lt;p&gt;**** List of PLAYBACK Hardware Devices ****&lt;&#x2F;p&gt;
&lt;p&gt;card 0: PCH [HDA Intel PCH], device 0: ALC283 Analog [ALC283 Analog]&lt;&#x2F;p&gt;
&lt;p&gt;  Subdevices: 1&#x2F;1&lt;&#x2F;p&gt;
&lt;p&gt;  Subdevice #0: subdevice #0&lt;&#x2F;p&gt;
&lt;p&gt;card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]&lt;&#x2F;p&gt;
&lt;p&gt;  Subdevices: 1&#x2F;1&lt;&#x2F;p&gt;
&lt;p&gt;  Subdevice #0: subdevice #0&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;次のコマンドで、音が出るかどうか試してみるとちゃんと出る。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;aplay -D plughw:0,3 &#x2F;usr&#x2F;share&#x2F;sounds&#x2F;alsa&#x2F;Front_Center.wav &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;次のファイルを書き換えXを再起動したところ、chromeでyoutubeなどの音声が聞こえるようになりました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x2F;etc&#x2F;asound.conf&lt;&#x2F;p&gt;
&lt;p&gt;pcm.!default { type hw; card 0 ; device 3; }&lt;&#x2F;p&gt;
&lt;p&gt;ctl.!default { type hw; card 0 ; device 3; }&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;以上、オチもまとめもないんですけど、&lt;&#x2F;p&gt;
&lt;p&gt;最近のLinuxはデスクトップとしても簡単に使えるので、皆さん使ってみましょう！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>今日の逸品</title>
        <published>2014-11-03T00:00:00+00:00</published>
        <updated>2014-11-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2014/11/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2014/11/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2014/11/blog-post.html/">&lt;p&gt;こんにちは。三連休の最終日、お天気は快晴で絶好の行楽日和となりましたね！&lt;&#x2F;p&gt;
&lt;p&gt;本当はどこかに出かけるか、外で思いっきりスポーツでもしたいところですが、某代理店さんからお借りしている最新の超高性能デバイスを本日中に返送しないといけないので、休日返上でブログを書きながらレポートしたいと思います(^^;)&lt;&#x2F;p&gt;
&lt;p&gt;まずは、写真をと。。。。じゃじゃーん！今日の逸品はこちらです！&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;11&#x2F;blog-post.html&#x2F;image&#x2F;IMG_20141028_000418_mini.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;IntelのPCI express typeのSSD DC P3700です。大きなヒートシンクに囲われていて、かっこいいですね！まあ、どんだけ熱くなるんだってお話もありますが。。。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;11&#x2F;blog-post.html&#x2F;image&#x2F;IMG_20141028_000931_mini.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;裏面も、NANDチップがびっしりです。どんだけ大容量なんだ！&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;11&#x2F;blog-post.html&#x2F;image&#x2F;IMG_20141028_001036.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;どうやら1.6TBのようです！！&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;11&#x2F;blog-post.html&#x2F;image&#x2F;IMG_20141028_001253.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;こんな風に、サーバのPCIeスロットに装着します。ちょっと、見えづらいかも知れませんが、この1Uサイズのサーバは、PCIeスロットが二段になっていて、上段がP3700、下段がLSI RAIDカードとなっています。&lt;&#x2F;p&gt;
&lt;p&gt;インテル® Solid-State Drive DC P3700 シリーズのカタログスペックは、こんな感じです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;容量 &lt;&#x2F;th&gt;&lt;th&gt;Sequencial Read&#x2F;Write  [MB&#x2F;s]&lt;&#x2F;th&gt;&lt;th&gt;4KB Random Read &#x2F; Write [IOPS]&lt;&#x2F;th&gt;&lt;th&gt;8KB Random Read &#x2F; Write [IOPS]&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;400 GB&lt;&#x2F;td&gt;&lt;td&gt;2,700 &#x2F; 1,080&lt;&#x2F;td&gt;&lt;td&gt;450,000 &#x2F; 75,000&lt;&#x2F;td&gt;&lt;td&gt;275,000 &#x2F; 32,000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;800 GB&lt;&#x2F;td&gt;&lt;td&gt;2,800 &#x2F; 1,900&lt;&#x2F;td&gt;&lt;td&gt;460,000 &#x2F; 90,000&lt;&#x2F;td&gt;&lt;td&gt;285,000 &#x2F; 45,000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1.6 TB&lt;&#x2F;td&gt;&lt;td&gt;2,800 &#x2F; 1,900&lt;&#x2F;td&gt;&lt;td&gt;450,000 &#x2F; 150,000&lt;&#x2F;td&gt;&lt;td&gt;290,000 &#x2F; 75,000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2.0 TB&lt;&#x2F;td&gt;&lt;td&gt;2,800 &#x2F; 2,000&lt;&#x2F;td&gt;&lt;td&gt;450,000 &#x2F; 175,000&lt;&#x2F;td&gt;&lt;td&gt;295,000 &#x2F; 90,000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;( &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.co.jp&#x2F;content&#x2F;www&#x2F;jp&#x2F;ja&#x2F;solid-state-drives&#x2F;intel-ssd-dc-family-for-pcie.html&quot;&gt;http:&#x2F;&#x2F;www.intel.co.jp&#x2F;content&#x2F;www&#x2F;jp&#x2F;ja&#x2F;solid-state-drives&#x2F;intel-ssd-dc-family-for-pcie.html&lt;&#x2F;a&gt; こちらのページより抜粋 )&lt;&#x2F;p&gt;
&lt;p&gt;シーケンシャルのリード&#x2F;ライトが2.8GB&#x2F;s、1.9GB&#x2F;s、4KBのランダムリード&#x2F;ライトが45万IOPS、15万IOPS　！！&lt;&#x2F;p&gt;
&lt;p&gt;一気に眠気が吹き飛びます！！&lt;&#x2F;p&gt;
&lt;p&gt;ちなみに、7200rpmのSATA HDDの場合は、ざっくりとシーケンシャル100MB、ランダム100IOPS程度ですので、どれだけ高性能かおわかりいただけるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;ライバルは、もしかしてこれ？&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;11&#x2F;blog-post.html&#x2F;image&#x2F;IMG_2038.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;使ってみたいですよね？それでは使ってみましょう。このカードは、PCIe SSDの新しい規格NVMe (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;NVM_Express&quot;&gt;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;NVM_Express&lt;&#x2F;a&gt;)に対応していますので、Linuxカーネルでnvmeドライバがロードされている必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;バニラカーネルをコンパイルする際には、CONFIG_BLK_DEV_NVME=m　などとなるようにします。&lt;&#x2F;p&gt;
&lt;p&gt;うまく認識されると、&#x2F;dev&#x2F;nvmexxxとして、見えるようになります。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# fdisk  -l &#x2F;dev&#x2F;nvme0n1&lt;&#x2F;p&gt;
&lt;p&gt;Disk &#x2F;dev&#x2F;nvme0n1: 1600.3 GB, 1600321314816 bytes&lt;&#x2F;p&gt;
&lt;p&gt;64 heads, 32 sectors&#x2F;track, 1526185 cylinders, total 3125627568 sectors&lt;&#x2F;p&gt;
&lt;p&gt;Units = sectors of 1 * 512 = 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;Sector size (logical&#x2F;physical): 512 bytes &#x2F; 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;I&#x2F;O size (minimum&#x2F;optimal): 512 bytes &#x2F; 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;Disk identifier: 0xc55b79ff&lt;&#x2F;p&gt;
&lt;p&gt;        Device Boot      Start         End      Blocks   Id  System&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;fdiskでパーティション作成します。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# fdisk &#x2F;dev&#x2F;nvme0n1&lt;&#x2F;p&gt;
&lt;p&gt;Command (m for help): n&lt;&#x2F;p&gt;
&lt;p&gt;Partition type:&lt;&#x2F;p&gt;
&lt;p&gt;   p   primary (0 primary, 0 extended, 4 free)&lt;&#x2F;p&gt;
&lt;p&gt;   e   extended&lt;&#x2F;p&gt;
&lt;p&gt;Select (default p): p&lt;&#x2F;p&gt;
&lt;p&gt;Partition number (1-4, default 1): 1&lt;&#x2F;p&gt;
&lt;p&gt;First sector (2048-3125627567, default 2048):&lt;&#x2F;p&gt;
&lt;p&gt;Using default value 2048&lt;&#x2F;p&gt;
&lt;p&gt;Last sector, +sectors or +size{K,M,G} (2048-3125627567, default 3125627567):&lt;&#x2F;p&gt;
&lt;p&gt;Using default value 3125627567&lt;&#x2F;p&gt;
&lt;p&gt;Command (m for help): p&lt;&#x2F;p&gt;
&lt;p&gt;Disk &#x2F;dev&#x2F;nvme0n1: 1600.3 GB, 1600321314816 bytes&lt;&#x2F;p&gt;
&lt;p&gt;64 heads, 32 sectors&#x2F;track, 1526185 cylinders, total 3125627568 sectors&lt;&#x2F;p&gt;
&lt;p&gt;Units = sectors of 1 * 512 = 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;Sector size (logical&#x2F;physical): 512 bytes &#x2F; 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;I&#x2F;O size (minimum&#x2F;optimal): 512 bytes &#x2F; 512 bytes&lt;&#x2F;p&gt;
&lt;p&gt;Disk identifier: 0xc55b79ff&lt;&#x2F;p&gt;
&lt;p&gt;        Device Boot      Start         End      Blocks   Id  System&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;dev&#x2F;nvme0n1p1            2048  3125627567  1562812760   83  Linux&lt;&#x2F;p&gt;
&lt;p&gt;Command (m for help): w&lt;&#x2F;p&gt;
&lt;p&gt;The partition table has been altered!&lt;&#x2F;p&gt;
&lt;p&gt;Calling ioctl() to re-read partition table.&lt;&#x2F;p&gt;
&lt;p&gt;Syncing disks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ファイルシステム作ります。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# time mkfs.ext4 &#x2F;dev&#x2F;nvme0n1p1&lt;&#x2F;p&gt;
&lt;p&gt;mke2fs 1.42.5 (29-Jul-2012)&lt;&#x2F;p&gt;
&lt;p&gt;Discarding device blocks: done                          &lt;&#x2F;p&gt;
&lt;p&gt;Filesystem label=&lt;&#x2F;p&gt;
&lt;p&gt;OS type: Linux&lt;&#x2F;p&gt;
&lt;p&gt;Block size=4096 (log=2)&lt;&#x2F;p&gt;
&lt;p&gt;Fragment size=4096 (log=2)&lt;&#x2F;p&gt;
&lt;p&gt;Stride=0 blocks, Stripe width=0 blocks&lt;&#x2F;p&gt;
&lt;p&gt;97681408 inodes, 390703190 blocks&lt;&#x2F;p&gt;
&lt;p&gt;19535159 blocks (5.00%) reserved for the super user&lt;&#x2F;p&gt;
&lt;p&gt;First data block=0&lt;&#x2F;p&gt;
&lt;p&gt;Maximum filesystem blocks=4294967296&lt;&#x2F;p&gt;
&lt;p&gt;11924 block groups&lt;&#x2F;p&gt;
&lt;p&gt;32768 blocks per group, 32768 fragments per group&lt;&#x2F;p&gt;
&lt;p&gt;8192 inodes per group&lt;&#x2F;p&gt;
&lt;p&gt;Superblock backups stored on blocks:&lt;&#x2F;p&gt;
&lt;p&gt;        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,&lt;&#x2F;p&gt;
&lt;p&gt;        4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,&lt;&#x2F;p&gt;
&lt;p&gt;        102400000, 214990848&lt;&#x2F;p&gt;
&lt;p&gt;Allocating group tables: done                          &lt;&#x2F;p&gt;
&lt;p&gt;Writing inode tables: done                          &lt;&#x2F;p&gt;
&lt;p&gt;Creating journal (32768 blocks): done&lt;&#x2F;p&gt;
&lt;p&gt;Writing superblocks and filesystem accounting information: done     &lt;&#x2F;p&gt;
&lt;p&gt;real    0m13.304s&lt;&#x2F;p&gt;
&lt;p&gt;user    0m2.230s&lt;&#x2F;p&gt;
&lt;p&gt;sys     0m0.440s&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;マウントします。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# mkdir &#x2F;mnt&#x2F;p3700&lt;&#x2F;p&gt;
&lt;p&gt;wheezy64:~# mount &#x2F;dev&#x2F;nvme0n1p1 &#x2F;mnt&#x2F;p3700&#x2F; &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# df -h&lt;&#x2F;p&gt;
&lt;p&gt;Filesystem      Size  Used Avail Use% Mounted on&lt;&#x2F;p&gt;
&lt;p&gt;rootfs           48G  510M   47G   2% &#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;tmpfs            48G  510M   47G   2% &#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;tmpfs           9.5G  228K  9.5G   1% &#x2F;run&lt;&#x2F;p&gt;
&lt;p&gt;tmpfs           5.0M     0  5.0M   0% &#x2F;run&#x2F;lock&lt;&#x2F;p&gt;
&lt;p&gt;tmpfs            10M     0   10M   0% &#x2F;dev&lt;&#x2F;p&gt;
&lt;p&gt;tmpfs            19G     0   19G   0% &#x2F;run&#x2F;shm&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;dev&#x2F;nvme0n1p1  1.5T   70M  1.4T   1% &#x2F;mnt&#x2F;p3700 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;とりあえず、100GB程度、読み書きしてみます。まずは、Write。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# time dd if=&#x2F;dev&#x2F;zero of=&#x2F;mnt&#x2F;p3700&#x2F;hello bs=100M count=1000 oflag=direct&lt;&#x2F;p&gt;
&lt;p&gt;1000+0 records in&lt;&#x2F;p&gt;
&lt;p&gt;1000+0 records out&lt;&#x2F;p&gt;
&lt;p&gt;104857600000 bytes (105 GB) copied, 77.9616 s, &lt;strong&gt;1.3 GB&#x2F;s&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;real    1m17.964s&lt;&#x2F;p&gt;
&lt;p&gt;user    0m0.000s&lt;&#x2F;p&gt;
&lt;p&gt;sys     0m45.700s &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;そして、Read。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# time dd of=&#x2F;dev&#x2F;null if=&#x2F;mnt&#x2F;p3700&#x2F;hello bs=100M count=1000 iflag=direct&lt;&#x2F;p&gt;
&lt;p&gt;1000+0 records in&lt;&#x2F;p&gt;
&lt;p&gt;1000+0 records out&lt;&#x2F;p&gt;
&lt;p&gt;104857600000 bytes (105 GB) copied, 40.6814 s, &lt;strong&gt;2.6 GB&#x2F;s&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;real    0m40.684s&lt;&#x2F;p&gt;
&lt;p&gt;user    0m0.010s&lt;&#x2F;p&gt;
&lt;p&gt;sys     0m22.650s&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;カタログスペックには若干届かないですけど、爆速です！！&lt;&#x2F;p&gt;
&lt;p&gt;大事なのでもう一度、&lt;strong&gt;爆速です！！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ランダムIOを測ってみます。まずはrandomwrite。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# fio --filename=&#x2F;mnt&#x2F;p3700&#x2F;hello  --direct=1 --rw=randwrite --bs=4k --size=2G --numjobs=64 --runtime=180 --name=file1 --ioengine=aio --iodepth=512 --group_reporting&lt;&#x2F;p&gt;
&lt;p&gt;file1: (g=0): rw=randwrite, bs=4K-4K&#x2F;4K-4K, ioengine=libaio, iodepth=512&lt;&#x2F;p&gt;
&lt;p&gt;...&lt;&#x2F;p&gt;
&lt;p&gt;file1: (g=0): rw=randwrite, bs=4K-4K&#x2F;4K-4K, ioengine=libaio, iodepth=512&lt;&#x2F;p&gt;
&lt;p&gt;2.0.8&lt;&#x2F;p&gt;
&lt;p&gt;Starting 64 processes&lt;&#x2F;p&gt;
&lt;p&gt;Jobs: 1 (f=1): [_________________________________________________________&lt;em&gt;&lt;strong&gt;w&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;] [98.4% done] [0K&#x2F;833.5M &#x2F;s] [0 &#x2F;213K iops] [eta 00m:03s]s]&lt;&#x2F;p&gt;
&lt;p&gt;file1: (groupid=0, jobs=64): err= 0: pid=20537&lt;&#x2F;p&gt;
&lt;p&gt;  write: io=129218MB, bw=734950KB&#x2F;s, iops=183737 , runt=180039msec&lt;&#x2F;p&gt;
&lt;p&gt;    slat (usec): min=3 , max=2162.1K, avg=322.56, stdev=12338.02&lt;&#x2F;p&gt;
&lt;p&gt;    clat (usec): min=12 , max=9825.2K, avg=166237.67, stdev=381829.66&lt;&#x2F;p&gt;
&lt;p&gt;     lat (usec): min=20 , max=9825.2K, avg=166560.46, stdev=382293.33&lt;&#x2F;p&gt;
&lt;p&gt;    clat percentiles (msec):&lt;&#x2F;p&gt;
&lt;p&gt;     |  1.00th=[    5],  5.00th=[    6], 10.00th=[    7], 20.00th=[    8],&lt;&#x2F;p&gt;
&lt;p&gt;     | 30.00th=[    9], 40.00th=[   11], 50.00th=[   13], 60.00th=[   22],&lt;&#x2F;p&gt;
&lt;p&gt;     | 70.00th=[   70], 80.00th=[  208], 90.00th=[  519], 95.00th=[  898],&lt;&#x2F;p&gt;
&lt;p&gt;     | 99.00th=[ 1844], 99.50th=[ 2343], 99.90th=[ 3458], 99.95th=[ 3884],&lt;&#x2F;p&gt;
&lt;p&gt;     | 99.99th=[ 5211]&lt;&#x2F;p&gt;
&lt;p&gt;    bw (KB&#x2F;s)  : min=    0, max=310600, per=1.82%, avg=13395.80, stdev=22803.92&lt;&#x2F;p&gt;
&lt;p&gt;    lat (usec) : 20=0.01%, 50=0.01%, 100=0.01%, 250=0.01%, 500=0.01%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (usec) : 750=0.01%, 1000=0.01%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 2=0.01%, 4=0.02%, 10=39.48%, 20=19.46%, 50=8.79%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 100=4.69%, 250=9.58%, 500=7.63%, 750=3.74%, 1000=2.47%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 2000=3.33%, &amp;gt;=2000=0.79%&lt;&#x2F;p&gt;
&lt;p&gt;  cpu          : usr=0.92%, sys=13.35%, ctx=29141732, majf=0, minf=3026598&lt;&#x2F;p&gt;
&lt;p&gt;  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, &amp;gt;=64=100.0%&lt;&#x2F;p&gt;
&lt;p&gt;     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &amp;gt;=64=0.0%&lt;&#x2F;p&gt;
&lt;p&gt;     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &amp;gt;=64=0.1%&lt;&#x2F;p&gt;
&lt;p&gt;     issued    : total=r=0&#x2F;w=33079899&#x2F;d=0, short=r=0&#x2F;w=0&#x2F;d=0&lt;&#x2F;p&gt;
&lt;p&gt;Run status group 0 (all jobs):&lt;&#x2F;p&gt;
&lt;p&gt;  WRITE: io=129218MB, aggrb=734949KB&#x2F;s, minb=734949KB&#x2F;s, maxb=734949KB&#x2F;s, mint=180039msec, maxt=180039msec&lt;&#x2F;p&gt;
&lt;p&gt;Disk stats (read&#x2F;write):&lt;&#x2F;p&gt;
&lt;p&gt;  nvme0n1: ios=0&#x2F;33078988, merge=0&#x2F;0, ticks=0&#x2F;5930480, in_queue=5933370, util=99.60%&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;そしてRandomRead。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wheezy64:~# fio --filename=&#x2F;mnt&#x2F;p3700&#x2F;hello  --direct=1 --rw=randread --bs=4k --size=2G --numjobs=64 --runtime=180 --name=file1 --ioengine=aio --iodepth=512 --group_reporting&lt;&#x2F;p&gt;
&lt;p&gt;file1: (g=0): rw=randread, bs=4K-4K&#x2F;4K-4K, ioengine=libaio, iodepth=512&lt;&#x2F;p&gt;
&lt;p&gt;...&lt;&#x2F;p&gt;
&lt;p&gt;file1: (g=0): rw=randread, bs=4K-4K&#x2F;4K-4K, ioengine=libaio, iodepth=512&lt;&#x2F;p&gt;
&lt;p&gt;2.0.8&lt;&#x2F;p&gt;
&lt;p&gt;Starting 64 processes&lt;&#x2F;p&gt;
&lt;p&gt;Jobs: 12 (f=6): [r__r____r___r__r__________r_r_r_r________________________r_r_r__] [93.2% done] [1403M&#x2F;0K &#x2F;s] [359K&#x2F;0  iops] [eta 00m:08s]]&lt;&#x2F;p&gt;
&lt;p&gt;file1: (groupid=0, jobs=64): err= 0: pid=21635&lt;&#x2F;p&gt;
&lt;p&gt;  read : io=131072MB, bw=1194.3MB&#x2F;s, iops=305724 , runt=109754msec&lt;&#x2F;p&gt;
&lt;p&gt;    slat (usec): min=1 , max=104416 , avg=181.86, stdev=2273.95&lt;&#x2F;p&gt;
&lt;p&gt;    clat (usec): min=88 , max=1698.4K, avg=94142.32, stdev=89737.06&lt;&#x2F;p&gt;
&lt;p&gt;     lat (usec): min=102 , max=1698.5K, avg=94324.37, stdev=89854.71&lt;&#x2F;p&gt;
&lt;p&gt;    clat percentiles (msec):&lt;&#x2F;p&gt;
&lt;p&gt;     |  1.00th=[   17],  5.00th=[   27], 10.00th=[   32], 20.00th=[   37],&lt;&#x2F;p&gt;
&lt;p&gt;     | 30.00th=[   42], 40.00th=[   57], 50.00th=[   72], 60.00th=[   85],&lt;&#x2F;p&gt;
&lt;p&gt;     | 70.00th=[  102], 80.00th=[  131], 90.00th=[  180], 95.00th=[  241],&lt;&#x2F;p&gt;
&lt;p&gt;     | 99.00th=[  478], 99.50th=[  594], 99.90th=[  865], 99.95th=[  979],&lt;&#x2F;p&gt;
&lt;p&gt;     | 99.99th=[ 1270]&lt;&#x2F;p&gt;
&lt;p&gt;    bw (KB&#x2F;s)  : min=    6, max=164272, per=1.77%, avg=21641.11, stdev=11545.90&lt;&#x2F;p&gt;
&lt;p&gt;    lat (usec) : 100=0.01%, 250=0.01%, 500=0.01%, 750=0.01%, 1000=0.01%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 2=0.01%, 4=0.03%, 10=0.40%, 20=1.29%, 50=34.99%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 100=32.37%, 250=26.29%, 500=3.75%, 750=0.66%, 1000=0.15%&lt;&#x2F;p&gt;
&lt;p&gt;    lat (msec) : 2000=0.05%&lt;&#x2F;p&gt;
&lt;p&gt;  cpu          : usr=1.34%, sys=37.50%, ctx=2798932, majf=0, minf=1003485&lt;&#x2F;p&gt;
&lt;p&gt;  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, &amp;gt;=64=100.0%&lt;&#x2F;p&gt;
&lt;p&gt;     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &amp;gt;=64=0.0%&lt;&#x2F;p&gt;
&lt;p&gt;     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &amp;gt;=64=0.1%&lt;&#x2F;p&gt;
&lt;p&gt;     issued    : total=r=33554432&#x2F;w=0&#x2F;d=0, short=r=0&#x2F;w=0&#x2F;d=0&lt;&#x2F;p&gt;
&lt;p&gt;Run status group 0 (all jobs):&lt;&#x2F;p&gt;
&lt;p&gt;   READ: io=131072MB, aggrb=1194.3MB&#x2F;s, minb=1194.3MB&#x2F;s, maxb=1194.3MB&#x2F;s, mint=109754msec, maxt=109754msec&lt;&#x2F;p&gt;
&lt;p&gt;Disk stats (read&#x2F;write):&lt;&#x2F;p&gt;
&lt;p&gt;  nvme0n1: ios=33536051&#x2F;4, merge=0&#x2F;0, ticks=4207010&#x2F;0, in_queue=4260150, util=100.00%&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;レポートから結果を抜粋してみると。 &lt;strong&gt;write 183,737iops、read 305,724iops&lt;&#x2F;strong&gt;とこれも**爆速****です！！ ** &lt;&#x2F;p&gt;
&lt;p&gt;最後にざっくりとmysqlのベンチマークを実行してみます。&lt;&#x2F;p&gt;
&lt;p&gt;Intel SSD DC P3700の場合&lt;&#x2F;p&gt;
&lt;p&gt;MySQLバージョン: &quot;5.5.38&quot;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@kvm3:~# time mysqlslap --concurrency=50 --iterations=1 --auto-generate-sql --engine=innodb --auto-generate-sql-load-type=write --number-of-queries=5000000  --port=3306 --host=197.3.o -proot&lt;&#x2F;p&gt;
&lt;p&gt;Benchmark&lt;&#x2F;p&gt;
&lt;p&gt;Running for engine innodb&lt;&#x2F;p&gt;
&lt;p&gt;Average number of seconds to run all queries: 153.368 seconds&lt;&#x2F;p&gt;
&lt;p&gt;Minimum number of seconds to run all queries: 153.368 seconds&lt;&#x2F;p&gt;
&lt;p&gt;Maximum number of seconds to run all queries: 153.368 seconds&lt;&#x2F;p&gt;
&lt;p&gt;Number of clients running queries: 50&lt;&#x2F;p&gt;
&lt;p&gt;Average number of queries per client: 100000&lt;&#x2F;p&gt;
&lt;p&gt;real 2m33.485s&lt;&#x2F;p&gt;
&lt;p&gt;user 0m38.288s&lt;&#x2F;p&gt;
&lt;p&gt;sys 4m37.968s&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;5,000,000クエリーを213.485秒で処理したので、約23,420クエリー&#x2F;秒の処理性能でした。&lt;&#x2F;p&gt;
&lt;p&gt;ちなみに、AWSのRDSの場合は以下の通りでした。&lt;&#x2F;p&gt;
&lt;p&gt;インスタンスタイプ: db.t2.medium&lt;&#x2F;p&gt;
&lt;p&gt;MySQLバージョン: &quot;5.6.17&quot;&lt;&#x2F;p&gt;
&lt;p&gt;ストレージサイズ: 10GB&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@aws2:~# time mysqlslap --concurrency=50 --iterations=1 --auto-generate-sql --engine=innodb --auto-generate-sql-load-type=write --number-of-queries=5000000  --port=3306 --host=test.hsjektsilal9.ap-northeast-1.rds.amazonaws.com -p -vv&lt;&#x2F;p&gt;
&lt;p&gt;Building Create Statements for Auto&lt;&#x2F;p&gt;
&lt;p&gt;Building Query Statements for Auto&lt;&#x2F;p&gt;
&lt;p&gt;Generating INSERT Statements for Auto&lt;&#x2F;p&gt;
&lt;p&gt;Parsing engines to use.&lt;&#x2F;p&gt;
&lt;p&gt;Starting Concurrency Test&lt;&#x2F;p&gt;
&lt;p&gt;Loading Pre-data&lt;&#x2F;p&gt;
&lt;p&gt;Generating primary key list&lt;&#x2F;p&gt;
&lt;p&gt;Generating stats&lt;&#x2F;p&gt;
&lt;p&gt;Benchmark&lt;&#x2F;p&gt;
&lt;p&gt;        Running for engine innodb&lt;&#x2F;p&gt;
&lt;p&gt;        Average number of seconds to run all queries: 1082.128 seconds&lt;&#x2F;p&gt;
&lt;p&gt;        Minimum number of seconds to run all queries: 1082.128 seconds&lt;&#x2F;p&gt;
&lt;p&gt;        Maximum number of seconds to run all queries: 1082.128 seconds&lt;&#x2F;p&gt;
&lt;p&gt;        Number of clients running queries: 50&lt;&#x2F;p&gt;
&lt;p&gt;        Average number of queries per client: 100000&lt;&#x2F;p&gt;
&lt;p&gt;real    18m2.874s&lt;&#x2F;p&gt;
&lt;p&gt;user    0m8.965s&lt;&#x2F;p&gt;
&lt;p&gt;sys     0m46.891s&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;5,000,000クエリーを1082.128秒で処理したので、約4,620クエリー&#x2F;秒の処理性能でした。&lt;&#x2F;p&gt;
&lt;p&gt;これも&lt;strong&gt;爆速&lt;&#x2F;strong&gt;といえるでしょう！！&lt;&#x2F;p&gt;
&lt;p&gt;MySQL用のストレージとして、Intel DC P3700いかがでしょうか？&lt;&#x2F;p&gt;
&lt;p&gt;現場からは以上です！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>今日のお仕事</title>
        <published>2014-10-26T00:00:00+00:00</published>
        <updated>2014-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2014/10/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2014/10/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2014/10/blog-post.html/">&lt;p&gt;こんにちは。昨日、今日と暖かく過ごしやすい週末でしたね。&lt;&#x2F;p&gt;
&lt;p&gt;とはいえ、弊社では、サーバの納期が迫っていたため、休日返上で準備に追われていました。&lt;&#x2F;p&gt;
&lt;p&gt;今回のサーバはこんなやつです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;IMG_4850s.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;3Uのシャーシに3.5インチのHDDベイが16個並んでいて、一見ストレージサーバのように見えます。しかし、背面をのぞいてみると...&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;IMG_5021s.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;こんな、1ソケットのXeonサーバボードが....&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;IMG_4856s.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;こんな感じで、8ノード搭載されています！&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;10&#x2F;blog-post.html&#x2F;image&#x2F;IMG_4851s.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;IPMIも使えて、ssh経由のSMASH&#x2F;CLPもなかなかグッドです。&lt;&#x2F;p&gt;
&lt;p&gt;WEBやキャッシュサーバなんかには、最適なんじゃないかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;休日にも関わらず、出荷のお手伝いをしてくれたスタッフのMさん、ありがとう！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>出荷を待つサーバたち</title>
        <published>2014-08-27T00:00:00+00:00</published>
        <updated>2014-08-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2014/08/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2014/08/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2014/08/blog-post.html/">&lt;p&gt;皆さんこんばんは。
今日は肌寒い一日でしたね。&lt;&#x2F;p&gt;
&lt;p&gt;季節の変り目には体調を崩しがちですので注意しましょうね。 &lt;&#x2F;p&gt;
&lt;p&gt;さて以下の写真は弊社で販売しているIntel IvyBridge Xeonプロセッサを2基搭載した、とっても高性能なサーバたちです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;08&#x2F;blog-post.html&#x2F;image&#x2F;1402285918006.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;メモリは、最大で512GB搭載可能で、最近は100GBを超えるものがよくご注文いただきます。LSIの高性能なRAIDカードが標準装備。8本のSSDと組み合わせることで、びっくりする位のIO性能をたたき出します。&lt;&#x2F;p&gt;
&lt;p&gt;オンラインゲームなどを支えるデータベースの高速化にぴったりです。 &lt;&#x2F;p&gt;
&lt;p&gt;お好みにより、10GBaseTのネットワークにも対応可能です。&lt;&#x2F;p&gt;
&lt;p&gt;商品紹介ページは&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;clustcom.com&#x2F;products&#x2F;345-2014-ivybridge-ep-xeon-dual-cpu-1u-e5-2600-v2&quot;&gt;こちら&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;一家に一台。奥さんいかがですか！&lt;&#x2F;p&gt;
&lt;p&gt;追記、開腹写真もありましたので、貼っておきます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;08&#x2F;blog-post.html&#x2F;image&#x2F;DSC_0104.JPG&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intel SSDの保証とsmart情報について</title>
        <published>2014-08-11T00:00:00+00:00</published>
        <updated>2014-08-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2014/08/intel-ssd.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2014/08/intel-ssd.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2014/08/intel-ssd.html/">&lt;p&gt;こんにちは。暑い日が続きますね。&lt;&#x2F;p&gt;
&lt;p&gt;Intel SSDの保証期間について調べる機会がありましたので、 忘れないようにメモしておきます。&lt;&#x2F;p&gt;
&lt;p&gt;何のことはなくインテルの以下のページに、よくまとまってかかれています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;CS-029645.htm&quot;&gt;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;CS-029645.htm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;これによると、保証の条件は製品によって若干異なるようですが、大まかに言って、次の二つに大別されるようです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SSDのフラッシュメディアのWear out(摩耗)情報が取れるものに関しては、それが限度に達するか、5年または3年の保証。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;上記に当てはまらないものは、5年または3年の保証。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;SSDには書き込み寿命がありますので、保証期間内であっても、メディアが寿命を越えてしまった場合には、保証の対象外となってしまう場合があるようです。&lt;&#x2F;p&gt;
&lt;p&gt;手元に、Intel 520 SSD 240GBと、DC S3500 120GBがありましたので、詳しく調べてみました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mazu-intel-520-ssd-240gbnochang-he&quot;&gt;まず、Intel 520 SSD 240GBの場合。&lt;&#x2F;h3&gt;
&lt;p&gt;以下のページを見ると、520は、&quot;E9 メディア消耗指数 (Media Wear-Out Indicator) が利用できない&quot;らしく、上述の保証条件の2番に当てはまりそうです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;cs-032511.htm&quot;&gt;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;cs-032511.htm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;なるほど、&quot;Media Wear-Out Indicator&quot;は取得できないのですね…確かめてみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;手元のIntel 520 SSD 240GBと言うのは、実は、LSIのMegaraid 9266-8iという、それはそれは高性能なRAIDカードの配下にぶら下がっています。&lt;&#x2F;p&gt;
&lt;p&gt;Megaraid配下のドライブの&quot;Media Wear-Out Indicator&quot;情報を取得するには、RAIDのユーティリティ(megacli, storcli等)でドライブIDを特定し、smartctlでsmart情報を取得すれば良いようです。&lt;&#x2F;p&gt;
&lt;p&gt;まず、storcliでDriveIDを取得します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0 &#x2F;eall &#x2F;sall show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Show Drive Information Succeeded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Drive Information :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:0     8 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:1    46 UBad   - 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:2    48 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:3     9 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:4    37 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:6    47 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:7    12 JBOD   - 232.375 GB SATA HDD N   N  512B ST9250421AS         U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この例では、{8,46,48,9,37,11,47,12}が各スロットにつながっているSSD&#x2F;HDDのDriveIDとなります。&lt;&#x2F;p&gt;
&lt;p&gt;スロット0番のSSDのスマート情報を取得するには、例えば以下の様にすれば良いです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# smartctl  -d megaraid,8  &#x2F;dev&#x2F;sdb -A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.13.2-64kvmh01] (local build)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copyright (C) 2002-11 by Bruce Allen, http:&#x2F;&#x2F;smartmontools.sourceforge.net&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;dev&#x2F;sdb [megaraid_disk_08] [SAT]: Device open changed type from &amp;#39;megaraid&amp;#39; to &amp;#39;sat&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== START OF READ SMART DATA SECTION ===&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SMART Attributes Data Structure revision number: 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Vendor Specific SMART Attributes with Thresholds:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  5 Reallocated_Sector_Ct   0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  9 Power_On_Hours          0x0032   000   000   000    Old_age   Always       -       257801117878698&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       362&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;170 Unknown_Attribute       0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;171 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;172 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;174 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       353&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;184 End-to-End_Error        0x0033   100   100   090    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;192 Power-Off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       353&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;225 Load_Cycle_Count        0x0032   100   100   000    Old_age   Always       -       1902970&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;226 Load-in_Time            0x0032   100   100   000    Old_age   Always       -       65535&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;227 Torq-amp_Count          0x0032   100   100   000    Old_age   Always       -       56&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;228 Power-off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       65535&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;232 Available_Reservd_Space 0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;233 Media_Wearout_Indicator 0x0032   097   097   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;241 Total_LBAs_Written      0x0032   100   100   000    Old_age   Always       -       1902970&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;242 Total_LBAs_Read         0x0032   100   100   000    Old_age   Always       -       2432048&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;249 Unknown_Attribute       0x0013   100   100   000    Pre-fail  Always       -       50803# smartctl  -d megaraid,8  &#x2F;dev&#x2F;sdb -A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.13.2-64kvmh01] (local build)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copyright (C) 2002-11 by Bruce Allen, http:&#x2F;&#x2F;smartmontools.sourceforge.net&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;dev&#x2F;sdb [megaraid_disk_08] [SAT]: Device open changed type from &amp;#39;megaraid&amp;#39; to &amp;#39;sat&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== START OF READ SMART DATA SECTION ===&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SMART Attributes Data Structure revision number: 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Vendor Specific SMART Attributes with Thresholds:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  5 Reallocated_Sector_Ct   0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  9 Power_On_Hours          0x0032   000   000   000    Old_age   Always       -       257801117878698&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       362&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;170 Unknown_Attribute       0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;171 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;172 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;174 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       353&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;184 End-to-End_Error        0x0033   100   100   090    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;192 Power-Off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       353&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;225 Load_Cycle_Count        0x0032   100   100   000    Old_age   Always       -       1902970&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;226 Load-in_Time            0x0032   100   100   000    Old_age   Always       -       65535&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;227 Torq-amp_Count          0x0032   100   100   000    Old_age   Always       -       56&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;228 Power-off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       65535&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;232 Available_Reservd_Space 0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;233 Media_Wearout_Indicator 0x0032   097   097   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;241 Total_LBAs_Written      0x0032   100   100   000    Old_age   Always       -       1902970&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;242 Total_LBAs_Read         0x0032   100   100   000    Old_age   Always       -       2432048&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;249 Unknown_Attribute       0x0013   100   100   000    Pre-fail  Always       -       50803&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;上記のsmart情報で、16進数でE9、すなわち233番がMedia_Wearout_Indicatorとなっていることが分かります。上記の場合、現在の値が97で、ワースト値が97、しきい値が0ということになります。&lt;&#x2F;p&gt;
&lt;p&gt;よく分からないので調べてみると、どうやら、新品のSSDはMedia_Wearout_Indicatorの値が100で、使用するにつれてだんだん減っていき、1になるともうダメと言うことのようです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Media Wear-out Indicator は、正規化した (normalized) 値が 100 で (SSD が新規工場出荷時)、1 へと減少していきます。値が 1 になった時、それは消耗の限界に到達したことを意味し、データ消滅を防ぐためにその SSD を交換するか、バックアップを取ることが推奨されます。 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;CS-032510.htm&quot;&gt;http:&#x2F;&#x2F;www.intel.com&#x2F;jp&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;CS-032510.htm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;しきい値0と言うのは、smartの世界では、障害予測に用いないということを意味する、特別な値を示しているようです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.hdsentinel.com&#x2F;smart&#x2F;index.php&quot;&gt;http:&#x2F;&#x2F;www.hdsentinel.com&#x2F;smart&#x2F;index.php&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.easis.com&#x2F;smart-value-interpretation.html&quot;&gt;http:&#x2F;&#x2F;www.easis.com&#x2F;smart-value-interpretation.html&lt;&#x2F;a&gt; &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;インテルの保証のページには、520シリーズのSSDは&quot;Media Wear-out Indicatorが取得できない&quot;種類のSSDに大別されていましたが、どうやら取得できてしまうようですσ(^_^;)&lt;&#x2F;p&gt;
&lt;p&gt;どうせ壊れるんなら、保証期間内かつMedia Wear-out Indicatorが1になる前に壊れてくれることを祈りましょう。。。&lt;&#x2F;p&gt;
&lt;p&gt;ちなみにデータシートによると、241のTotal_LBAs_WrittenのRawValueは総書き込み量を32MByteで割ったもの、同じく242のTotal_LBAs_ReadのRawValueは総読み出し量を32MByteで割ったものであるようです。&lt;&#x2F;p&gt;
&lt;p&gt;したがって、この場合の書き込み総量は、60,895,040Mbyte = 約61Tbyte、読み出し総量は、77,825,536Mbyte = 約78TByteとなります。&lt;&#x2F;p&gt;
&lt;p&gt;かなり書き込んでるにも関わらず、Media Wear-out Indicatorが3しか減っていないと言うのはうれしいですね。(この割合で行くと仮定すると、あと1PB位は余裕で書けちゃいそうですね。)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ci-ni-dc-s3500-120gbnochang-he-desu&quot;&gt;次に、DC S3500 120GBの場合です。&lt;&#x2F;h3&gt;
&lt;p&gt;以下のドキュメントによると、DC S3500シリーズのSSDは保証期間に加えて、Media Wear-out Indicatorも、保証の条件として考慮されるようです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;download.intel.com&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;DC_S3500_Warranty_r0_Japanese.pdf&quot;&gt;http:&#x2F;&#x2F;download.intel.com&#x2F;support&#x2F;ssdc&#x2F;hpssd&#x2F;sb&#x2F;DC_S3500_Warranty_r0_Japanese.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;では、実際にMedia Wear-out Indicatorの値を確かめて見ましょう。&lt;&#x2F;p&gt;
&lt;p&gt;手元のDC 3500 120GBと言うのは、Adaptec 5805Zと言う、とっても高性能なRAIDコントローラーにぶら下がっています。&lt;&#x2F;p&gt;
&lt;p&gt;AdaptecのRAIDコントローラにぶら下がった、SSDやHDDのsmart情報を取得するには、次のようなコマンドを実行すれば良いはずです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;smartctl-d-sat-dev-sg3-i&quot;&gt;smartctl -d sat &#x2F;dev&#x2F;sg3 -i&lt;&#x2F;h1&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;AdaptecのRAIDカードの場合、scsi genericドライバを読み込めば、&#x2F;dev&#x2F;sgXにデバイスファイルを作成してくれるので、それはそれは便利です。&#x2F;dev&#x2F;sgXのXの値が何になるかは、dmesgの出力を見て判別してもいいですが、&#x2F;dev&#x2F;sgXの数自体がそんなに多くなければ、順番にsmartctl -d sat &#x2F;dev&#x2F;sgX -iで調べていってもいいでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;dmesgの出力例&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# dmesg |grep scsi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi0 : aacraid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:0:0:0: Direct-Access     Adaptec  1                V1.0 PQ: 0 ANSI: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:0:1:0: Direct-Access     Adaptec  Device 1         V1.0 PQ: 0 ANSI: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:0:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:1:0: Direct-Access     INTEL    SSDSC2CW24       400i PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:2:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:3:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:4:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:5:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:6:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:7:0: Direct-Access     INTEL    SSDSC2BB12       D201 PQ: 1 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:3:0:0: Enclosure         ADAPTEC  Virtual SGPIO  0 0001 PQ: 0 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:3:1:0: Enclosure         ADAPTEC  Virtual SGPIO  1 0001 PQ: 0 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sd 0:0:0:0: Attached scsi generic sg0 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sd 0:0:1:0: Attached scsi generic sg1 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:0:0: Attached scsi generic sg2 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:1:0: Attached scsi generic sg3 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:2:0: Attached scsi generic sg4 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:3:0: Attached scsi generic sg5 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:4:0: Attached scsi generic sg6 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:5:0: Attached scsi generic sg7 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:6:0: Attached scsi generic sg8 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:1:7:0: Attached scsi generic sg9 type 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:3:0:0: Attached scsi generic sg10 type 13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 0:3:1:0: Attached scsi generic sg11 type 13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi1 : ata_piix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi2 : ata_piix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi3 : ata_piix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi4 : ata_piix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 2:0:1:0: CD-ROM            TEAC     DV-28S-V         1.0B PQ: 0 ANSI: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scsi 2:0:1:0: Attached scsi generic sg12 type 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&#x2F;dev&#x2F;sg2で試して見ます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# smartctl -d sat &#x2F;dev&#x2F;sg2 -i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.14.4-64kvmh01] (local build)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copyright (C) 2002-11 by Bruce Allen, http:&#x2F;&#x2F;smartmontools.sourceforge.net&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== START OF INFORMATION SECTION ===&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Device Model:     INTEL SSDSC2BB120G4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Serial Number:    BTWL40150AQK120LGN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LU WWN Device Id: 5 5cd2e4 04b5637db&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Firmware Version: D2010370&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;User Capacity:    120,034,123,776 bytes [120 GB]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sector Sizes:     512 bytes logical, 4096 bytes physical&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Device is:        Not in smartctl database [for details use: -P showall]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ATA Version is:   8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ATA Standard is:  ACS-2 revision 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Local Time is:    Mon Aug 11 13:57:01 2014 JST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SMART support is: Available - device has SMART capability.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SMART support is: Enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Media Wear-out Indicatorの値は以下のように取得できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# smartctl -d sat &#x2F;dev&#x2F;sg2 -A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.14.4-64kvmh01] (local build)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copyright (C) 2002-11 by Bruce Allen, http:&#x2F;&#x2F;smartmontools.sourceforge.net&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== START OF READ SMART DATA SECTION ===&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SMART Attributes Data Structure revision number: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Vendor Specific SMART Attributes with Thresholds:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  5 Reallocated_Sector_Ct   0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  9 Power_On_Hours          0x0032   100   100   000    Old_age   Always       -       798&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;170 Unknown_Attribute       0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;171 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;172 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;174 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;175 Program_Fail_Count_Chip 0x0033   100   100   010    Pre-fail  Always       -       17188520638&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;183 Runtime_Bad_Block       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;184 End-to-End_Error        0x0033   100   100   090    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;190 Airflow_Temperature_Cel 0x0022   074   074   000    Old_age   Always       -       26 (Min&#x2F;Max 23&#x2F;27)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;192 Power-Off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;194 Temperature_Celsius     0x0022   100   100   000    Old_age   Always       -       33&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;197 Current_Pending_Sector  0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;199 UDMA_CRC_Error_Count    0x003e   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;225 Load_Cycle_Count        0x0032   100   100   000    Old_age   Always       -       6850&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;226 Load-in_Time            0x0032   100   100   000    Old_age   Always       -       30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;227 Torq-amp_Count          0x0032   100   100   000    Old_age   Always       -       76&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;228 Power-off_Retract_Count 0x0032   100   100   000    Old_age   Always       -       47910&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;232 Available_Reservd_Space 0x0033   100   100   010    Pre-fail  Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;233 Media_Wearout_Indicator 0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;234 Unknown_Attribute       0x0032   100   100   000    Old_age   Always       -       0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;241 Total_LBAs_Written      0x0032   100   100   000    Old_age   Always       -       6850&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;242 Total_LBAs_Read         0x0032   100   100   000    Old_age   Always       -       21958&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Media_Wearout_Indicatorの値は100です。つまり、新品同様です。&lt;&#x2F;p&gt;
&lt;p&gt;Total_LBAs_WrittenやTotal_LBAs_Readで見ても、それぞれ、219,200Mbyte、702,656Mbyte相当となりますので、まだまだたくさん使えそうです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;matome&quot;&gt;まとめ&lt;&#x2F;h3&gt;
&lt;p&gt;Intel SSDの保証とsmart情報について調べて見ました。保証の条件は製品により異なりますが、Media Wearout Indicatorの値が取得できるとされる製品とそうでないものに大別され、前者の場合、Media Wearout Indicatorが１になってしまうと、保証交換が受けられないと考えられます。Media Wearout Indicatorはsmartctlコマンドで取得できます。手元にあったIntel 520とDC S3500は両方とも値が取得できました。SMART情報には、他にもTotal LBA WrittenなどSSDの使用状況を確認するのにちょうど良い値が記録されているので、いろいろ調べてみると良いでしょう。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Lineのインフラセミナーに参加してきました。</title>
        <published>2014-04-16T00:00:00+00:00</published>
        <updated>2014-04-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2014/04/line.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2014/04/line.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2014/04/line.html/">&lt;p&gt;昨日、LINE Developer Conference（テーマ：インフラ）に参加してきましたので、備忘録的にメモ。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Systemのお話し（講演の途中から参加）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;年末年始の障害、redisのレスポンスが悪化し、コネクションバースト。redisの処理とNIC割り込みを同じコアで処理していた。&#x2F;proc&#x2F;interruptをwatchして発見し、tasksetで解決。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;データベースのお話し&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Lineツムツムのデータベースのお話し。multimasterのmysql replication。PerconaのMMM Managerを使用。write VIPとread VIPをMMMが管理。Failover時にVIPを移動。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Shardの自動追加。すべてのUIDに対しハッシュ関数を通しグループIDを発行。グループIDに対しshardを割り当てる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;MMMはカスタマイズして使っている。主に障害判断の部分。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;shardの追加時には、移動するグループに対しselect&#x2F;insert(update?)を複数回に分けて実行する。更新時刻でソートして実行しているので、マイグレーション中に更新されたデータも、もれなく移動することができる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;3．ネットワークのお話し&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内部ネットワーク。Core-Pod-Edgeの3階層。unknown unicast flooding により、ギガビット大半の帯域を消費していた。Pod当たり数千台のサーバ。L2セグメントはPod単位だったのを、L2セグメントをEdge単位にした。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ロードバランサL3DSR採用。L2セグメントを小さくしたので必要になった。DSCP方式。Tosフィールドのdscp=1などを設定し、それに応じてソースアドレスをリアルサーバで付け替える。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ラックは24kVA 51U。スイッチは背面設置。サーバの排熱を避けるためにスイッチ3台を囲えるダクトを作成。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;海外拠点はアメリカ、アジア3ヶ所、ヨーロッパ。リングトポロジー。専用線を節約し、冗長性を確保。MPLSでPseudo Wire。出来るだけルーティングに関与せずに、拠点間接続。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバ間接続とユーザーエッジへの接続を、別々のネットワークにした。ユーザーがどの拠点に接続するか、登録時のユーザー情報をもとにスタティックにマッピング。クライアント側で実装。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;TCPコネクションはりっぱなし。ロードバランサのセッション、コネクションテーブルサイズがボトルネックになっていた。→　Stateless SLB　ハッシュテーブルに基づいて、リクエストを分散。ソースIPをキーにハッシュ値計算すればいい。サーバが落ちるとハッシュ再計算。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ハッシュの再計算を部分的に行うタイプの機器で、Stateless SLBを実現。今年一月から。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;箱物のロードバランサを使っているらしい。LVSとかじゃダメなのかな？&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;img src=&quot;&#x2F;2014&#x2F;04&#x2F;line.html&#x2F;image&#x2F;BlQaY7lCYAAI7Fj.jpg&quot; width=&quot;320&quot; height=&quot;180&quot;&gt;
&lt;p&gt;お土産までいただきました。ありがとうございます！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>1CPU、Xeonサーバ紹介</title>
        <published>2013-11-18T00:00:00+00:00</published>
        <updated>2013-11-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/11/1cpuxeon.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/11/1cpuxeon.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/11/1cpuxeon.html/">&lt;p&gt;少し前に、お客さんに納品したサーバですが、写真を撮ってあったので紹介たいと思います。 このサーバは、シングルソケットにXeon E3-1200シリーズCPUを搭載することができ、大変高速です。また、前面に2.5インチホットスワップベイを4つ搭載しているので、2.5インチのSSDを搭載することが可能で、運用も楽ちんです。&lt;&#x2F;p&gt;
&lt;p&gt;高速なWEBサーバ等に最適で、弊社のおすすめサーバの一つです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;11&#x2F;1cpuxeon.html&#x2F;image&#x2F;1cpu_xeon201311.jpg&quot; width=&quot;320&quot; height=&quot;189&quot;&gt;
&lt;p&gt;スペックは、以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CPU：　Intel Xeon E3-1270v2(IvyBridge)  3.5GHz 4core &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;メモリ：　DDR3 ECC, 4GByte x4 (合計16GByte)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ストレージ：　Intel 530 SSD x2&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;メモリスロットは4つあり、8Gbyteのメモリモジュールを用いることで、最大32GByteの構成が可能です。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;11&#x2F;1cpuxeon.html&#x2F;image&#x2F;IMG_2831.jpg&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;シャーシの全面には、4つの2.5インチホットスワップベイがあり、2.5インチのSATA SSDを搭載可能です。そのおかげで、万が一SSDが故障した際にもサーバをラックから取り外すことなく、壊れたSSDを交換可能です。また、ソフトウェアRAIDを利用することにより、場合によっては、OSを停止することなく、SSDを交換してしまうことも可能です。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;11&#x2F;1cpuxeon.html&#x2F;image&#x2F;IMG_4245.jpg&quot; width=&quot;320&quot; height=&quot;162&quot;&gt;
&lt;p&gt;最近、このサーバの後継品も販売開始しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.clustcom.com&#x2F;products&#x2F;220-intel-ssd-haswell-xeon-cpu-ez1u-e3-1200-v3&quot;&gt;http:&#x2F;&#x2F;www.clustcom.com&#x2F;products&#x2F;220-intel-ssd-haswell-xeon-cpu-ez1u-e3-1200-v3&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;コストパフォーマンスの高いシンプルなサーバです。御社で導入してみてはいかがでしょうか。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>sshuttle最強すぎる</title>
        <published>2013-07-31T00:00:00+00:00</published>
        <updated>2013-07-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/07/sshuttle.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/07/sshuttle.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/07/sshuttle.html/">&lt;p&gt;先日知った簡易vpn、sshuttleが強力過ぎる。&lt;&#x2F;p&gt;
&lt;p&gt;外出先から社内のWindowsサーバにリモートデスクトップ接続したいのだが、&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# sshuttle  --dns -r ktaka@fumidai.clustcom.com:22 192.168.20.0&#x2F;22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Connected.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ktaka@vaiox:~$ rdesktop -r sound:local -f winserver.intra.clustcom.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;たったこれだけでOK。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ノートパソコン(Debian Linux)からdocomo wifiへの接続法(メモ)</title>
        <published>2013-07-25T00:00:00+00:00</published>
        <updated>2013-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/07/debian-linuxdocomo-wifi.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/07/debian-linuxdocomo-wifi.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/07/debian-linuxdocomo-wifi.html/">&lt;p&gt;パソコンからドコモwifiに繋ぐための設定。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vaiox:~# cat &#x2F;etc&#x2F;wpa_supplicant.conf_docomo_wifi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ctrl_interface=&#x2F;var&#x2F;run&#x2F;wpa_supplicant&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;network={&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ssid=&amp;quot;docomo&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; scan_ssid=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; key_mgmt=IEEE8021X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; eap=TTLS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; identity=&amp;quot;xxxxx-spmode@docomo&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; password=&amp;quot;xxxxxx&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ca_cert=&amp;quot;&#x2F;etc&#x2F;PCA-3.pem&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; phase2=&amp;quot;auth=PAP&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;無線LANチップのドライバーをロードし、wpa_supplicantをデーモンとして起動、dhcpでアドレスを取得すればOK。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;modprobe ath9k&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;wpa_supplicant -Dwext -iwlan0 -c &#x2F;etc&#x2F;wpa_supplicant.conf_docomo_wifi -B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dhclient wlan0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>sshuttle vpnでサーバのリモート管理を便利に</title>
        <published>2013-07-25T00:00:00+00:00</published>
        <updated>2013-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/07/sshuttle-vpn.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/07/sshuttle-vpn.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/07/sshuttle-vpn.html/">&lt;p&gt;データセンタに置かれたサーバに外部からネットワーク経由でアクセスし、電源のON&#x2F;OFFやBIOS設定、OSインストールなどを行うことができれば、非常に便利です。&lt;&#x2F;p&gt;
&lt;p&gt;最近のサーバには、ネットワーク経由で電源をON&#x2F;OFFしたり、コーンソール画面を操作するための、IPMI準拠のリモートマネージメント機能が備わっていることが多いので、既に利用されている方も多いと思います。&lt;&#x2F;p&gt;
&lt;p&gt;通常、サーバは、ファイアウォールによりネットワーク的に守られた場所にあるので、踏み台サーバにsshログインして、そこからアクセスしている場合も多いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;このような場合、リモートマネージメント機能を使うには、オフィスからデータセンタにvpnを張れると便利なのですが、vpnを張るのもなかなか面倒です。&lt;&#x2F;p&gt;
&lt;p&gt;今回、sshuttle(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apenwarr&#x2F;sshuttle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;apenwarr&#x2F;sshuttle&lt;&#x2F;a&gt;)という、sshポートのみの開放でOKな、簡易vpnツールを見つけたので紹介したいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;sshuttleはLinuxとMacOSで利用可能な、簡易vpnです。踏み台サーバにはssh経由でアクセスするので、SSHのDynamic Port forwardingによるSOCKS proxyにプラスアルファしたような働きをします。&lt;&#x2F;p&gt;
&lt;p&gt;プラスアルファの部分は何かというと、あるIPアドレス、あるネットワークアドレスに対しては、クライアントプログラムでは何の設定も無しに透過的にproxyを使うことができるということです。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば、以下のポンチ絵の様に、client、proxy、targetの3台のマシンがあったとします。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;                       |&lt;&#x2F;p&gt;
&lt;p&gt;                       |   sshd:22&lt;&#x2F;p&gt;
&lt;p&gt; client  proxy  target(192.168.20.153)
                       |
                       |&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ここで、clientとproxyの間にはファイアウォールがあり、proxyへは22番ポートへのアクセスしか許可されていません。したがって、当然ながらclientからtargetへも直接アクセスできません。&lt;&#x2F;p&gt;
&lt;p&gt;踏み台サーバproxy:22へのsshコネクションを経由してtargetへアクセスできるようにするには次のコマンドのみでOKです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:~# sshuttle  -r ktaka@proxy:22 192.168.20.153&lt;&#x2F;p&gt;
&lt;p&gt;Connected.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;これだけで、以下のようにclientとporxy間にトンネルが張られます。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;                       |&lt;&#x2F;p&gt;
&lt;p&gt;     sshuttlesshd:22
 client  proxy  target(192.168.20.153)
                       |
                       |&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;トンネルを張った後に、clientからtargetに http, https, vncなどでアクセスしようとすると、&lt;&#x2F;p&gt;
&lt;p&gt;sshuttlesshd:22のトンネルを通り、targetにアクセスできるようになります。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;                       |                http, https&lt;&#x2F;p&gt;
&lt;p&gt;   sshuttlesshd:22  -------------------&amp;gt;
 client  proxy  target(192.168.20.153)
                       |
                       |&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;クライアントマシンで、どうなっているかを見てみると。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;192.168.20.153宛のパケットはTTL=42以外であれば、全て12300番ポートにリダイレクトしています&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:~# iptables -L -n -t nat&lt;&#x2F;p&gt;
&lt;p&gt;Chain PREROUTING (policy ACCEPT)&lt;&#x2F;p&gt;
&lt;p&gt;target     prot opt source               destination      &lt;&#x2F;p&gt;
&lt;p&gt;sshuttle-12300  all  --  0.0.0.0&#x2F;0            0.0.0.0&#x2F;0        &lt;&#x2F;p&gt;
&lt;p&gt;Chain INPUT (policy ACCEPT)&lt;&#x2F;p&gt;
&lt;p&gt;target     prot opt source               destination      &lt;&#x2F;p&gt;
&lt;p&gt;Chain OUTPUT (policy ACCEPT)&lt;&#x2F;p&gt;
&lt;p&gt;target     prot opt source               destination      &lt;&#x2F;p&gt;
&lt;p&gt;sshuttle-12300  all  --  0.0.0.0&#x2F;0            0.0.0.0&#x2F;0        &lt;&#x2F;p&gt;
&lt;p&gt;Chain POSTROUTING (policy ACCEPT)&lt;&#x2F;p&gt;
&lt;p&gt;target     prot opt source               destination      &lt;&#x2F;p&gt;
&lt;p&gt;Chain sshuttle-12300 (2 references)&lt;&#x2F;p&gt;
&lt;p&gt;target     prot opt source               destination      &lt;&#x2F;p&gt;
&lt;p&gt;REDIRECT   tcp  --  0.0.0.0&#x2F;0            192.168.20.153       TTL match TTL != 42 redir ports 12300&lt;&#x2F;p&gt;
&lt;p&gt;RETURN     tcp  --  0.0.0.0&#x2F;0            127.0.0.0&#x2F;8         &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;12300番ポートでは、pyhtonプログラム(sshuttle)が待ち受けています。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:~# netstat -lnp|grep 12300&lt;&#x2F;p&gt;
&lt;p&gt;tcp        0      0 127.0.0.1:12300         0.0.0.0:*               LISTEN      5059&#x2F;python    &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;これにより192.168.20.153宛のパケットは、ほぼ(TTL=42を除き) sshuttleが張ったコネクションを通るということになるのです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>出荷を待つファイルサーバー</title>
        <published>2013-07-03T00:00:00+00:00</published>
        <updated>2013-07-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/07/blog-post_3.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/07/blog-post_3.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/07/blog-post_3.html/">&lt;p&gt;某お客様向けのファイルサーバーです。フロントに2.5インチのホットスワップHDDベイを8個備えています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2828.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;今回はSeagateの1TByte SATAドライブを8本搭載します。合計8TByteの構成です。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2830.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;HDDはバックプレーンからminiSASケーブルを介してLSIのRAIDカードMegaRAID SAS 9271-8iに接続されています。このカードにはキャッシュ保護のためにCacheVaultというモジュールが取り付けられています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2832.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;CPUはXeon E3-1270v2、メモリは8GByte x4 合計32GByteと、なかなかハイスペックな構成です。8本のHDDドライブをSSDに交換すれば、そこそこ高速なDBサーバとしても使えそうです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2831.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;12,000回転のカウンターローテイティングファンを5個でシステムを冷却。CPUもメモリもRAIDカードも十分に冷却できます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2833.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;電源は500Wの電源モジュール2個で冗長化されています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2835.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;IOインターフェースは、PS&#x2F;2 マウス、キーボード、IPMI専用LANポート、USBx2、シリアルポート、VGAポート、GLANポートｘ2となっています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2836.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;筐体内部のほぼ全体写真です。配線もまあまあ、スッキリしています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;07&#x2F;blog-post_3.html&#x2F;image&#x2F;IMG_2834.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;以上です。&lt;&#x2F;p&gt;
&lt;p&gt;こんなサーバが欲しいというご要望がありましたら、是非ともご相談ください。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>kvmによる仮想マシン&quot;-cpu host&quot;オプションで性能向上する場合がある</title>
        <published>2013-05-22T00:00:00+00:00</published>
        <updated>2013-05-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/05/kvm-cpu.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/05/kvm-cpu.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/05/kvm-cpu.html/">&lt;p&gt;kvmのゲストマシンのチューニングをするために、以下のページを眺めていたら、&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Tuning_KVM&quot;&gt;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Tuning_KVM&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;こんな、記述を発見しました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Modern processors come with a wide variety of performance enhancing features such as streaming instructions sets (sse) and other performance-enhancing instructions. These features vary from processor to processor. &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;QEMU and KVM default to a compatible subset of cpu features, so that if you change your host processor, or perform a live migration, the guest will see its cpu features unchanged. This is great for compatibility but comes at a performance cost. &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;To pass all available host processor features to the guest, use the command line switch&lt;&#x2F;p&gt;
&lt;p&gt; qemu -cpu host&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;なるほど-cpu hostをつければ、CPUの高速演算機能が使えて、性能が向上するかもしれないのか…&lt;&#x2F;p&gt;
&lt;p&gt;ということで試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;&quot;-cpu host&quot;が無いゲストマシン&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# egrep model &#x2F;proc&#x2F;cpuinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model           : 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model name      : QEMU Virtual CPU version 1.4.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model           : 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model name      : QEMU Virtual CPU version 1.4.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# egrep flags &#x2F;proc&#x2F;cpuinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags           : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse36 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervisor lahf_lm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags           : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse36 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervisor lahf_lm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&quot;-cpu host&quot;があるゲストマシン&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# egrep model &#x2F;proc&#x2F;cpuinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model           : 45&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model name      : Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model           : 45&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model name      : Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# egrep flags &#x2F;proc&#x2F;cpuinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl eagerfpu pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx hypervisor lahf_lm xsaveopt tsc_adjust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl eagerfpu pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx hypervisor lahf_lm xsaveopt tsc_adjust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CPUの認識のされ方、見えてるflagの数が違います。&lt;&#x2F;p&gt;
&lt;p&gt;実際にlinpackベンチマークを採ってみました。&lt;&#x2F;p&gt;
&lt;p&gt;&quot;-cpu host&quot;が無いゲストマシン　13.0GFlops&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# cat lin_xeon64.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Thu May 23 18:59:36 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Intel(R) Optimized LINPACK Benchmark data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current date&#x2F;time: Thu May 23 18:59:36 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU frequency:    1.991 GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of CPUs: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of cores: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Parameters are set to:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of tests: 15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of equations to solve (problem size) : 1000  2000  5000  10000 15000 18000 20000 22000 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Leading dimension of array                  : 1000  2000  5008  10000 15000 18008 20016 22008 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of trials to run                     : 4     2     2     2     2     2     2     2     2     2     1     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Data alignment value (in Kbytes)            : 4     4     4     4     4     4     4     4     4     4     4     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Maximum memory requested that can be used=3873852256, at the size=22000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================== Timing linear equation system solver ===================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align. Time(s)    GFlops   Residual     Residual(norm) Check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.073      9.1585   1.125766e-12 3.839152e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.058      11.5232  1.125766e-12 3.839152e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.058      11.5443  1.125766e-12 3.839152e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.059      11.2817  1.125766e-12 3.839152e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.440      12.1283  4.992673e-12 4.343014e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.440      12.1421  4.992673e-12 4.343014e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      6.610      12.6155  2.427966e-11 3.385603e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      6.605      12.6248  2.427966e-11 3.385603e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      51.994     12.8258  8.998519e-11 3.172969e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      51.965     12.8330  8.998519e-11 3.172969e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      174.335    12.9087  2.187028e-10 3.444605e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      173.510    12.9702  2.187028e-10 3.444605e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      298.936    13.0083  2.887995e-10 3.162709e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      298.826    13.0131  2.887995e-10 3.162709e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      409.500    13.0260  3.701985e-10 3.277068e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      408.885    13.0456  3.701985e-10 3.277068e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4      544.380    13.0417  4.627267e-10 3.389291e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4      544.508    13.0386  4.627267e-10 3.389291e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Performance Summary (GFlops)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align.  Average  Maximal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4       10.8769  11.5443&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4       12.1352  12.1421&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4       12.6201  12.6248&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4       12.8294  12.8330&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4       12.9395  12.9702&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4       13.0107  13.0131&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4       13.0358  13.0456&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4       13.0402  13.0417&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Residual checks PASSED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;End of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done: Thu May 23 19:53:14 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&quot;-cpu host&quot;があるゲストマシン　28.1GFlops&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# cat lin_xeon64.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Thu May 23 18:58:46 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Intel(R) Optimized LINPACK Benchmark data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current date&#x2F;time: Thu May 23 18:58:46 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU frequency:    1.991 GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of CPUs: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of cores: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Parameters are set to:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of tests: 15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of equations to solve (problem size) : 1000  2000  5000  10000 15000 18000 20000 22000 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Leading dimension of array                  : 1000  2000  5008  10000 15000 18008 20016 22008 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of trials to run                     : 4     2     2     2     2     2     2     2     2     2     1     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Data alignment value (in Kbytes)            : 4     4     4     4     4     4     4     4     4     4     4     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Maximum memory requested that can be used=3873852256, at the size=22000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================== Timing linear equation system solver ===================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align. Time(s)    GFlops   Residual     Residual(norm) Check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.040      16.7342  1.029343e-12 3.510325e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.033      20.1526  1.029343e-12 3.510325e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.033      20.1592  1.029343e-12 3.510325e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.033      20.1368  1.029343e-12 3.510325e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.277      19.2876  4.298950e-12 3.739560e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.275      19.4285  4.298950e-12 3.739560e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      3.235      25.7781  2.581643e-11 3.599893e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      3.219      25.9008  2.581643e-11 3.599893e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      24.330     27.4089  9.603002e-11 3.386116e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      24.457     27.2672  9.603002e-11 3.386116e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      80.958     27.7979  2.042799e-10 3.217442e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      80.941     27.8037  2.042799e-10 3.217442e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      139.266    27.9224  2.894987e-10 3.170367e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      139.108    27.9542  2.894987e-10 3.170367e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      191.221    27.8951  4.097986e-10 3.627616e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      191.229    27.8940  4.097986e-10 3.627616e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4      252.595    28.1068  4.548092e-10 3.331299e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4      252.600    28.1062  4.548092e-10 3.331299e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Performance Summary (GFlops)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align.  Average  Maximal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4       19.2957  20.1592&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4       19.3581  19.4285&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4       25.8395  25.9008&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4       27.3381  27.4089&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4       27.8008  27.8037&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4       27.9383  27.9542&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4       27.8946  27.8951&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22000  22008  4       28.1065  28.1068&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Residual checks PASSED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;End of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done: Thu May 23 19:25:57 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&quot;-cpu host&quot;無しで　13.0GFlops、有りで 28.1GFlops。&lt;&#x2F;p&gt;
&lt;p&gt;だいぶ違いますね。&lt;&#x2F;p&gt;
&lt;p&gt;使っている便利マークソフトが、Intelで最適化されたLinpackなので、最新のCPUの高速演算機能を使い倒せるようになっているのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;この他、sysbenchのcpuテストや、Unixbenchで比べてみましたが、&quot;-cpu host&quot;有り無しでの性能差はありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;そうすると、ものによっては、最適化によってCPUの機能(sse4やavx等)が使い倒せれば、速くなるということなのかもしれません。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>MegaRAIDのStorCLIを試してみました。</title>
        <published>2013-05-22T00:00:00+00:00</published>
        <updated>2013-05-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/05/megaraidstorcli.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/05/megaraidstorcli.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/05/megaraidstorcli.html/">&lt;p&gt;みなさんこんにちは！&lt;&#x2F;p&gt;
&lt;p&gt;今日も相変わらず良い天気ですね。そろそろ、長袖のシャツでは暑く感じることも多くなってきました。&lt;&#x2F;p&gt;
&lt;p&gt;さて、本日は、LSIのRAIDカードの管理ユーティリティーツール、StorCLIについて、ご紹介したいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;皆さんは、RAIDカードの管理ユーティリティーと言ったら、何を思い浮かべますか？&lt;&#x2F;p&gt;
&lt;p&gt;多くの方は、綺麗なGUIツールでRAIDのアレイ削除を行ったり、Webブラウザーを使って管理することを思い浮かべるかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;今回ご紹介するのは、そういうものではなくて、sshログインしたサーバ上でコマンドラインでRAIDの設定を行う、ソフトウェアです。&lt;&#x2F;p&gt;
&lt;p&gt;古くは、3wareのtw_cliであったり、Adaptecのarcconf、LSIのmegacliをご存知の方にとっては、お馴染みかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;私個人的には、tw_cliは使いこなしており、その後、arcconfなども使っておりましたが、LSIのmegacliはあまり使いやすいとは感じておりませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;つい最近、LSIのサイトでドライバなどを探していた時に、たまたま、StorCLIという比較的新しいツールがリリースされていましたので、試しに使ってみました。&lt;&#x2F;p&gt;
&lt;p&gt;インストールは以下の通り&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# wget http:&#x2F;&#x2F;www.lsi.com&#x2F;downloads&#x2F;Public&#x2F;MegaRAID%20Common%20Files&#x2F;1.03.11_StorCLI.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# unzip 1.03.11_StorCLI.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# cd StorCli_All_OS&#x2F;Linux&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# alien  -t storcli-1.03.11-1.noarch.rpm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# tar tvf storcli-1.03.11.tgz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x root&#x2F;root         0 2013-05-23 01:57 .&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x root&#x2F;root         0 2013-05-23 01:57 .&#x2F;opt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x root&#x2F;root         0 2013-05-23 01:57 .&#x2F;opt&#x2F;MegaRAID&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x root&#x2F;root         0 2013-05-23 01:57 .&#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rwxr-xr-x root&#x2F;root   4956856 2013-01-30 19:25 .&#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rwxr-xr-x root&#x2F;root   4907676 2013-01-30 19:25 .&#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# tar  xf storcli-1.03.11.tgz  -C &#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# tree &#x2F;opt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;opt&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`-- MegaRAID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    `-- storcli&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        |-- storcli&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        `-- storcli64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 directories, 2 files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;storcli64が64bit Linux用のバイナリです。早速、コマンドを叩いてみると、&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Storage Command Line Tool  Ver 1.03.11 Jan 30, 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     (c)Copyright 2012, LSI Corporation, All Rights Reserved.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;help - lists all the commands with their usage. E.g. storcli help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;help - gives details about a particular command. E.g. storcli add help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;List of commands:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Commands   Description&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add        Adds&#x2F;creates a new element to controller like VD,Spare..etc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;delete     Deletes an element like VD,Spare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;show       Displays information about an element&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set        Set a particular value to a property&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;start      Start background operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stop       Stop background operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pause      Pause background operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;resume     Resume background operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;download   Downloads file to given device&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;expand     expands size of given drive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;insert     inserts new drive for missing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;transform  downgrades the controller&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;cx        Controller specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;ex        Enclosure specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sx        Slot&#x2F;PD specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;vx        Virtual drive specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;dx        Disk group specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;fx        Foreign configuration specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;px        Phy specific commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;bbu       Battery Backup Unit related commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Other aliases : cachecade, freespace, sysinfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use a combination of commands to filter the output of help further.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;E.g. &amp;#39;storcli cx show help&amp;#39; displays all the show operations on cx.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use verbose for detailed description E.g. &amp;#39;storcli add  verbose help&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use &amp;#39;page=[x]&amp;#39; as the last option in all the commands to set the page break.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;X=lines per page. E.g. &amp;#39;storcli help page=10&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Command options must be entered in the same order as displayed in the help of&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the respective commands.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;新しいCLIツールと聞いて薄々感づいていましたが、どうやら、tw_cliと構文がそっくりです。&lt;&#x2F;p&gt;
&lt;p&gt;3wareは、2009年にLSIに買収されたのですが、使い易いと評判だった3wareのCLIの良い部分を、既存のMegaraidのプロダクトラインでも使えるようにしたのでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;コントローラの情報を表示してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status Code = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of Controllers = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host Name = 151&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Operating System  = Linux3.8.8-64kvmh01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Overview :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;===============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ctl Model   Ports PDs DGs DNOpt VDs VNOpt BBU  sPR DS  EHS ASOs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 9266-8i     8   6   0     0   0     0 Msng On  1&amp;amp;2 Y      2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ctl=Controller Index|DGs=Drive groups|VDs=Virtual drives|Fld=Failed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PDs=Physical drives|DNOpt=DG NotOptimal|VNOpt=VD NotOptimal|Opt=Optimal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Msng=Missing|Dgd=Degraded|NdAtn=Need Attention|Unkwn=Unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sPR=Scheduled Patrol Read|DS=DimmerSwitch|EHS=Emergency Hot Spare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Y=Yes|N=No|ASOs=Advanced Software Options|BBU=Battery backup unit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;コントローラ0番が9266-8i であることがわかりますね。ポート数は8で、現在接続されているドライブは6本、BBUはMissing　…　あってます。&lt;&#x2F;p&gt;
&lt;p&gt;下の方に書いてある、説明が地味に便利ですね。&lt;&#x2F;p&gt;
&lt;p&gt;コントローラ0番の情報を、さらに詳しく見てみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Product Name = LSI MegaRAID SAS 9266-8i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Serial Number = SV22625074&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SAS Address =  500605b0050719c0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Mfg. Date = 07&#x2F;03&#x2F;12&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Time = 05&#x2F;23&#x2F;2013 02:16:39&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller Time = 05&#x2F;22&#x2F;2013 17:16:38&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FW Package Build = 23.9.0-0018&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BIOS Version = 5.38.00_4.12.05.00_0x05180000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FW Version = 3.220.35-1998&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Driver Name = megaraid_sas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Driver Version = 06.504.01.00-rc1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller Bus Type = N&#x2F;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Slot = N&#x2F;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Bus Number = 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Device Number = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Function Number = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Physical Drives = 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PD LIST :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=======&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:0    39 JBOD  -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:1     8 JBOD  -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:2    38 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:3     9 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:4    37 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ああ、良いですね、いろんな情報とれてます。文法は、tw_cliそのまんまですね。&lt;&#x2F;p&gt;
&lt;p&gt;せっかくですので、RAIDのアレイを作ってみましょう…まずは、ヘルプを…&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 add help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Storage Command Line Tool  Ver 1.03.11 Jan 30, 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     (c)Copyright 2012, LSI Corporation, All Rights Reserved.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storcli &#x2F;cx add vd type=raid[0|1|5|6|00|10|50|60]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [Size=,,..|all] [name=,..]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; drives=e:s|e:s-x|e:s-x,y,e:s-x,y,z [PDperArray=x][SED]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [pdcache=on|off|default][pi][DimmerSwitch(ds)=default|automatic(auto)|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; none|maximum(max)|MaximumWithoutCaching(maxnocache)][wt|wb][nora|ra]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [direct|cached] [CachedBadBBU|NoCachedBadBBU] [cachevd]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [Strip=] [AfterVd=X]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [Spares = [e:]s|[e:]s-x|[e:]s-x,y] [force]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storcli &#x2F;cx add vd each type=raid0 [name=,..] [drives=e:s|e:s-x|e:s-x,y]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [SED] [pdcache=on|off|default][pi] [DimmerSwitch(ds)=default|automatic(auto)|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; none|maximum(max)|MaximumWithoutCaching(maxnocache)] [wt|wb] [nora|ra]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [direct|cached] [CachedBadBBU|NoCachedBadBBU]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [Strip=]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storcli &#x2F;cx add vd cachecade Type = raid[0,1,10] drives = [e:]s|[e:]s-x|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [e:]s-x,y [WT| WB] [assignvds = 0,1,2]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storcli &#x2F;cx[&#x2F;ex]&#x2F;sx add hotsparedrive [DGs=] [enclaffinity] [nonrevertible]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;なるほど…　スロット2，3，4のドライブを使って、RAID5のアレイ=バーチャルドライブを作ってみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0 add vd type=raid5  drives=252:2,252:3,252:4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Add VD Succeeded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;うまくいったみたいなので、確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Product Name = LSI MegaRAID SAS 9266-8i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Serial Number = SV22625074&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SAS Address =  500605b0050719c0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Mfg. Date = 07&#x2F;03&#x2F;12&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Time = 05&#x2F;23&#x2F;2013 02:36:32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller Time = 05&#x2F;22&#x2F;2013 17:36:30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FW Package Build = 23.9.0-0018&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BIOS Version = 5.38.00_4.12.05.00_0x05180000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FW Version = 3.220.35-1998&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Driver Name = megaraid_sas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Driver Version = 06.504.01.00-rc1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller Bus Type = N&#x2F;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Slot = N&#x2F;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Bus Number = 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Device Number = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PCI Function Number = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Drive Groups = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOPOLOGY :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG Arr Row EID:Slot DID Type  State BT       Size PDC  PI SED DS3  FSpace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 -   -   -        -   RAID5 Optl  N  446.125 GB enbl N  N   none N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   -   -        -   RAID5 Optl  N  446.125 GB enbl N  N   none N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   0   252:2    38  DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   1   252:3    9   DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   2   252:4    37  DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG=Disk Group Index|Arr=Array Index|Row=Row Index|EID=Enclosure Device ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DID=Device ID|Type=Drive Type|Onln=Online|Rbld=Rebuild|Dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pdgd=Partially degraded|Offln=Offline|BT=Background Task Active&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PDC=PD Cache|PI=Protection Info|SED=Self Encrypting Drive|Frgn=Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DS3=Dimmer Switch 3|dflt=Default|Msng=Missing|FSpace=Free Space Present&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Virtual Drives = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VD LIST :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=======&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG&#x2F;VD TYPE  State Access Consist Cache sCC       Size Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0&#x2F;0   RAID5 Optl  RW     No      RaWTD -   446.125 GB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Cac=CacheCade|Rec=Recovery|OfLn=OffLine|Pdgd=Partially Degraded|dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Optl=Optimal|RO=Read Only|RW=Read Write|B=Blocked|Consist=Consistent|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ra=Read Ahead Adaptive|R=Read Ahead Always|NR=No Read Ahead|WB=WriteBack|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWB=Always WriteBack|WT=WriteThrough|C=Cached IO|D=Direct IO|sCC=Scheduled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Check Consistency&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Physical Drives = 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PD LIST :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=======&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:0    39 JBOD  -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:1     8 JBOD  -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:2    38 Onln  0  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:3     9 Onln  0  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:4    37 Onln  0  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ドライブグループ0番と、バーチャルドライブ0番が、今作成したRAID5のアレイ=VDです。DG=0の情報だけを見るには、次のようにします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;d0 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Show Diskgroup Succeeded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOPOLOGY :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG Arr Row EID:Slot DID Type  State BT       Size PDC  PI SED DS3  FSpace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 -   -   -        -   RAID5 Optl  N  446.125 GB enbl N  N   none N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   -   -        -   RAID5 Optl  N  446.125 GB enbl N  N   none N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   0   252:2    38  DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   1   252:3    9   DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 0   2   252:4    37  DRIVE Onln  N  223.062 GB enbl N  N   none -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG=Disk Group Index|Arr=Array Index|Row=Row Index|EID=Enclosure Device ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DID=Device ID|Type=Drive Type|Onln=Online|Rbld=Rebuild|Dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pdgd=Partially degraded|Offln=Offline|BT=Background Task Active&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PDC=PD Cache|PI=Protection Info|SED=Self Encrypting Drive|Frgn=Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DS3=Dimmer Switch 3|dflt=Default|Msng=Missing|FSpace=Free Space Present&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;VD=0の情報だけを見るには、以下のようにします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;v0 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Virtual Drives :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;==============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG&#x2F;VD TYPE  State Access Consist Cache sCC       Size Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0&#x2F;0   RAID5 Optl  RW     No      RaWTD -   446.125 GB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Cac=CacheCade|Rec=Recovery|OfLn=OffLine|Pdgd=Partially Degraded|dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Optl=Optimal|RO=Read Only|RW=Read Write|B=Blocked|Consist=Consistent|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ra=Read Ahead Adaptive|R=Read Ahead Always|NR=No Read Ahead|WB=WriteBack|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWB=Always WriteBack|WT=WriteThrough|C=Cached IO|D=Direct IO|sCC=Scheduled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Check Consistency&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ライトキャッシュの設定がWTになっているので、AWBに変えてみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@151:~# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;v0 set wrcache=AWB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Detailed Status :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;===============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VD Property Value Status  ErrCd ErrMsg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 wrCache  AWB   Success     0 -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;確認は次のようにします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@151:~# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;v0 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Virtual Drives :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;==============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG&#x2F;VD TYPE  State Access Consist Cache  sCC       Size Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0&#x2F;0   RAID5 Optl  RW     No      RaAWBD -   446.125 GB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Cac=CacheCade|Rec=Recovery|OfLn=OffLine|Pdgd=Partially Degraded|dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Optl=Optimal|RO=Read Only|RW=Read Write|B=Blocked|Consist=Consistent|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ra=Read Ahead Adaptive|R=Read Ahead Always|NR=No Read Ahead|WB=WriteBack|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWB=Always WriteBack|WT=WriteThrough|C=Cached IO|D=Direct IO|sCC=Scheduled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Check Consistency&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;AWB　Always WriteBackに変わりました。&lt;&#x2F;p&gt;
&lt;p&gt;次に、ホットスペアドライブを設定してみます。まずはヘルプで、コマンドシンタックスを確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;e252&#x2F;s5 add help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Storage Command Line Tool  Ver 1.03.11 Jan 30, 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     (c)Copyright 2012, LSI Corporation, All Rights Reserved.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NAME: Add Hot Spare Drive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SYNTAX: storcli &#x2F;cx[&#x2F;ex]&#x2F;sx add hotsparedrive [DGs=]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [enclaffinity] [nonrevertible]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DESCRIPTION: This command creates a hotspare drive.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OPTIONS:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DGs          - Specifies the drive group to which the hotspare drive is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               dedicated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;enclaffinity - Specifies the enclosure to which the hotspare is associated&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               with. If this option is specified, affinity is set; if it is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               not specified, there is no affinity.NOTE Affinity cannot be&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               removed once it is set for a hotspare drive.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nonrevertible- Sets the drive as a nonrevertible hotspare.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONVENTION:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;cx - specifies a controller where X is the controller index.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;ex - specifies a enclosure where X is the enclosure device ID.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sx - specifies a physical drive where X is the slot number.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;そしてスロット5番のドライブをホットスペアに設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;e252&#x2F;s5 add hotsparedrive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Add Hot Spare Succeeded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;確認してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@151:~# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;e252&#x2F;s5 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Show Drive Information Succeeded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Drive Information :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 GHS   -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;スロット5番のドライブがグローバルホットスペアになったようです。&lt;&#x2F;p&gt;
&lt;p&gt;グローバルホットスペアの機能を確認するために、今RAID5のアレイの作成に用いたドライブの内、スロット2番のドライブをオフラインにしてみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;e252&#x2F;s2 set offline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Set Drive Offline Succeeded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;バーチャルドライブの状態を見てみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;v0 show all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;c0&#x2F;v0 :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;======&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DG&#x2F;VD TYPE  State Access Consist Cache  sCC       Size Name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0&#x2F;0   RAID5 Dgrd  RW     Yes     RaAWBD -   446.125 GB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Cac=CacheCade|Rec=Recovery|OfLn=OffLine|Pdgd=Partially Degraded|dgrd=Degraded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Optl=Optimal|RO=Read Only|RW=Read Write|B=Blocked|Consist=Consistent|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ra=Read Ahead Adaptive|R=Read Ahead Always|NR=No Read Ahead|WB=WriteBack|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWB=Always WriteBack|WT=WriteThrough|C=Cached IO|D=Direct IO|sCC=Scheduled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Check Consistency&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PDs for VD 0 :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 Rbld   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:3     9 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:4    37 Onln   0 223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VD0 Properties :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;==============&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Strip Size = 256 KB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Span Depth = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of Drives Per Span = 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Disk Cache Policy = Enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Encryption = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Data Protection = Disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Active Operations = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Exposed to OS = Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Creation Date = 22-05-2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Creation Time = 05:28:54 PM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Emulation type = None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;vd0はDegradedとなり、ホットスペアにしてあったスロット5番のドライブがvd0に加わり、Rebuild状態になっていることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;最後にvd0を削除してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@151:~#  &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;v0 del&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Delete VD succeeded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#  &#x2F;opt&#x2F;MegaRAID&#x2F;storcli&#x2F;storcli64 &#x2F;c0&#x2F;e252&#x2F;s2-5 show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Controller = 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status = Success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description = Show Drive Information Succeeded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Drive Information :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID:Slt DID State DG       Size Intf Med SED PI SeSz Model               Sp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:2    38 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:3     9 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:4    37 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;252:5    11 UGood -  223.062 GB SATA SSD N   N  512B INTEL SSDSC2CW240A3 U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;----------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EID-Enclosure Device ID|Slt-Slot No.|DID-Device ID|DG-DriveGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DHS-Dedicated Hot Spare|UGood-Unconfigured Good|GHS-Global Hotspare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UBad-Unconfigured Bad|Onln-Online|Offln-Offline|Intf-Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Med-Media Type|SED-Self Encryptive Drive|PI-Protection Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SeSz-Sector Size|Sp-Spun|U-Up|D-Down|T-Transition|F-Foreign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;スロット2，3，4，5のドライブが、最初の状態Unconfigured Goodに戻りました。&lt;&#x2F;p&gt;
&lt;p&gt;以上、見てきたように、StorCLIの使い方について試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;3wareのtw_cliに慣れた管理者の方には、直感的で大変使い易いのではないかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;参考までにStorCLIのダウンロードリンクと、リファレンスマニュアルへの直リンクを貼っておきます。&lt;&#x2F;p&gt;
&lt;p&gt;StorCLI&lt;&#x2F;p&gt;
&lt;p&gt;http:&#x2F;&#x2F;www.lsi.com&#x2F;downloads&#x2F;Public&#x2F;MegaRAID%20Common%20Files&#x2F;1.03.11_StorCLI.zip&lt;&#x2F;p&gt;
&lt;p&gt;リファレンスマニュアル&lt;&#x2F;p&gt;
&lt;p&gt;http:&#x2F;&#x2F;www.lsi.com&#x2F;downloads&#x2F;Public&#x2F;MegaRAID%20Common%20Files&#x2F;StorCLI_RefMan_revf_.pdf&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>もろもろLinpack Benchmarkしてみました</title>
        <published>2013-05-21T00:00:00+00:00</published>
        <updated>2013-05-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/05/linpack-benchmark.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/05/linpack-benchmark.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/05/linpack-benchmark.html/">&lt;p&gt;こんにちは！&lt;&#x2F;p&gt;
&lt;p&gt;今日は、引きこもって仕事をするには、もったいないくらいの良いお天気でしたね♪&lt;&#x2F;p&gt;
&lt;p&gt;なかなか良い季節になってきたので、週末が楽しみです。&lt;&#x2F;p&gt;
&lt;p&gt;前回に引き続き、いくつかのサーバでベンチマークを採る機会があったので、ここに晒します。&lt;&#x2F;p&gt;
&lt;p&gt;Linpack ベンチマークは「一番じゃなきゃダメですか」で有名なスパコンのランキングを決定するためにも使われる、有名なベンチマークソフトです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;LINPACK ベンチマークは LINPACK に基づいたベンチマークプログラムで、システムの浮動小数点演算性能を評価する。ジャック・ドンガラが考案したもので、理学・工学で一般的な n×n の線型方程式系 Ax = b を解く速度を測定する。このベンチマークの最新版はTOP500で世界の高速なコンピュータの性能値としてランキングに使用されている。　&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;LINPACK&quot;&gt;http:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;LINPACK&lt;&#x2F;a&gt;　より&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt; スパコンの評価のためには、並列計算用のMPIライブラリや、行列計算ライブラリ、LINPACK本体等、いろいろセットアップが必要です。&lt;&#x2F;p&gt;
&lt;p&gt;クラスター構成ではない普通のSMPマシンを評価するには、IntelのOptimized LINPACK Benchmarkというのを使えば、お手軽にベンチマークができそうです。&lt;&#x2F;p&gt;
&lt;p&gt;まず、以下のページから、tarボールをダウンロードし、展開します。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;software.intel.com&#x2F;en-us&#x2F;articles&#x2F;intel-math-kernel-library-linpack-download&#x2F;&quot;&gt;http:&#x2F;&#x2F;software.intel.com&#x2F;en-us&#x2F;articles&#x2F;intel-math-kernel-library-linpack-download&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;wget http:&#x2F;&#x2F;registrationcenter.intel.com&#x2F;irc_nas&#x2F;3058&#x2F;l_lpk_p_11.0.3.008.tgz&lt;&#x2F;p&gt;
&lt;p&gt;tar xvf  l_lpk_p_11.0.3.008.tgz&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;以下のディレクトリにベンチマーク本体、スクリプト、入力ファイルなどが用意されているので、そのディレクトリで標準的なrunme_xeon64などのスクリプトを実行すれば良さそうです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;cd  linpack_11.0.3&#x2F;benchmarks&#x2F;linpack&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt; 試しに実行してみます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&#x2F;runme_xeon64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is a SAMPLE run script for SMP LINPACK. Change it to reflect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the correct number of CPUs&#x2F;threads, problem input files, etc..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Tue May 14 18:47:46 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Intel(R) Optimized LINPACK Benchmark data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current date&#x2F;time: Tue May 14 18:47:46 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU frequency:    2.932 GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of CPUs: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of cores: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Parameters are set to:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of tests: 15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of equations to solve (problem size) : 1000  2000  5000  10000 15000 18000 20000 22000 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Leading dimension of array                  : 1000  2000  5008  10000 15000 18008 20016 22008 25000 26000 27000 30000 35000 40000 45000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Number of trials to run                     : 4     2     2     2     2     2     2     2     2     2     1     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Data alignment value (in Kbytes)            : 4     4     4     4     4     4     4     4     4     4     4     1     1     1     1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Maximum memory requested that can be used=3202964416, at the size=20000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================== Timing linear equation system solver ===================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align. Time(s)    GFlops   Residual     Residual(norm) Check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.038      17.4850  1.236872e-12 4.218050e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.037      17.9669  1.236872e-12 4.218050e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.037      17.9904  1.236872e-12 4.218050e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4      0.037      18.0328  1.236872e-12 4.218050e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.271      19.7349  4.570122e-12 3.975446e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4      0.270      19.7479  4.570122e-12 3.975446e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      2.512      33.1981  2.113014e-11 2.946428e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4      2.492      33.4647  2.113014e-11 2.946428e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      17.385     38.3576  9.365270e-11 3.302289e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4      17.431     38.2572  9.365270e-11 3.302289e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      59.425     37.8704  2.005595e-10 3.158845e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4      60.409     37.2536  2.005595e-10 3.158845e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      103.157    37.6964  2.980711e-10 3.264245e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4      102.891    37.7938  2.980711e-10 3.264245e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      142.172    37.5190  3.917629e-10 3.467960e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4      142.003    37.5634  3.917629e-10 3.467960e-02   pass&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Performance Summary (GFlops)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size   LDA    Align.  Average  Maximal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1000   1000   4       17.8687  18.0328&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2000   2000   4       19.7414  19.7479&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5000   5008   4       33.3314  33.4647&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10000  10000  4       38.3074  38.3576&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15000  15000  4       37.5620  37.8704&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18000  18008  4       37.7451  37.7938&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20000  20016  4       37.5412  37.5634&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Residual checks PASSED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;End of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done: Tue May 14 19:01:30 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;上記は、4コア、8スレッドのCPUを搭載したサーバーですが、自動的にCPUの数を認識して、適切なThread数を設定してくれているようです。&lt;&#x2F;p&gt;
&lt;p&gt;runme_xeon64スクリプトの中で、&quot;export OMP_NUM_THREADS=4&quot;のように明示的にスレッド数を指定することも可能です。&lt;&#x2F;p&gt;
&lt;p&gt;入力ファイルでいくつかproblem sizeが指定されていますが、搭載しているメモリの容量から判断して、大きすぎるものは実行されないようです。&lt;&#x2F;p&gt;
&lt;p&gt;swapを含む、メモリ容量で実行可否を判断しているようなので、可能ならswapoff -aするか、あるいは、入力ファイルから大きすぎるものを削除した方が良いかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;上記の結果からは、最大で、38.4GFlopsの性能であると、判断できます。&lt;&#x2F;p&gt;
&lt;p&gt;さて、このLinpackベンチマークを、弊社にあるいくつかの物理マシン、仮想マシン上で実行してみました。&lt;&#x2F;p&gt;
&lt;p&gt;物理マシン&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;マシン名&lt;&#x2F;th&gt;&lt;th&gt;CPU スペック&lt;&#x2F;th&gt;&lt;th&gt;HT&lt;&#x2F;th&gt;&lt;th&gt;メモリ GByte&lt;&#x2F;th&gt;&lt;th&gt;総クロック GHz&lt;&#x2F;th&gt;&lt;th&gt;スコア GFlops&lt;&#x2F;th&gt;&lt;th&gt;スコア&#x2F;総クロック&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;Xeon E5-2650 2.00GHz 8 core x 2cpu&lt;&#x2F;td&gt;&lt;td&gt;on&lt;&#x2F;td&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;229.8&lt;&#x2F;td&gt;&lt;td&gt;7.18&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;Xeon E5-2650 2.00GHz 8 core x 2cpu&lt;&#x2F;td&gt;&lt;td&gt;off&lt;&#x2F;td&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;231.0&lt;&#x2F;td&gt;&lt;td&gt;7.22&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;Xeon E5-2650 2.00GHz 4 core x 2cpu&lt;&#x2F;td&gt;&lt;td&gt;on&lt;&#x2F;td&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;117.1&lt;&#x2F;td&gt;&lt;td&gt;7.32&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;Xeon E5-2603 1.80GHz 4 core x 2cpu&lt;&#x2F;td&gt;&lt;td&gt;na&lt;&#x2F;td&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;14.4&lt;&#x2F;td&gt;&lt;td&gt;103.8&lt;&#x2F;td&gt;&lt;td&gt;7.21&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;Xeon X5650 2.67GHz 6 core x 2cpu&lt;&#x2F;td&gt;&lt;td&gt;on&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;32.04&lt;&#x2F;td&gt;&lt;td&gt;114.1&lt;&#x2F;td&gt;&lt;td&gt;3.56&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;Xeon X3440 2.53GHz 4 core x 1cpu&lt;&#x2F;td&gt;&lt;td&gt;on&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;10.12&lt;&#x2F;td&gt;&lt;td&gt;38.0&lt;&#x2F;td&gt;&lt;td&gt;3.75&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;Xeon X3440 2.53GHz 4 core x 1cpu&lt;&#x2F;td&gt;&lt;td&gt;on&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;10.12&lt;&#x2F;td&gt;&lt;td&gt;38.4&lt;&#x2F;td&gt;&lt;td&gt;3.79&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;マシンスペック&lt;&#x2F;p&gt;
&lt;p&gt;1,2,3は同一マシンで、Supermicro 1027R-WRF&#x2F;Xeon E5-2650 x 2&#x2F;メモリ 96MByte&#x2F;Intel 520 SSD 240GB。2ではBIOSでHyperThreadingを無効化、3ではBIOSでアクティブコア数を4個に制限しています。&lt;&#x2F;p&gt;
&lt;p&gt;4 はSupermicro 1027R-WR&#x2F;Xeon E5-2603 x 2&#x2F;メモリ 96MByte&#x2F;Intel 520 SSD 240GB&lt;&#x2F;p&gt;
&lt;p&gt;5 はIntel S5520SC&#x2F;Xeon X5650 x 2&#x2F;メモリ 16MByte&#x2F;Adaptec ASR-5405&#x2F;HGST SATA 2TB HDD&lt;&#x2F;p&gt;
&lt;p&gt;6,7 Intel S3420GP &#x2F;Xeon X3440 x 1&#x2F;メモリ 4MByte&#x2F;Seagate SATA 320GB HDD&lt;&#x2F;p&gt;
&lt;p&gt;表中の総クロックGHzはクロックxコア数で計算してあります。&lt;&#x2F;p&gt;
&lt;p&gt;1と2を比べるとHyperThreadingをOFFにしても、スコアが変わらないことがわかります。また、1と3を比べると、コア数が半分になり総クロックが半分になると、スコアが約半分になっています。&lt;&#x2F;p&gt;
&lt;p&gt;また、3と4からは、総クロックにだいたい比例しているようです。&lt;&#x2F;p&gt;
&lt;p&gt;したがって、Linpack性能は、同じ世代のCPUであればHTの有無には依存せず、総クロックに比例すると考えられます。&lt;&#x2F;p&gt;
&lt;p&gt;CPUの世代の異なる1と5を比べると、最新のXeon E5-2650(Sandybridge)のスコアは約230GFlopsで、一世代前のXeon X5650(Westmere)のスコア約114GFlops比べて、倍以上の性能があることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;Xeon X5650(Westmere)とXeon X3440(Lynnfield)は同じ世代のプロセッサですが、 5と6を比べてみると、だいたい総クロックに比例した性能になっていることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;一番右の行にスコア&#x2F;総クロックを示してみましたが、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;FLOPS&quot;&gt;このページ&lt;&#x2F;a&gt;によると理論性能は、Nehalem&#x2F;Westmere&#x2F;Lynnfield世代で4、Sandybridge世代で8であるので、だいたいこれに近い値になっていることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;次の上記のマシン上に作成した仮想マシンの性能を調べてみました。&lt;&#x2F;p&gt;
&lt;p&gt;仮想マシン&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;マシン名&lt;&#x2F;th&gt;&lt;th&gt;仮想マシン種類&lt;&#x2F;th&gt;&lt;th&gt;CPU スペック&lt;&#x2F;th&gt;&lt;th&gt;メモリGByte&lt;&#x2F;th&gt;&lt;th&gt;総クロックGHz&lt;&#x2F;th&gt;&lt;th&gt;スコアGFlops&lt;&#x2F;th&gt;&lt;th&gt;スコア&#x2F;総クロック&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;kvm1&lt;&#x2F;td&gt;&lt;td&gt;kvm&lt;&#x2F;td&gt;&lt;td&gt;2.0GHz x 2 (Xeon E5-2650)  &lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;28.2&lt;&#x2F;td&gt;&lt;td&gt;7.05&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;kvm2&lt;&#x2F;td&gt;&lt;td&gt;kvm&lt;&#x2F;td&gt;&lt;td&gt;2.0GHz x 16 (Xeon E5-2650)&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;187.3&lt;&#x2F;td&gt;&lt;td&gt;5.85&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;kvm3&lt;&#x2F;td&gt;&lt;td&gt;kvm&lt;&#x2F;td&gt;&lt;td&gt;2.67GHz x 2 (Xeon X5650)&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;5.34&lt;&#x2F;td&gt;&lt;td&gt;21.9&lt;&#x2F;td&gt;&lt;td&gt;4.10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;kvm4&lt;&#x2F;td&gt;&lt;td&gt;kvm&lt;&#x2F;td&gt;&lt;td&gt;2.53GHz x 2 (Xeon X3440)&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;5.06&lt;&#x2F;td&gt;&lt;td&gt;20.13&lt;&#x2F;td&gt;&lt;td&gt;3.98&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;sak1&lt;&#x2F;td&gt;&lt;td&gt;Sakura VPS&lt;&#x2F;td&gt;&lt;td&gt;2.4GHz x 2 (Core 2 DuoT7700)&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;4.8&lt;&#x2F;td&gt;&lt;td&gt;11.7&lt;&#x2F;td&gt;&lt;td&gt;2.43&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;xen1&lt;&#x2F;td&gt;&lt;td&gt;xenserver 6.1&lt;&#x2F;td&gt;&lt;td&gt;1.8GHz x 8 (Xeon E5-2603)&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;14.4&lt;&#x2F;td&gt;&lt;td&gt;6.8&lt;&#x2F;td&gt;&lt;td&gt;0.47&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;xen2&lt;&#x2F;td&gt;&lt;td&gt;xenserver 6.1&lt;&#x2F;td&gt;&lt;td&gt;1.8GHz x 1 (Xeon E5-2603)&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;1.8&lt;&#x2F;td&gt;&lt;td&gt;6.8&lt;&#x2F;td&gt;&lt;td&gt;3.78&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;kvm1のスコア&#x2F;総クロックは7.05で理論値の8に近く、上の物理マシン表と比べても遜色なく、なかなか優秀と言えます。しかしながらkvm2の場合には、5.85と若干下がった値になっています。kvmのゲストカーネルはNUMA対応カーネルにしていないので、それが原因かもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;kvm3、kvm4のスコア&#x2F;総クロックを見ると優秀ではありますが、理論値の4に非常に近いか、又は超えてしまっており、ちょっと不自然です。ターボブースト機能により、実際のコアのクロックが上がっているのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;sak1のスコア&#x2F;総クロックは2.43は、Core 2 Duoの理論値4よりもだいぶ小さく、あまり優秀ではありません。&lt;&#x2F;p&gt;
&lt;p&gt;xen1、xen2も、Sandybridge世代の理論値8よりもかなり小さく、全く優秀ではありません。xen1は8CPUにも関わらず、1CPUのxen2とスコアが変わらず、仮想の8CPUのスレッドが、一個の物理コア上で実行されているように見受けられます。&lt;&#x2F;p&gt;
&lt;p&gt;以上、まとめると、&lt;&#x2F;p&gt;
&lt;p&gt;Linpackの性能はCPUの世代間で進歩があり、同じ世代のCPUであれば、おおよそクロックxコア数に比例しています。&lt;&#x2F;p&gt;
&lt;p&gt;また、kvmの仮想マシンは総じて優秀であるが、NUMAアーキテクチャのホストでホストのCPUと同じくらいのCPUをゲストに割り当てようとすると、性能は総クロックで期待されるよりも落ちてしまう。&lt;&#x2F;p&gt;
&lt;p&gt;xenserverはあまり、優秀ではありません。&lt;&#x2F;p&gt;
&lt;p&gt;SakuraのVPSもあまり優秀ではありません。&lt;&#x2F;p&gt;
&lt;p&gt;性能を求めるなら、最新の物理サーバを用いるのがおすすめで、仮想マシンを使いたいなら、VPSサービスではなく、自前でkvmによる仮想環境作るのが良いと言えるでしょう。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>KVMのゲストマシンとさくらのVPSでUnixBench採ってみました</title>
        <published>2013-05-09T00:00:00+00:00</published>
        <updated>2013-05-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/05/kvmvpsunixbench.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/05/kvmvpsunixbench.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/05/kvmvpsunixbench.html/">&lt;p&gt;みなさん、こんにちは(^^)&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;楽しかったゴールデンウィークも終わってしましたが、いかがお過ごしでしょうか？&lt;&#x2F;p&gt;
&lt;p&gt;私はというと、行楽日和の晴天を横目に、薄暗い事務所の中でコンピューターに向かって黙々と仕事をこなす毎日ですw&lt;&#x2F;p&gt;
&lt;p&gt;さて、仕事でUnixBenchを採る機会がありましたので、個人的な備忘録の意味も含め、ここに記録して(晒して)おきたいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;UnixBenchは以下のページから取ってきます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;byte-unixbench&#x2F;&quot;&gt;https:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;byte-unixbench&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;wget http:&#x2F;&#x2F;byte-unixbench.googlecode.com&#x2F;files&#x2F;UnixBench5.1.3.tgz&lt;&#x2F;p&gt;
&lt;p&gt;tar xvf UnixBench5.1.3.tgz&lt;&#x2F;p&gt;
&lt;p&gt;cd UnixBench&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;USAGEをざっと眺めると、makeして.&#x2F;Runスクリプトを実行すれば用意されたすべてのテストが実行されるらしいです。&lt;&#x2F;p&gt;
&lt;p&gt;バージョン5.1から新しく用意されたGRAPHICテストを実行したい場合には、Makefileを編集し&quot;GRAPHIC_TESTS = defined&quot;の行を有効にしてmakeする必要がありますが、今回は不要です。 &lt;&#x2F;p&gt;
&lt;p&gt;CPUが二つ以上のシステムの場合、テストは二回実行されます。一回目は一セットのテストが同時実行され、二回目はCPUの数をNとすると、Nセットのテストが並列に同時実行されます。 &lt;&#x2F;p&gt;
&lt;p&gt;テストの実行時間は一セットおよそ29分で、マルチCPUマシン上で、GRAPHICテストを行わない場合、およそ、58分程度かかるということです。&lt;&#x2F;p&gt;
&lt;p&gt;今回UnixBenchを実行したのは以下のマシンです。&lt;&#x2F;p&gt;
&lt;p&gt;(1)さくらのVPS512@980円　&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CPU  Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz　x 2&lt;&#x2F;p&gt;
&lt;p&gt;メモリー　1GByte&lt;&#x2F;p&gt;
&lt;p&gt;OS Debian 6.0.7 Kernel 2.6.32 SMP x86_64&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(2)内製KVMゲストマシン1　(ホストCPU　Xeon X5650 @ 2.67GHz)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CPU   QEMU Virtual CPU version 1.0 2.67GHz x 2&lt;&#x2F;p&gt;
&lt;p&gt;メモリー 512MByte&lt;&#x2F;p&gt;
&lt;p&gt;OS Debian 7.0 Kernel 3.9.1 SMP x86_64&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(3)内製KVMゲストマシン2　(ホストCPU　Xeon X3440  @ 2.53GHz)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CPU   QEMU Virtual CPU version 1.0 2.52GHz x 2&lt;&#x2F;p&gt;
&lt;p&gt;メモリー 512MByte&lt;&#x2F;p&gt;
&lt;p&gt;OS Debian 7.0 Kernel 3.8.8 SMP x86_64&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(4)(3)のホストマシン　&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CPU   Intel(R) Xeon(R) CPU  X3440  @ 2.53GHz　4core 8thread&lt;&#x2F;p&gt;
&lt;p&gt;メモリー 4GByte&lt;&#x2F;p&gt;
&lt;p&gt;OS Debian 6.0.7 Kernel 3.4.0 SMP x86_64&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(1)さくらのVPS512の結果&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;BYTE UNIX Benchmarks (Version 5.1.3)&lt;&#x2F;p&gt;
&lt;p&gt;System: sak1: GNU&#x2F;Linux
OS: GNU&#x2F;Linux -- 2.6.32-5-amd64 -- #1 SMP Mon Jan 9 20:49:59 UTC 2012
Machine: x86_64 (unknown)
Language: en_US.utf8 (charmap=&quot;ANSI_X3.4-1968&quot;, collate=&quot;ANSI_X3.4-1968&quot;)
CPU 0: Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz (5320.2 bogomips)
x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET
CPU 1: Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz (5320.2 bogomips)
x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET
13:48:04 up 146 days, 11:37,  1 user,  load average: 0.22, 0.12, 0.04; runlevel&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Benchmark Run: Wed May 08 2013 13:48:04 - 14:16:18
2 CPUs in system; running 1 parallel copy of tests&lt;&#x2F;p&gt;
&lt;p&gt;Dhrystone 2 using register variables       24085942.4 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     3098.5 MWIPS (9.9 s, 7 samples)
Execl Throughput                               2249.6 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        671875.9 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          196527.3 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       1413265.2 KBps  (30.0 s, 2 samples)
Pipe Throughput                             1897140.7 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 287952.8 lps   (10.0 s, 7 samples)
Process Creation                               5839.1 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   5899.8 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   1365.4 lpm   (60.0 s, 2 samples)
System Call Overhead                        3301152.6 lps   (10.0 s, 7 samples)&lt;&#x2F;p&gt;
&lt;p&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   24085942.4   2063.9
Double-Precision Whetstone                       55.0       3098.5    563.4
Execl Throughput                                 43.0       2249.6    523.2
File Copy 1024 bufsize 2000 maxblocks          3960.0     671875.9   1696.7
File Copy 256 bufsize 500 maxblocks            1655.0     196527.3   1187.5
File Copy 4096 bufsize 8000 maxblocks          5800.0    1413265.2   2436.7
Pipe Throughput                               12440.0    1897140.7   1525.0
Pipe-based Context Switching                   4000.0     287952.8    719.9
Process Creation                                126.0       5839.1    463.4
Shell Scripts (1 concurrent)                     42.4       5899.8   1391.5
Shell Scripts (8 concurrent)                      6.0       1365.4   2275.7
System Call Overhead                          15000.0    3301152.6   2200.8
========
System Benchmarks Index Score                                        1217.3&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Benchmark Run: Wed May 08 2013 14:16:18 - 14:44:33
2 CPUs in system; running 2 parallel copies of tests&lt;&#x2F;p&gt;
&lt;p&gt;Dhrystone 2 using register variables       48543864.7 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     6093.3 MWIPS (10.0 s, 7 samples)
Execl Throughput                               6641.9 lps   (29.6 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        775102.5 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          214100.7 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       2170934.3 KBps  (30.0 s, 2 samples)
Pipe Throughput                             3701877.8 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 603992.9 lps   (10.0 s, 7 samples)
Process Creation                              21862.8 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                  10135.8 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   1410.2 lpm   (60.0 s, 2 samples)
System Call Overhead                        5432476.9 lps   (10.0 s, 7 samples)&lt;&#x2F;p&gt;
&lt;p&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   48543864.7   4159.7
Double-Precision Whetstone                       55.0       6093.3   1107.9
Execl Throughput                                 43.0       6641.9   1544.6
File Copy 1024 bufsize 2000 maxblocks          3960.0     775102.5   1957.3
File Copy 256 bufsize 500 maxblocks            1655.0     214100.7   1293.7
File Copy 4096 bufsize 8000 maxblocks          5800.0    2170934.3   3743.0
Pipe Throughput                               12440.0    3701877.8   2975.8
Pipe-based Context Switching                   4000.0     603992.9   1510.0
Process Creation                                126.0      21862.8   1735.1
Shell Scripts (1 concurrent)                     42.4      10135.8   2390.5
Shell Scripts (8 concurrent)                      6.0       1410.2   2350.3
System Call Overhead                          15000.0    5432476.9   3621.7
========
System Benchmarks Index Score                                        2166.7&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(2)内製KVMゲストマシン1　(ホストCPU　Xeon X5650 @ 2.67GHz)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BYTE UNIX Benchmarks (Version 5.1.3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   System: v147: GNU&#x2F;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   OS: GNU&#x2F;Linux -- 3.9.1-64kvmg01 -- #1 SMP Wed May 8 22:00:45 JST 2013&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Machine: x86_64 (unknown)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Language: en_US.utf8 (charmap=&amp;quot;ANSI_X3.4-1968&amp;quot;, collate=&amp;quot;ANSI_X3.4-1968&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 0: QEMU Virtual CPU version 1.0 (5333.3 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 1: QEMU Virtual CPU version 1.0 (5333.3 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   15:34:32 up 0 min,  1 user,  load average: 0.16, 0.03, 0.01; runlevel 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark Run: Thu May 09 2013 15:34:32 - 16:02:31&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 CPUs in system; running 1 parallel copy of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables       30879094.2 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                     3749.0 MWIPS (9.1 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                               4534.2 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks       1097888.6 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks          301066.2 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks       2055234.3 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                             2216106.5 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                 381391.5 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                               5417.9 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                   9541.0 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                   2040.2 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                        4035159.8 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables         116700.0   30879094.2   2646.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                       55.0       3749.0    681.6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                                 43.0       4534.2   1054.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks          3960.0    1097888.6   2772.4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks            1655.0     301066.2   1819.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks          5800.0    2055234.3   3543.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                               12440.0    2216106.5   1781.4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                   4000.0     381391.5    953.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                                126.0       5417.9    430.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                     42.4       9541.0   2250.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                      6.0       2040.2   3400.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                          15000.0    4035159.8   2690.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                                   ========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Score                                        1681.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark Run: Thu May 09 2013 16:02:31 - 16:30:31&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 CPUs in system; running 2 parallel copies of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables       61886737.4 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                     7438.8 MWIPS (9.1 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                               8960.8 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks       1356632.6 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks          228901.8 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks       3404779.9 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                             4411432.3 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                 792350.4 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                              29506.4 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                  16737.4 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                   2339.6 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                        6544409.1 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables         116700.0   61886737.4   5303.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                       55.0       7438.8   1352.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                                 43.0       8960.8   2083.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks          3960.0    1356632.6   3425.8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks            1655.0     228901.8   1383.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks          5800.0    3404779.9   5870.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                               12440.0    4411432.3   3546.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                   4000.0     792350.4   1980.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                                126.0      29506.4   2341.8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                     42.4      16737.4   3947.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                      6.0       2339.6   3899.4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                          15000.0    6544409.1   4362.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                                   ========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Score                                        2963.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(3)内製KVMゲストマシン2　(ホストCPU　Xeon X3440  @ 2.53GHz)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;byte-unix-benchmarks-version-5-1-3-system-v153-gnu-linuxos-gnu-linux-3-8-8-64kvmg01-1-smp-mon-apr-22-23-44-25-jst-2013machine-x86-64-unknown-language-en-us-utf8-charmap-ansi-x3-4-1968-collate-ansi-x3-4-1968-cpu-0-qemu-virtual-cpu-version-1-4-1-5066-6-bogomips-x86-64-mmx-physical-address-ext-sysenter-sysexit-syscall-sysretcpu-1-qemu-virtual-cpu-version-1-4-1-5066-6-bogomips-x86-64-mmx-physical-address-ext-sysenter-sysexit-syscall-sysret04-21-48-up-2-min-2-users-load-average-0-06-0-02-0-01-runlevel-2&quot;&gt;BYTE UNIX Benchmarks (Version 5.1.3)
System: v153: GNU&#x2F;Linux
OS: GNU&#x2F;Linux -- 3.8.8-64kvmg01 -- #1 SMP Mon Apr 22 23:44:25 JST 2013
Machine: x86_64 (unknown)
Language: en_US.utf8 (charmap=&quot;ANSI_X3.4-1968&quot;, collate=&quot;ANSI_X3.4-1968&quot;)
CPU 0: QEMU Virtual CPU version 1.4.1 (5066.6 bogomips)
x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET
CPU 1: QEMU Virtual CPU version 1.4.1 (5066.6 bogomips)
x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET
04:21:48 up 2 min,  2 users,  load average: 0.06, 0.02, 0.01; runlevel 2&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;benchmark-run-fri-may-10-2013-04-21-48-04-49-562-cpus-in-system-running-1-parallel-copy-of-testsdhrystone-2-using-register-variables-28700468-1-lps-10-0-s-7-samples-double-precision-whetstone-3603-2-mwips-10-0-s-7-samples-execl-throughput-4820-8-lps-30-0-s-2-samples-file-copy-1024-bufsize-2000-maxblocks-1136729-9-kbps-30-0-s-2-samples-file-copy-256-bufsize-500-maxblocks-313902-4-kbps-30-0-s-2-samples-file-copy-4096-bufsize-8000-maxblocks-2329713-1-kbps-30-0-s-2-samples-pipe-throughput-1937085-6-lps-10-0-s-7-samples-pipe-based-context-switching-416442-2-lps-10-0-s-7-samples-process-creation-4905-0-lps-30-0-s-2-samples-shell-scripts-1-concurrent-5206-7-lpm-60-0-s-2-samples-shell-scripts-8-concurrent-2342-7-lpm-60-0-s-2-samples-system-call-overhead-3696866-5-lps-10-0-s-7-samples-system-benchmarks-index-values-baseline-result-indexdhrystone-2-using-register-variables-116700-0-28700468-1-2459-3double-precision-whetstone-55-0-3603-2-655-1execl-throughput-43-0-4820-8-1121-1file-copy-1024-bufsize-2000-maxblocks-3960-0-1136729-9-2870-5file-copy-256-bufsize-500-maxblocks-1655-0-313902-4-1896-7file-copy-4096-bufsize-8000-maxblocks-5800-0-2329713-1-4016-7pipe-throughput-12440-0-1937085-6-1557-1pipe-based-context-switching-4000-0-416442-2-1041-1process-creation-126-0-4905-0-389-3shell-scripts-1-concurrent-42-4-5206-7-1228-0shell-scripts-8-concurrent-6-0-2342-7-3904-5system-call-overhead-15000-0-3696866-5-2464-6-system-benchmarks-index-score-1606-1&quot;&gt;Benchmark Run: Fri May 10 2013 04:21:48 - 04:49:56
2 CPUs in system; running 1 parallel copy of tests
Dhrystone 2 using register variables       28700468.1 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     3603.2 MWIPS (10.0 s, 7 samples)
Execl Throughput                               4820.8 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks       1136729.9 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          313902.4 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       2329713.1 KBps  (30.0 s, 2 samples)
Pipe Throughput                             1937085.6 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 416442.2 lps   (10.0 s, 7 samples)
Process Creation                               4905.0 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   5206.7 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   2342.7 lpm   (60.0 s, 2 samples)
System Call Overhead                        3696866.5 lps   (10.0 s, 7 samples)
System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   28700468.1   2459.3
Double-Precision Whetstone                       55.0       3603.2    655.1
Execl Throughput                                 43.0       4820.8   1121.1
File Copy 1024 bufsize 2000 maxblocks          3960.0    1136729.9   2870.5
File Copy 256 bufsize 500 maxblocks            1655.0     313902.4   1896.7
File Copy 4096 bufsize 8000 maxblocks          5800.0    2329713.1   4016.7
Pipe Throughput                               12440.0    1937085.6   1557.1
Pipe-based Context Switching                   4000.0     416442.2   1041.1
Process Creation                                126.0       4905.0    389.3
Shell Scripts (1 concurrent)                     42.4       5206.7   1228.0
Shell Scripts (8 concurrent)                      6.0       2342.7   3904.5
System Call Overhead                          15000.0    3696866.5   2464.6
========
System Benchmarks Index Score                                        1606.1&lt;&#x2F;h2&gt;
&lt;p&gt;Benchmark Run: Fri May 10 2013 04:49:56 - 05:18:04
2 CPUs in system; running 2 parallel copies of tests
Dhrystone 2 using register variables       54903785.4 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     6894.6 MWIPS (10.0 s, 7 samples)
Execl Throughput                               9306.8 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks       1347898.4 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          354944.7 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       3256880.8 KBps  (30.0 s, 2 samples)
Pipe Throughput                             3680672.6 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 740043.1 lps   (10.0 s, 7 samples)
Process Creation                              34071.7 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                  17647.1 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   2415.1 lpm   (60.0 s, 2 samples)
System Call Overhead                        5929544.7 lps   (10.0 s, 7 samples)
System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   54903785.4   4704.7
Double-Precision Whetstone                       55.0       6894.6   1253.6
Execl Throughput                                 43.0       9306.8   2164.4
File Copy 1024 bufsize 2000 maxblocks          3960.0    1347898.4   3403.8
File Copy 256 bufsize 500 maxblocks            1655.0     354944.7   2144.7
File Copy 4096 bufsize 8000 maxblocks          5800.0    3256880.8   5615.3
Pipe Throughput                               12440.0    3680672.6   2958.7
Pipe-based Context Switching                   4000.0     740043.1   1850.1
Process Creation                                126.0      34071.7   2704.1
Shell Scripts (1 concurrent)                     42.4      17647.1   4162.0
Shell Scripts (8 concurrent)                      6.0       2415.1   4025.1
System Call Overhead                          15000.0    5929544.7   3953.0
========
System Benchmarks Index Score                                        2991.1&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(4)(3)のホストマシン　&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BYTE UNIX Benchmarks (Version 5.1.3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   System: kvm: GNU&#x2F;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   OS: GNU&#x2F;Linux -- 3.4.0-64kvmh01 -- #1 SMP Fri May 25 14:59:18 JST 2012&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Machine: x86_64 (unknown)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Language: en_US.utf8 (charmap=&amp;quot;ANSI_X3.4-1968&amp;quot;, collate=&amp;quot;ANSI_X3.4-1968&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 0: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 1: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 2: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 3: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 4: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 5: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 6: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   CPU 7: Intel(R) Xeon(R) CPU X3440 @ 2.53GHz (5066.2 bogomips)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER&#x2F;SYSEXIT, SYSCALL&#x2F;SYSRET, Intel virtualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   20:37:04 up 113 days,  7:51,  2 users,  load average: 0.50, 0.22, 0.52; runlevel 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark Run: Thu May 09 2013 20:37:04 - 21:05:17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 CPUs in system; running 1 parallel copy of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables       28301315.7 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                     3470.1 MWIPS (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                               1569.0 lps   (29.9 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks        841958.4 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks          235274.3 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks       1938405.5 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                             1827474.3 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                  54481.2 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                               3844.0 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                   3859.0 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                   2910.4 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                        3240538.1 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables         116700.0   28301315.7   2425.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                       55.0       3470.1    630.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                                 43.0       1569.0    364.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks          3960.0     841958.4   2126.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks            1655.0     235274.3   1421.6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks          5800.0    1938405.5   3342.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                               12440.0    1827474.3   1469.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                   4000.0      54481.2    136.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                                126.0       3844.0    305.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                     42.4       3859.0    910.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                      6.0       2910.4   4850.6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                          15000.0    3240538.1   2160.4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                                   ========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Score                                        1104.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark Run: Thu May 09 2013 21:05:17 - 21:33:41&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 CPUs in system; running 8 parallel copies of tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables      110467624.7 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                    21211.4 MWIPS (9.9 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                              12952.9 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks        495833.5 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks          134897.1 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks       1547822.4 KBps  (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                             2276741.3 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                 455844.3 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                              30000.0 lps   (30.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                  28230.5 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                   3724.5 lpm   (60.0 s, 2 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                        3454619.9 lps   (10.0 s, 7 samples)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Values               BASELINE       RESULT    INDEX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dhrystone 2 using register variables         116700.0  110467624.7   9465.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Double-Precision Whetstone                       55.0      21211.4   3856.6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Execl Throughput                                 43.0      12952.9   3012.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 1024 bufsize 2000 maxblocks          3960.0     495833.5   1252.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 256 bufsize 500 maxblocks            1655.0     134897.1    815.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;File Copy 4096 bufsize 8000 maxblocks          5800.0    1547822.4   2668.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe Throughput                               12440.0    2276741.3   1830.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pipe-based Context Switching                   4000.0     455844.3   1139.6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process Creation                                126.0      30000.0   2381.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (1 concurrent)                     42.4      28230.5   6658.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell Scripts (8 concurrent)                      6.0       3724.5   6207.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Call Overhead                          15000.0    3454619.9   2303.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                                   ========&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;System Benchmarks Index Score                                        2686.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以上の結果を見ると、CPU8個のサーバより、2CPUの仮想マシンゲストの方が最終スコアが高かったり、FileCopy関連のインデックスが仮想マシンの方が軒並み高かったり、理解に苦しむ結果が出ています。&lt;&#x2F;p&gt;
&lt;p&gt;今後、別のベンチマークツールで試してみたいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;追記　System Benchmarks Index Scoreではなく、個別のテストごとに比較すべきか。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>出荷を待つサーバたち</title>
        <published>2013-04-03T00:00:00+00:00</published>
        <updated>2013-04-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/04/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/04/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/04/blog-post.html/">&lt;p&gt;出荷前テスト中のサーバたちです。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;04&#x2F;blog-post.html&#x2F;image&#x2F;IMG_2779.JPG&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;
&lt;p&gt;サーバの組上げ後、一日から二日かけて、様々な動作チェック、メモリテストや負荷テストなどを行い、お客様の元へお届けしています。パーツに初期不良がある場合、通常、この段階で発覚します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;04&#x2F;blog-post.html&#x2F;image&#x2F;IMG_2775.JPG&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;
&lt;p&gt;今回のサーバは、デュアルXeon E5-2650、メモリー96GB、LSI 9266-8i、Intel 520 SSD という非常に高性能な構成です。&lt;&#x2F;p&gt;
&lt;p&gt;お客様の元で、DBサーバとして大活躍することを期待しております。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>CentOSをネットワークインストールしてみる</title>
        <published>2013-01-10T00:00:00+00:00</published>
        <updated>2013-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2013/01/centos.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2013/01/centos.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2013/01/centos.html/">&lt;p&gt;みなさんこんにちは！&lt;&#x2F;p&gt;
&lt;p&gt;ここ2、3年、OSのインストールも自分でやらなくなってしまった気がしますが、とあるサーバーにCentOS 6.3をインストールすることになりました。備忘録的に記録を書いておこうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;CentOSのダウンロードサイトは、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.centos.org&#x2F;modules&#x2F;tinycontent&#x2F;index.php?id=30&quot;&gt;この辺り&lt;&#x2F;a&gt;にリスト化されているので、この中のどれかから持ってくれば良さそうです。&lt;&#x2F;p&gt;
&lt;p&gt;今回、linuxカーネルダウンロードでおなじみの&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mirrors.kernel.org&#x2F;centos&#x2F;&quot;&gt;kernel.orgのサイト&lt;&#x2F;a&gt;からダウンロードして来ようと思います。&lt;&#x2F;p&gt;
&lt;p&gt;ディレクトリを眺めていると、&#x2F;centos&#x2F;6.3&#x2F;os&#x2F;x86_64&#x2F;images&#x2F;pxeboot にネットワークインストールに必要なカーネルとinitrdイメージが置いてあるようなので、ダウンロードしてpxeサーバに置いておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;initrd.img                    06-Jul-2012 10:13   30M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vmlinuz                       06-Jul-2012 10:13  3.8M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;それにしても、カーネルもinitrdもでかいですね…(^_^;)&lt;&#x2F;p&gt;
&lt;p&gt;pxelinux..cfg&#x2F;defaultに以下の行を追加&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;label cent63
        kernel img&#x2F;centos&#x2F;6.3-x86_64&#x2F;vmlinuz
        append vga=normal initrd=img&#x2F;centos&#x2F;6.3-x86_64&#x2F;initrd.img panic=10 text console=tty0 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;上記で指定した場所に、先ほどファイルを置いておきます。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;tree-img-centos-6-3-x86-64&quot;&gt;tree  img&#x2F;centos&#x2F;6.3-x86_64&#x2F;&lt;&#x2F;h1&gt;
&lt;p&gt;img&#x2F;centos&#x2F;6.3-x86_64&#x2F;
├── initrd.img
└── vmlinuz
0 directories, 2 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;そして対象サーバをpxebootすると、弊社のサーバでは以下の様なメニュー画面が表示されます。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_01.jpg&quot; width=&quot;400&quot; height=&quot;243&quot;&gt;
&lt;p&gt;cent63を選択すると、無事インストーラが立ち上がりました。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_02.jpg&quot; width=&quot;400&quot; height=&quot;243&quot;&gt;
&lt;p&gt;後は普通にインストールを進めます。&lt;&#x2F;p&gt;
&lt;p&gt;ネットワーク経由でインストールするので、次のメニューではURLを選択します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_03.jpg&quot; width=&quot;400&quot; height=&quot;242&quot;&gt;
&lt;p&gt;URLには、　http:&#x2F;&#x2F;mirrors.kernel.org&#x2F;centos&#x2F;6.3&#x2F;os&#x2F;x86_64&#x2F;　と入力し、OKを押します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_04.jpg&quot; width=&quot;400&quot; height=&quot;243&quot;&gt;
&lt;p&gt;すると、インストールイメージを取得します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_05.jpg&quot; width=&quot;400&quot; height=&quot;243&quot;&gt;
&lt;p&gt;その後メニューで、textモードを選択するとインストーラーが起動します。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2013&#x2F;01&#x2F;centos.html&#x2F;image&#x2F;20130110_06.jpg&quot; width=&quot;400&quot; height=&quot;243&quot;&gt;
&lt;p&gt;後は、普通にインストールすればOKです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>シングルソケット ローコスト　Intelサーバー </title>
        <published>2012-11-13T00:00:00+00:00</published>
        <updated>2012-11-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/11/intel.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/11/intel.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/11/intel.html/">&lt;p&gt;こんにちは。&lt;&#x2F;p&gt;
&lt;p&gt;Intelのローコスト、シングルソケットサーバの写真です。&lt;&#x2F;p&gt;
&lt;p&gt;固定式ＨＤＤベイが4つ、奥行きも短くシンプルなサーバです。&lt;&#x2F;p&gt;
&lt;p&gt;WEBサーバやＬｉｎｕｘルータ用にいかがでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;clustcom.com&#x2F;-mainmenu-34&#x2F;204--ez1ui-e31270ssd&quot;&gt;製品紹介ページ&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;11&#x2F;intel.html&#x2F;image&#x2F;IMG_2113_2.jpg&quot; width=&quot;320&quot; height=&quot;242&quot;&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;11&#x2F;intel.html&#x2F;image&#x2F;IMG_2104.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>iodrive2入荷しました</title>
        <published>2012-10-05T00:00:00+00:00</published>
        <updated>2012-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/10/iodrive2.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/10/iodrive2.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/10/iodrive2.html/">&lt;p&gt;FusionIOが製造しているpci expressタイプのフラッシュストレージiodrive2が入荷しました。&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.fusionio.com&#x2F;platforms&#x2F;iodrive2&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.fusionio.com&#x2F;platforms&#x2F;iodrive2&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;10&#x2F;iodrive2.html&#x2F;image&#x2F;IMG_2037.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;SSD等のフラッシュメモリを利用したデバイスの登場により、人気のWEBサイト、ゲームサイトなどでボトルネックになりがちだった、データベースサーバが革新的に高速になるようです。&lt;&#x2F;p&gt;
&lt;p&gt;512ByteのランダムIO性能(IOPS)は、Readが143k、Writeが535kだそうです。　バンド幅に換算すると、それぞれ71.5MB&#x2F;sec、267.5MB&#x2F;secと、驚異的な性能です。&lt;&#x2F;p&gt;
&lt;p&gt;弊社ではFusionIOのiodriveシリーズを搭載可能なサーバを扱っております。&lt;&#x2F;p&gt;
&lt;p&gt;今回は、下の写真のようなサーバに組み込んで出荷しました。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;10&#x2F;iodrive2.html&#x2F;image&#x2F;IMG_2041.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ブログ</title>
        <published>2012-07-06T00:00:00+00:00</published>
        <updated>2012-07-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/07/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/07/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/07/blog-post.html/">&lt;p&gt;構えて文章を書こうとするので、なかなか記事が書けない。下書きに未完の記事がいくつかたまっていて、旬を過ぎてしまったものもちらほら…&lt;&#x2F;p&gt;
&lt;p&gt;そういう意味では、構えずに書けるマイクロブログ、Twitterの登場は革命的だったのだけど、人の言動が気になってしまうのと、ソーシャル的なやり取りが面倒くさい。&lt;&#x2F;p&gt;
&lt;p&gt;非ソーシャルなつぶやきとして、書いて行こうかな…&lt;&#x2F;p&gt;
&lt;p&gt;この投稿もたいした結論が無いので、公開をためらっているナウ&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>KVM用のマシンの引越し</title>
        <published>2012-05-29T00:00:00+00:00</published>
        <updated>2012-05-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/05/kvm.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/05/kvm.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/05/kvm.html/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;2012_02_01_archive.html&quot;&gt;先日立ち上げたKVM用のマシン&lt;&#x2F;a&gt;ですが、同じ機種のwindows serverマシンが故障で起動不能になってしまったため、代替機として使用することになってしまいました。そこで、弊社で過去に販売していたIntel製の1Uサーバに引っ越すことにしました。&lt;&#x2F;p&gt;
&lt;p&gt;スペックは&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU: Intel QuadCore Xeon X3440, 2.53GHz, cache 8 MB　&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MEM: DDR2 800MHz ECC Unbuffered 2GB x2　&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;HDD: Seagate ST3320613AS 320GB SATA　&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NIC: Intel 82574L &#x2F; 82578DM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;と、メモリが若干少ないですが、なかなか素敵なサーバです。メモリは機会を見て増設することにします。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;05&#x2F;kvm.html&#x2F;image&#x2F;IMG_2028.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;05&#x2F;kvm.html&#x2F;image&#x2F;IMG_2030.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;ちなみに、このサーバの後継機種は&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.clustcom.com&#x2F;-mainmenu-34&#x2F;205--ez1ui-e31270&quot;&gt;こちら&lt;&#x2F;a&gt;になります。最新のIntel Xeon E3-12xx v2(Ivybridge)シリーズのプロセッサを搭載していて大変コストパフォーマンスに優れています。&lt;&#x2F;p&gt;
&lt;p&gt;引越し作業は次の様にしました。まず、HDDを載せ替えてブートしてみます。ネットワークが認識しなかったので、ホストカーネルをコンパイルし直しe1000eを有効にしました。&lt;&#x2F;p&gt;
&lt;p&gt;このマシンのKVM環境、前回のブログを書いてからそのまま放置していたので、まだ完成していません。&lt;&#x2F;p&gt;
&lt;p&gt;近いうちにちゃんと使えるようにしておきたいと思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>10GBaseTとSFP+DACの比較</title>
        <published>2012-05-14T00:00:00+00:00</published>
        <updated>2012-05-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/05/10gbasetsfpdac.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/05/10gbasetsfpdac.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/05/10gbasetsfpdac.html/">&lt;p&gt;タイトルの件について調べ物をしたので、メモ。&lt;&#x2F;p&gt;
&lt;p&gt;レイテンシ&lt;&#x2F;p&gt;
&lt;p&gt;10GBaseTの規格ではエラー無くデータを転送するために、ブロックエンコーディングを行う。そのためには、ブロックサイズ分のデータを送信PHYに読み込み、エンコーディングを行ったのち、送信することが必要である。受信側では、その反対が必要である。規格によると、送受信PHYのペアで2.56μsの遅延を許容している。ブロックデータのサイズを考慮に入れると、リンクあたり2μs以下にすることは不可能である。&lt;&#x2F;p&gt;
&lt;p&gt;SFP+の場合には、ブロックエンコーディングが無く、より単純なエレクトロニクス構成であるため、遅延は典型値で300ns程度である。&lt;&#x2F;p&gt;
&lt;p&gt;それぞれの場合に、さらにメディア遅延を考慮する必用があるが、光であれ電気信号であれ、およそ5ns&#x2F;m程度である。&lt;&#x2F;p&gt;
&lt;p&gt;最大ケーブル長&lt;&#x2F;p&gt;
&lt;p&gt;10GBaseTの場合、Cat6AまたはCat7ケーブルの利用により、100mまで通信可能である。&lt;&#x2F;p&gt;
&lt;p&gt;パッチパネルも使用可能である。&lt;&#x2F;p&gt;
&lt;p&gt;ダイレクトアタッチケーブルの場合、8.5mまでである。&lt;&#x2F;p&gt;
&lt;p&gt;25mまで大丈夫なケーブルも提案されている。&lt;&#x2F;p&gt;
&lt;p&gt;消費電力&lt;&#x2F;p&gt;
&lt;p&gt;10GBaseTは4W-6W&#x2F;port(片側)&lt;&#x2F;p&gt;
&lt;p&gt;SFP+DACは1.5W&#x2F;port(片側)&lt;&#x2F;p&gt;
&lt;p&gt;ソースは以下のホワイトペーパー&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.missioncriticalmagazine.com&#x2F;ext&#x2F;resources&#x2F;MC&#x2F;Home&#x2F;Files&#x2F;PDFs&#x2F;WP_Blade_Ethernet_Cabling.pdf&quot;&gt;http:&#x2F;&#x2F;www.missioncriticalmagazine.com&#x2F;ext&#x2F;resources&#x2F;MC&#x2F;Home&#x2F;Files&#x2F;PDFs&#x2F;WP_Blade_Ethernet_Cabling.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;HPCなどの分野では遅延が少ない方が良いので、SFP+DACの方がお勧めということらしい。&lt;&#x2F;p&gt;
&lt;p&gt;Webやゲームのデータセンター用途で、2.6µsの遅延が問題になるのか、気になるところ。&lt;&#x2F;p&gt;
&lt;p&gt;ちなみにアリスタの10Gスイッチの遅延は、以下のサイトによると10GBaseTで3-3.6µs、SFP+で0.8-1.15µsである。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050t&quot;&gt;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050t&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050s&quot;&gt;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050s&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intel 10GBaseT NICのドライバ</title>
        <published>2012-05-14T00:00:00+00:00</published>
        <updated>2012-05-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/05/intel-10gbaset-nic.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/05/intel-10gbaset-nic.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/05/intel-10gbaset-nic.html/">&lt;p&gt;linuxでは、Intel の10G NIC X540はixgbeでサポートされるようだ。&lt;&#x2F;p&gt;
&lt;p&gt;Device 8086:1528&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pci-ids.ucw.cz&#x2F;read&#x2F;PC&#x2F;8086&#x2F;1528&quot;&gt;http:&#x2F;&#x2F;pci-ids.ucw.cz&#x2F;read&#x2F;PC&#x2F;8086&#x2F;1528&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;2.6.38からサポートされている&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kernelnewbies.org&#x2F;Linux_2_6_38-DriversArch&quot;&gt;http:&#x2F;&#x2F;kernelnewbies.org&#x2F;Linux_2_6_38-DriversArch&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;drivers&#x2F;net&#x2F;ethernet&#x2F;intel&#x2F;ixgbe&#x2F;ixgbe_x540.c&lt;&#x2F;p&gt;
&lt;p&gt;バニラカーネルであれば使えそう。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>10GBaseTイーサネットに関して調べ物</title>
        <published>2012-05-10T00:00:00+00:00</published>
        <updated>2012-05-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/05/10gbaset.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/05/10gbaset.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/05/10gbaset.html/">&lt;p&gt;10GbeのインターフェイスにはCX4、SFP+ファイバー、SFP+ダイレクトアタッチカッパー(DAC)、10GBaseTなどがある。&lt;&#x2F;p&gt;
&lt;p&gt;CX4&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;古い技術で、ケーブルの太さやコネクタの大きさなどから、高集積化には向かない。ケーブル長15mまで。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;SFP+ファイバー　10GBase-SR&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;高価である&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;低消費電力、ケーブル長300mまで。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバにネットワークカードの増設が必用。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;SFP+DAC&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;比較的安価である。ケーブル長は7mまで。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバにネットワークカードの増設が必用。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;10GBaseT&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安価である。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;従来、消費電力が大きく、高コストであると思われていたが、最近のプロセステクノロジーによりそうでもなくなった。NICの消費電力が初期の25W&#x2F;portから6W&#x2F;portに低下した。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;1000BaseTイーサネット環境とポート互換性がある。1ギガビットのNICを持つサーバを10GBaseTのスイッチに接続でき、10GBaseTのNICを持つサーバを1ギガのスイッチに接続することができる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;サーバにネットワークカードの増設が必用。10GBaseTポートが搭載されたマザーが出始めている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;レイテンシー2μs～4μs。HPCユーザや高頻度な金融取引の用途では、気になるかもしれない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;普通はCPUの割り込み負荷低減のために、Interrupt Moderationが使われ、その場合には～100μsのレイテンシーが意図的に追加されるので問題ない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以上、Intelのホワイトペーパーより&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;network-adapters&#x2F;10-gigabit-network-adapters&#x2F;10-gigabit-ethernet-10gbase-t-paper.html&quot;&gt;http:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;network-adapters&#x2F;10-gigabit-network-adapters&#x2F;10-gigabit-ethernet-10gbase-t-paper.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;10GBaseTポート標準搭載のサーバの例&lt;&#x2F;p&gt;
&lt;p&gt;Supermicro 1027R-WRFT+&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.supermicro.com&#x2F;products&#x2F;system&#x2F;1U&#x2F;1027&#x2F;SYS-1027R-WRFT_.cfm&quot;&gt;http:&#x2F;&#x2F;www.supermicro.com&#x2F;products&#x2F;system&#x2F;1U&#x2F;1027&#x2F;SYS-1027R-WRFT_.cfm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Supermicro 6017R-N3RFT+&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.supermicro.com&#x2F;products&#x2F;system&#x2F;1U&#x2F;6017&#x2F;SYS-6017R-N3RFT_.cfm&quot;&gt;http:&#x2F;&#x2F;www.supermicro.com&#x2F;products&#x2F;system&#x2F;1U&#x2F;6017&#x2F;SYS-6017R-N3RFT_.cfm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;10GBaseT x 48ポートスイッチ&lt;&#x2F;p&gt;
&lt;p&gt;Arista 7050T-52&#x2F;7050T-64&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050t&quot;&gt;http:&#x2F;&#x2F;www.aristanetworks.com&#x2F;jp&#x2F;products&#x2F;7050series&#x2F;7050t&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;いずれも弊社から、販売可能です！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>10ギガビットイーサネット</title>
        <published>2012-05-08T00:00:00+00:00</published>
        <updated>2012-05-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/05/10.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/05/10.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/05/10.html/">&lt;p&gt;そろそろ、10ギガビットイーサネットの時代に入ってきました。&lt;&#x2F;p&gt;
&lt;p&gt;データセンター向けのハイエンドソリューションやHPC向けの高速ネットワーク用途では、10ギガビットのソリューションは数年前から利用されてきたようです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、数ある10ギガの規格のうちどれがが標準になるか見極めるのが難しく、機器も高価で、なかなか導入が広まらない状況にあったと思います。&lt;&#x2F;p&gt;
&lt;p&gt;最近になって、SFP+ Direct Attach ケーブルを利用したソリューションや、10GBaseTソリューションで、比較的安価な製品が出始めています。&lt;&#x2F;p&gt;
&lt;p&gt;今年は、一気に10ギガビットイーサネットのソリューションが普及するのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;弊社では、10GBaseT デュアルポートをオンボード搭載したサーバ、Arista Networks社の10GBaseTスイッチなどを、販売していきたいと思います。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intel SSD 520 240GB 購入しました</title>
        <published>2012-04-14T00:00:00+00:00</published>
        <updated>2012-04-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/04/intel-ssd-520-240gb.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/04/intel-ssd-520-240gb.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/04/intel-ssd-520-240gb.html/">&lt;p&gt;先日発売されたIntel 520 SSDを購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;インターフェースはSATA 6Gb&#x2F;s、カタログスペックはシーケンシャルリード 550MB&#x2F;s、シーケンシャルライト 520MB&#x2F;s、4KB Random Read 50,000 IOPS、4KB Random Write 80,000 IOPSと大変高性能です。またMTBFは1,200,000時間でニアラインクラスのHDDと同等の信頼性です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;img src=&quot;&#x2F;2012&#x2F;04&#x2F;intel-ssd-520-240gb.html&#x2F;image&#x2F;IMG_1885.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Intelのカッコいい箱はCPU等と同様のカラーリング。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;img src=&quot;&#x2F;2012&#x2F;04&#x2F;intel-ssd-520-240gb.html&#x2F;image&#x2F;IMG_1891.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;同梱物の写真 SSD本体、3.5インチマウンター、CD、説明書、シール、 電源ケーブル、SATAケーブル、ネジが同梱されています。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;img src=&quot;&#x2F;2012&#x2F;04&#x2F;intel-ssd-520-240gb.html&#x2F;image&#x2F;IMG_1895.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3.5インチマウンタ。通常の電源ケーブルとSATAケーブルを利用する。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;img src=&quot;&#x2F;2012&#x2F;04&#x2F;intel-ssd-520-240gb.html&#x2F;image&#x2F;IMG_1892.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SSD本体&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;img src=&quot;&#x2F;2012&#x2F;04&#x2F;intel-ssd-520-240gb.html&#x2F;image&#x2F;IMG_1896.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;カッコいいシールはパソコンに貼るも善し。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Raidカードに8本ぶら下げたら、FusionIOなんかよりもお得かも知れないですね。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Kernel Virtual Machine(kvm)のセットアップ</title>
        <published>2012-02-15T00:00:00+00:00</published>
        <updated>2012-02-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/02/kvm.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/02/kvm.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/02/kvm.html/">&lt;p&gt;いくつもあるサーバを、仮想化によりまとめることができれば、サーバの保管場所や電気代の節約になる。私の会社ではいくつかのサーバを仮想マシン上で運用している。kvmによる仮想環境の再構築する機会があったので、備忘録的にノウハウというか、工夫した部分について、まとめておきたいと思う。&lt;&#x2F;p&gt;
&lt;p&gt;kvmはそれ用に構築したLinuxカーネルをハイパーバイザーとする仮想マシンである。GuestOSはWindowsやLinuxのみならず、様々なOSがサポートされている。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Guest_Support_Status&quot;&gt;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Guest_Support_Status&lt;&#x2F;a&gt;　&lt;&#x2F;p&gt;
&lt;p&gt;今回はDebianLinux上で、バニラカーネルをkvmホスト用に自前でコンパイルしたものに入れ替え、ゲストOSとしてDebianLinuxを複数動かせるようにする。ゲストOSはWEBサーバなどのネットワークサーバ用途を想定しているので、GUI機能は必要ない。したがって、コンソールログインとSSHログインが可能になれば良しとすることにした。&lt;&#x2F;p&gt;
&lt;p&gt;最近のDebianLinuxでは、おそらく標準でGUIを使ってkvmを利用可能である。しかし、仕事で使うとなると中身や仕組みをできるだけ熟知していたくもあるので、余分な機能で被われたディストリビューション標準のツールをあえて使わないことにした。&lt;&#x2F;p&gt;
&lt;p&gt;ハードウェアは、ちょっと昔のDellT105が遊んでいたので、これを使うことにした。今となってはそれほど強力なマシンではないが、4コアのAMD Opteronを搭載しており、メモリスロットも4つある。これにDDR2 ECC 2GBを4本積んで、8GBのメモリを確保した。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;02&#x2F;kvm.html&#x2F;image&#x2F;IMG_1596.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;02&#x2F;kvm.html&#x2F;image&#x2F;IMG_1605.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;&lt;strong&gt;1. ハードウェアスペック&lt;&#x2F;strong&gt;
**
**&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU: Quad-Core AMD Opteron 1352,  2.1GHz, cache 512 KB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MEM: DDR2 800MHz ECC Unbuffered 4GB x8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;HDD: Seagate ST3320613AS 320GB SATA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NIC: Broadcom NetXtreme BCM5722&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;kvmで仮想マシンを作る場合、IntelのCPUであればIntel VT、AMDのCPUであればAMD-Vに対応している必要がある。CPUのそれらの仮想化支援機能が無ければただの低速エミュレーターになってしまう。&lt;&#x2F;p&gt;
&lt;p&gt;CPUにそれらの機能が備わっているかどうかはメーカーのサイトで確認してもいいし、Linuxが既に動いている実機上で、以下のように確認しても良い。&lt;&#x2F;p&gt;
&lt;p&gt;AMDのマシンであれば、&#x2F;proc&#x2F;cpuinfoのflagsを見て、svmというのがあれば良い。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# egrep flags &#x2F;proc&#x2F;cpuinfo |head -n 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags  : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fxsr_opt pdpe1gb rdtscp lm 3dnowext 3dnow constant_tsc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rep_good nopl nonstop_tsc extd_apicid pni monitor cx16 popcnt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3dnowprefetch osvw ibs npt lbrv svm_lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Intelのマシンの場合、vmxというのがあれば良い。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ktaka@hana:~$ egrep flags &#x2F;proc&#x2F;cpuinfo |head -n 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;flags  : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bts rep_good nopl xtopology nonstop_tsc aperfmperf pni&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pdcm pcid dca sse4_1 sse4_2 popcnt aes lahf_lm ida arat epb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dts tpr_shadow vnmi flexpriority ept vpid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;**
**&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. ホストカーネルの構築&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;カーネルはkernel.orgにあるlinux-3.2.9をコンパイルして利用する。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Tuning_Kernel&quot;&gt;このページ&lt;&#x2F;a&gt;にKVMのホストカーネルの構築に必要なコンパイルフラグがまとめてあるので、これを参考にカーネルを構築した。実際には以下の関連フラグを有効にした。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUPS=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_DEBUG=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_FREEZER=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_DEVICE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_CPUACCT=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_MEM_RES_CTLR=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_PERF=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_CGROUP_SCHED=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_BLK_CGROUP=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_DEBUG_BLK_CGROUP=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HIGH_RES_TIMERS=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HPET_TIMER=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HPET_EMULATE_RTC=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_COMPACTION=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_MIGRATION=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KSM=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HPET=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HPET_MMAP=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HAVE_KVM=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HAVE_KVM_IRQCHIP=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HAVE_KVM_EVENTFD=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_APIC_ARCHITECTURE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_MMIO=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_ASYNC_PF=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTUALIZATION=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_INTEL=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_AMD=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_MMU_AUDIT=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VHOST_NET=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;KVMホスト上でブリッジネットワークを利用するために必要な以下のフラグも有効にした。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_BRIDGE_NETFILTER=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_BRIDGE=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_BRIDGE_IGMP_SNOOPING=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_STP=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_LLC=m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;カーネルコンパイル&amp;amp;インストール後、新規カーネルでブートしバージョン確認&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# uname  -a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Linux kvm 3.2.9-64kvmh01 #1 SMP Mon Mar 5 21:47:42 JST 2012&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x86_64 GNU&#x2F;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;関連モジュールの確認&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# lsmod |egrep &amp;quot;kvm|bridge&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;kvm_amd                71505  0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;kvm                   566158  1 kvm_amd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bridge                125971  0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stp                     2987  1 bridge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;llc                     8862  2 bridge,stp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;3. ホストOSのネットワーク設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;kvm用のブリッジインターフェースkbr0を作成する。&lt;&#x2F;p&gt;
&lt;p&gt;以下の内容で設定ファイル&#x2F;etc&#x2F;network&#x2F;interfacesを作成する。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auto lo kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface lo inet loopback&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iface kbr0 inet static&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     bridge_ports    eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     bridge_stp      off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     bridge_maxwait  2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     address         192.168.20.9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     netmask         255.255.252.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     network         192.168.20.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     broadcast       192.168.20.255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     gateway         192.168.20.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     pre-up &#x2F;sbin&#x2F;ip link set dev eth0 up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ホストOSを再起動すると、以下の様な状態になります。&lt;&#x2F;p&gt;
&lt;p&gt;ブリッジの状態確認&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# brctl show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bridge name bridge id  STP enabled interfaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;kbr0  8000.0022190601e3 no  eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ブリッジインターフェースkbr0が作成され、eth0が接続されている。&lt;&#x2F;p&gt;
&lt;p&gt;IPアドレスの確認&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# ip add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1: lo: mtu 16436 qdisc noqueue state UNKNOWN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    link&#x2F;loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet 127.0.0.1&#x2F;8 scope host lo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2: eth0: mtu 1500 qdisc mq master kbr0 state UP qlen 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    link&#x2F;ether 00:22:19:06:01:e3 brd ff:ff:ff:ff:ff:ff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3: kbr0: mtu 1500 qdisc noqueue state UP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    link&#x2F;ether 00:22:19:06:01:e3 brd ff:ff:ff:ff:ff:ff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inet 192.168.20.9&#x2F;22 brd 192.168.20.255 scope global kbr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ブリッジインターフェースkbr0に192.168.20.9というアドレスが割り当てられている。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. qemuのコンパイル&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;kvmによる仮想マシンではLinuxハイパーバイザー上で、kvmに対応したqemuエミュレーターを動作させる。qemuエミュレータ上ではwindowsやlinuxなど、サポートされているOSをゲストOSとして起動することが可能である。&lt;&#x2F;p&gt;
&lt;p&gt;当初はkvmに対応したqemuのソースをkvmプロジェクトのサイトから取得する必要があったが、最近ではqemuの本家のソースにkvmのパッチが既にマージされている。&lt;&#x2F;p&gt;
&lt;p&gt;従って、kvmの開発の最先端のソースを利用したいと言うのでなければ、qemuの本家サイトからソースを取ってくれば良い。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;wget http:&#x2F;&#x2F;wiki.qemu.org&#x2F;download&#x2F;qemu-1.0.1.tar.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;普通にtarボールを展開して、コンパイル＆インストールする。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tar xf qemu-1.0.1.tar.gz ; cd qemu-1.0.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&#x2F;configure  --prefix=&#x2F;kvm&#x2F;qemu&#x2F;qemu-1.0.1&#x2F; --enable-kvm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;make install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tree -L 2 &#x2F;kvm&#x2F;qemu&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;kvm&#x2F;qemu&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`-- qemu-1.0.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |-- bin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |-- etc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    `-- share&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# &#x2F;kvm&#x2F;qemu&#x2F;qemu-1.0.1&#x2F;bin&#x2F;qemu-x86_64 -version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu-x86_64 version 1.0,1, Copyright (c) 2003-2008 Fabrice Bellard&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;5. ゲストOSイメージの作成&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;qemuエミュレーター上で動かすゲストLinuxOSイメージを作成する。手順は以下の通り。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;スパースなイメージファイルを作成&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ext4でファイルシステム作成&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;debootstrapでOSインストール&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ネットワークやルートパスワードの設定等々細々としたを行う&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;イメージ作成&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dd if=&#x2F;dev&#x2F;zero of=.&#x2F;kvm.img bs=1024 seek=9999999 count=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ファイルシステム作成&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkfs.ext4 kvm.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;debootstrapでDebianインストール&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mount -o loop kvm.img &#x2F;mnt&#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;debootstrap --include=openssh-server,openssh-client,\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rsync,pciutils,acpid  squeeze &#x2F;mnt&#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;その他の細々した設定&lt;&#x2F;p&gt;
&lt;p&gt;シリアルコンソール設定&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;mnt&#x2F;tmp&#x2F;etc&#x2F;inittab にttyS0の設定を加える&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;T0:23:respawn:&#x2F;sbin&#x2F;getty -L ttyS0 19200 vt100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;BIOSクロックをUTCと見做さない設定(JSTのsystem dateが終了時にBIOSに書き込まれる。仮想マシンでは関係ないかも？)&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;mnt&#x2F;tmp&#x2F;etc&#x2F;default&#x2F;rcS&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UTC=no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ネットワーク設定(DHCPでアドレスを取得するようにする。) &lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;mnt&#x2F;tmp&#x2F;etc&#x2F;network&#x2F;interfaces&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auto lo eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  iface lo inet loopback&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  iface eth0 inet dhcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;余計なudevルールの削除&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rm &#x2F;mnt&#x2F;tmp&#x2F;etc&#x2F;udev&#x2F;rules.d&#x2F;70-persistent-net.rules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;パスワード初期設定、apt-cache掃除、timezoneをJSTに。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chroot &#x2F;mnt&#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;passwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;apt-get clean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dpkg-reconfigure tzdata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;6. ゲストカーネルのコンパイル&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;kvm上で仮想マシンを動かす場合、ゲストOSは改変不要でハードウェア上で動かす場合のカーネルがそのまま動く。これはしばしば完全仮想化と呼ばれる。しかしながら、仮想マシン用のドライバを使うようにしてやることで、ゲストOSの性能を大幅に向上することが可能である。仮想マシン用のドライバを利用した方法は、しばしば準仮想化と呼ばれる。&lt;&#x2F;p&gt;
&lt;p&gt;今回も準仮想化を使いたいし、なるべく必要最小限のドライバのみを有効にした、シンプルなカーネルを使いたいので、バニラソースからカーネルをコンパイルする。&lt;&#x2F;p&gt;
&lt;p&gt;必要なコンパイルフラグは、ホストカーネルの場合と同様に&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linux-kvm.org&#x2F;page&#x2F;Tuning_Kernel&quot;&gt;このページ&lt;&#x2F;a&gt;を参考にして有効にした。結局以下の関連フラグが有効にしてある。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HOTPLUG=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_TICK_ONESHOT=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT_GUEST=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT_TIME_ACCOUNTING=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_CLOCK=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_KVM_GUEST=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT_SPINLOCKS=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT_CLOCK=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PARAVIRT_DEBUG=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_MEMORY_HOTPLUG=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_MEMORY_HOTPLUG_SPARSE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_MEMORY_HOTREMOVE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRT_TO_BUS=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HOTPLUG_CPU=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_ACPI_HOTPLUG_CPU=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_PCI_MSI=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_BLK=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_NET=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_CONSOLE=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HW_RANDOM_VIRTIO=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_RING=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_PCI=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_BALLOON=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRTIO_MMIO=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_VIRT_DRIVERS=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONFIG_HAVE_KVM=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;今回、モジュールを使わずにモノリシックなカーネルにした。コンパイルしたカーネルは、適当決めたディレクトリ&#x2F;kvm&#x2F;bootに置いた。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@kvm:~# ls -la &#x2F;kvm&#x2F;boot&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;total 8728&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x  2 root root    4096 Mar  8 03:38 .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;drwxr-xr-x 10 root root    4096 Mar  6 17:12 ..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 root root 1105677 Mar  8 03:38 System.map-3.2.9-64kvmg01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 root root   44798 Mar  8 03:38 config-3.2.9-64kvmg01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-rw-r--r--  1 root root 3152304 Mar  8 03:38 vmlinuz-3.2.9-64kvmg01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;**&lt;&#x2F;p&gt;
&lt;p&gt;**
7. ゲストOSの起動コマンド&lt;&#x2F;p&gt;
&lt;p&gt;ゲストOSはqemuエミュレーター上で動作する。ゲストOSを起動するには、qemuコマンドを適切なオプションで実行すれば良い。kvmによる仮想マシンは、ホストOS(Linuxハイパーバイザー)上からは単なるqemuプロセスに見える。従って、それぞれのゲストOSがどのくらいのCPU、メモリ等のリソースを消費しているかは、ホストOS上でqemuプロセスがどのくらいそれらのリソースを消費しているかを見れば良い。不要になったゲストOSはいざとなったら、qemuプロセスをkillコマンドでkillすることで、終了させることも可能である。(実際にはもう少し丁寧にshutdownすべきであるが。)&lt;&#x2F;p&gt;
&lt;p&gt;さて、qemuのコマンドのオプションはqemu-system-x86_64 --helpで確認することが可能である。それぞれオプションを試行錯誤し、最終的に我々にとって使い易くしたものが、以下のものである。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;kvm&#x2F;qemu&#x2F;qemu-kvm-1.0&#x2F;bin&#x2F;qemu-system-x86_64 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--enable-kvm -nographic -daemonize \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-drive file=&#x2F;kvm&#x2F;data&#x2F;kvm.img,if=virtio -m 512 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-kernel &#x2F;kvm&#x2F;boot&#x2F;vmlinuz-3.2.9-64kvmg01 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-append &amp;quot;console=ttyS0,19200n8  root=&#x2F;dev&#x2F;vda&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-net nic,vlan=0,macaddr=52:54:00:21:00:01,model=virtio \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-net tap,vlan=0,script=&#x2F;kvm&#x2F;etc&#x2F;qemu-ifup,ifname=hoge \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-serial unix:&#x2F;tmp&#x2F;con.sock,server,nowait \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-monitor unix:&#x2F;tmp&#x2F;mon.sock,server,nowait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下、それぞれのオプションについて説明する。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;--enable-kvm&lt;&#x2F;strong&gt;　Intel-VT またはAMD-Vのハードウェア仮想化支援機能を利用する&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-nographic&lt;&#x2F;strong&gt;  グラフィカルな出力を無効にし、シリアルをコンソールにリダイレクトする&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-daemonize&lt;&#x2F;strong&gt;　qemuをデーモンとして起動する&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-m 512&lt;&#x2F;strong&gt;　メモリを512MByte 割り当てる&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-smp 1&lt;&#x2F;strong&gt; 　仮想マシンにプロセッサを一つ割り当てる&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-kernel&lt;&#x2F;strong&gt;   ゲストカーネルを指定。イメージの外、ホストOS上に置くことができる&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-append&lt;&#x2F;strong&gt;  カーネルに与えるオプションを指定&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-drive&lt;&#x2F;strong&gt; &lt;strong&gt;file=&lt;&#x2F;strong&gt;　イメージファイルの指定。if=virtioオプションによりパラヴァーチャルなブロックデバイスとして見せる &lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-net nic,vlan=0,macaddr= ,model=virtio&lt;&#x2F;strong&gt;  &lt;&#x2F;p&gt;
&lt;p&gt;NICを作成しvlan=0に接続する。model=virtioオプションによりパラバーチャルなNICに見せる。 &lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-net tap,vlan=0,script=&#x2F;kvm&#x2F;etc&#x2F;qemu-ifup,ifname=hoge&lt;&#x2F;strong&gt;  &lt;&#x2F;p&gt;
&lt;p&gt;ホストにtapデバイスhogeを作成しvlan=0に接続する。そしてスクリプト&#x2F;kvm&#x2F;etc&#x2F;qemu-ifupを実行する。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-serial unix:&#x2F;tmp&#x2F;con.sock,server,nowait&lt;&#x2F;strong&gt;   シリアルポートをUNIXドメインソケット&#x2F;tmp&#x2F;con.sockにリダイレクトする。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;-monitor unix:&#x2F;tmp&#x2F;mon.sock,server,nowait&lt;&#x2F;strong&gt; &lt;&#x2F;p&gt;
&lt;p&gt;QemuのモニターをUNIXドメインソケット&#x2F;tmp&#x2F;mon.sockにリダイレクトする。&lt;&#x2F;p&gt;
&lt;p&gt;serial,monitorのUNIXドメインソケットへのリダイレクトがミソ。&lt;&#x2F;p&gt;
&lt;p&gt;nographic, daemonizeオプションによりバックグラウンドで実行している仮想マシンを&#x2F;tmp&#x2F;mon.sock、&#x2F;tmp&#x2F;con.sockから制御することが可能である。serial、monitorをtcpやtelnetなどなどのネットワーク接続口にリダイレクトすることも可能であるが、その場合、認証無しでmonitorコンソールアクセスしqemuをコントロールすることができてしまう。UNIXドメインソケットを利用する場合、rootユーザのみにUNIXドメインソケットへの読み書き許可を与えることで、ホストOS上ののrootユーザのみにアクセス許可を与えることができるようになる。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;8. script=&#x2F;kvm&#x2F;etc&#x2F;qemu-ifupで何をしているのか&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;**&lt;&#x2F;p&gt;
&lt;p&gt;**&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;kvm&#x2F;etc&#x2F;qemu-ifupの内容&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;sbin&#x2F;ip link set dev $1 up promisc off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;usr&#x2F;sbin&#x2F;brctl addif kbr0 $1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;タップデバイスhogeがブリッジkbr0に接続されている。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brctl show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bridge name     bridge id               STP enabled     interfaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;kbr0            8000.0022190601e3       no              eth0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                        hoge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;9. UNIXドメインソケットへの接続方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;socatコマンドで接続可能である。&lt;&#x2F;p&gt;
&lt;p&gt;QEMUモニタへの接続&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;socat -,icanon=0,echo=0 unix-connect:&#x2F;tmp&#x2F;mon.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QEMU 1.0,1 monitor - type &amp;#39;help&amp;#39; for more information&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(qemu)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;シリアルコンソールへの接続&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;socat -,icanon=0,echo=0 unix-connect:&#x2F;tmp&#x2F;con.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Debian GNU&#x2F;Linux 6.0 (none) ttyS0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(none) login:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ただし、このままではctl-cでシリアルコンソール内のプロセスを終了しようとしても、socat自身がグナルを受け取ってしまうので、そのプロセスを終了することができない。その様な場合には、intrなを適当なキーに割り当てると良い。&lt;&#x2F;p&gt;
&lt;p&gt;例えば、次の様なラッパスクリプトを利用することで、socatにinterruptシグナルを送る場合のキーバインディングをctl+]に変更することができる。ctl+cを叩いた場合、socat自身gはシグナルとして受け取らず、接続先のプロセスがctl+cをinterruptシグナルとして受け取ることになる。&lt;&#x2F;p&gt;
&lt;p&gt;test_con.sh&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tty_setting=`stty -g`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stty intr ^]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;socat -,icanon=0,echo=0 unix-connect:&#x2F;tmp&#x2F;con.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stty $tty_setting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;**A1. 素のqemuとkvmどのくらい速さが違うの？　**&lt;&#x2F;p&gt;
&lt;p&gt;sysbenchと言うベンチマークツールを使って、簡単にCPUベンチマークを実行してみた。&lt;&#x2F;p&gt;
&lt;p&gt;ベンチマークコマンド&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sysbench --num-threads=24 --test=cpu --cpu-max-prime=10000 run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;素のqemu　(qemu-system-x86_64 .... )&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Test execution summary:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    total time:                          58.5005s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;kvmオプション付き　(qemu-system-x86_64 &lt;strong&gt;--enable-kvm&lt;&#x2F;strong&gt; .... )&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Test execution summary:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    total time:                          17.3854s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;約3.4倍高速であった。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A2. qemu-kvmと本家qemuどちらを使うべき？(2012&#x2F;3現在)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;以前は、kvmを使うためには、それ用にパッチの当たったqemuを使う必要があったが、現在kvmサポートパッチは本家qemuにマージされている。しかしながら、wiki.qemu.org&#x2F;downloadの他にも、sourceforgeにqemu-kvmが存在している。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、sysbenchでベンチマークしてみた。&lt;&#x2F;p&gt;
&lt;p&gt;ベンチマークコマンド&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sysbench --num-threads=24 --test=cpu --cpu-max-prime=10000 run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;qemu-1.0.1の場合(--enable-kvmオプション付き)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Test execution summary:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    total time:                          17.3854s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;qemu-kvm-1.0の場合&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Test execution summary:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    total time:                          17.2720s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;大きな差は見られない。&lt;&#x2F;p&gt;
&lt;p&gt;以上、kvmによる仮想マシンの構築について、備忘録的にまとめた。&lt;&#x2F;p&gt;
&lt;p&gt;部分的であれ記載した情報がお役に立てば幸いである。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>1U 4ノードサーバ　SR1640TH</title>
        <published>2012-01-12T00:00:00+00:00</published>
        <updated>2012-01-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/01/1u-4sr1640th.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/01/1u-4sr1640th.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/01/1u-4sr1640th.html/">&lt;p&gt;Intelのクアッドノード、サーバベアボーン&lt;&#x2F;p&gt;
&lt;p&gt;Xeon X3400系ですので、ちょっと古いですが…&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-4sr1640th.html&#x2F;image&#x2F;IMG_1443.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;1Uのシャーシに電源も独立したサーバユニットが二つ。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-4sr1640th.html&#x2F;image&#x2F;IMG_1450.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;それぞれのサーバユニットにはソケットが二つ。デュアルＣＰＵサーバ一台ではなく、独立したシングルＣＰＵのサーバ二台が、一枚のマザーに載っているという構成。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-4sr1640th.html&#x2F;image&#x2F;IMG_1451.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;サーバユニットは全面から引き出し可能。メンテナンスは2ノード毎に行うことになる。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-4sr1640th.html&#x2F;image&#x2F;IMG_1454.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;ServerEnginesのBMC&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-4sr1640th.html&#x2F;image&#x2F;IMG_1445.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;サーバユニットを、シャーシの上に乗せてみました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>1U Sandy Bridge Xeon ファイルサーバ</title>
        <published>2012-01-12T00:00:00+00:00</published>
        <updated>2012-01-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2012/01/1u-sandy-bridge-xeon.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2012/01/1u-sandy-bridge-xeon.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2012/01/1u-sandy-bridge-xeon.html/">&lt;p&gt;先日、お客様に納品した1Ｕサーバのご紹介です。&lt;&#x2F;p&gt;
&lt;p&gt;1ＵシャーシにSandy Bridge Xeon　E3-1270を一個搭載しています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1500.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1498.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;フロントには2.5インチのＨＤＤベイが8個あり、SATA、SAS HDD、SSDなどを8本搭載可能です。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1510.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;マザーボードはSupermicro X8SIU-F。このマザーボードは横方向に短いため、1Uシャーシ内への拡張カードの装着が容易になります。今回は、キャパシタ付のRAIDカードASR-5805Zを装着しましたが、いつもは置き場所に困るキャパシタが、余裕で取り付けられました。PCIスロットを二つ占有する、Teslaなどにも向いているのではないかと思います。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1507.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;6本あるメモリスロットは、4Ｇbyte DDR3 ECC Reg.モジュールで、フル実装。合計24GByteのメモリを搭載しています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1505.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;ASR-5805Zは1.2GHzのデュアルコアRAIDチップを搭載しているため、比較的発熱が大きいです。十分にカードを冷却するために、FANを二つ増設しています。&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;2012&#x2F;01&#x2F;1u-sandy-bridge-xeon.html&#x2F;image&#x2F;IMG_1503.JPG&quot; width=&quot;320&quot; height=&quot;240&quot;&gt;
&lt;p&gt;今回は冗長化電源付のシャーシをご希望されました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>今日は自転車通勤</title>
        <published>2011-04-25T00:00:00+00:00</published>
        <updated>2011-04-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/blog-post.html/">&lt;p&gt;暖かくなってきたので、自転車が気持ち良い(^^)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2011&#x2F;04&#x2F;blog-post.html&#x2F;bike1.webp&quot; alt=&quot;自転車通勤1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2011&#x2F;04&#x2F;blog-post.html&#x2F;bike2.webp&quot; alt=&quot;自転車通勤2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Galaxy からBlogger アプリ</title>
        <published>2011-04-25T00:00:00+00:00</published>
        <updated>2011-04-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/galaxy-blogger.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/galaxy-blogger.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/galaxy-blogger.html/">&lt;p&gt;Galaxy からBlogger アプリを使って投稿。編集機能は不十分だが、気軽に投稿できるのは便利。写真も簡単に貼り付けることができる。&lt;&#x2F;p&gt;
&lt;p&gt;ちなみに、愛用のメガネです。&lt;&#x2F;p&gt;
&lt;!-- 元の画像（メガネの写真）はBlogger CDNから取得不可 --&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>HHKB Pro2</title>
        <published>2011-04-25T00:00:00+00:00</published>
        <updated>2011-04-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/hhkb-pro2.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/hhkb-pro2.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/hhkb-pro2.html/">&lt;p&gt;愛用のキーボードは、Happy Hacking Keyboard Professional 2です。キータッチが秀逸です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2011&#x2F;04&#x2F;hhkb-pro2.html&#x2F;hhkb.webp&quot; alt=&quot;HHKB Pro2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>rsync --updateオプションで悩む</title>
        <published>2011-04-13T00:00:00+00:00</published>
        <updated>2011-04-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/rsync-update.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/rsync-update.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/rsync-update.html/">&lt;p&gt;rsyncの--updateオプションは、転送先ファイルのmtimeが転送元よりも新しい場合に、そのファイルのコピーをスキップするオプションである。&lt;&#x2F;p&gt;
&lt;p&gt;しかしながら、シンボリックリンクやスペシャルファイルの場合は、このオプションがあっても、コピーはスキップされない。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;-u, --update&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This forces rsync to skip any files which exist on the destination  and  have  a modified  time  that is newer than the source file.  (If an existing destination file has a modification time equal to the source file’s, it will be  updated  if the sizes are different.)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note that this does not affect the copying of symlinks or other special files.&lt;&#x2F;strong&gt;  Also, a difference of file format between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects.  In other words, if the source has a directory where the destination has a file, the transfer would occur regardless of the timestamps.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;コピー先のシンボリックの方が新しい場合には、コピーをスキップしたいのだが、どうすれば良いのでしょう？&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>aufs2.1を試してみる。</title>
        <published>2011-04-09T00:00:00+00:00</published>
        <updated>2011-04-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/aufs21.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/aufs21.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/aufs21.html/">&lt;p&gt;Aufs(AnotherUnionfs)は、複数のディレクトリを単一のディレクトリに見せるスタッカブルなファイルシステムです。Aufsを用いると、リードオンリーなディレクトリの上に、読み書き専用のディレクトリを重ねてマウントすることができます。&lt;&#x2F;p&gt;
&lt;p&gt;今回、これについて試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;インストール手順&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;aufs.sourceforge.net&#x2F;&quot;&gt;http:&#x2F;&#x2F;aufs.sourceforge.net&#x2F;&lt;&#x2F;a&gt;にあるドキュメントを参考にインストールします。&lt;&#x2F;p&gt;
&lt;p&gt;レポジトリの同期とチェックアウト&lt;&#x2F;p&gt;
&lt;p&gt;今回はバニラカーネルにパッチを当てて、カーネルモジュールとしてコンパイルするので、aufs2-standalone.gitのみ同期します。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;tmp# git clone http:&#x2F;&#x2F;git.c3sl.ufpr.br&#x2F;pub&#x2F;scm&#x2F;aufs&#x2F;aufs2-standalone.git aufs2-standalone.git&lt;&#x2F;p&gt;
&lt;p&gt;Cloning into aufs2-standalone.git... &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;使用するバニラカーネルのバージョンは2.6.38.2なので、aufs2.1-38 をチェックアウトします。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;tmp# cd aufs2-standalone.git&#x2F; &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;tmp&#x2F;aufs2-standalone.git# git checkout origin&#x2F;aufs2.1-38&lt;&#x2F;p&gt;
&lt;p&gt;Note: checking out &#x27;origin&#x2F;aufs2.1-38&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;You are in &#x27;detached HEAD&#x27; state. You can look around, make experimental&lt;&#x2F;p&gt;
&lt;p&gt;changes and commit them, and you can discard any commits you make in this&lt;&#x2F;p&gt;
&lt;p&gt;state without impacting any branches by performing another checkout.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to create a new branch to retain commits you create, you may&lt;&#x2F;p&gt;
&lt;p&gt;do so (now or later) by using -b with the checkout command again. Example:&lt;&#x2F;p&gt;
&lt;p&gt;  git checkout -b new_branch_name&lt;&#x2F;p&gt;
&lt;p&gt;HEAD is now at 4c5ce8c... aufs2.1 standalone version for linux-2.6.38 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;tmp&#x2F;aufs2-standalone.git# ls -la&lt;&#x2F;p&gt;
&lt;p&gt;total 356&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 7 root root   4096 Apr  8 14:08 .&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 3 root root   4096 Apr  8 14:06 ..&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 8 root root   4096 Apr  8 14:08 .git&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root  17990 Apr  8 14:07 COPYING&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root 268285 Apr  8 14:08 ChangeLog&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 3 root root   4096 Apr  8 14:08 Documentation&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root   1365 Apr  8 14:07 Makefile&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root  14421 Apr  8 14:08 README&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root   2971 Apr  8 14:08 aufs2-base.patch&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root    978 Apr  8 14:08 aufs2-kbuild.patch&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root   8732 Apr  8 14:08 aufs2-standalone.patch&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 root root   2793 Apr  8 14:08 config.mk&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 2 root root   4096 Apr  8 14:08 design&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 3 root root   4096 Apr  8 14:08 fs&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x 3 root root   4096 Apr  8 14:07 include&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;linux-2.6.38用のパッチが作成されました。&lt;&#x2F;p&gt;
&lt;p&gt;カーネルソースディレクトリに移動し、パッチを当てます。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# patch -p1
patching file fs&#x2F;splice.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file include&#x2F;linux&#x2F;namei.h&lt;&#x2F;p&gt;
&lt;p&gt;patching file include&#x2F;linux&#x2F;splice.h&lt;&#x2F;p&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# patch -p1
patching file fs&#x2F;Kconfig&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;Makefile&lt;&#x2F;p&gt;
&lt;p&gt;patching file include&#x2F;linux&#x2F;Kbuild&lt;&#x2F;p&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# patch -p1
patching file fs&#x2F;file_table.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;inode.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;namei.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;namespace.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;notify&#x2F;group.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;notify&#x2F;mark.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;open.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file fs&#x2F;splice.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file security&#x2F;commoncap.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file security&#x2F;device_cgroup.c&lt;&#x2F;p&gt;
&lt;p&gt;patching file security&#x2F;security.c&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;必要なファイルもコピーします。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# cp -R ~&#x2F;tmp&#x2F;aufs2-standalone.git&#x2F;Documentation .&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# cp -R ~&#x2F;tmp&#x2F;aufs2-standalone.git&#x2F;fs .&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# cp -R ~&#x2F;tmp&#x2F;aufs2-standalone.git&#x2F;include&#x2F;linux&#x2F;aufs_type.h .&#x2F;include&#x2F;linux&#x2F; &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;make menuconfig で必要な設定をします。aufsに関する設定パラメータは以下の通りです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~&#x2F;Kernel&#x2F;linux-2.6.38.2# egrep AUFS .config&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_FS=m&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_BRANCH_MAX_127=y&lt;&#x2F;p&gt;
&lt;h1 id=&quot;config-aufs-branch-max-511-is-not-set&quot;&gt;CONFIG_AUFS_BRANCH_MAX_511 is not set&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;config-aufs-branch-max-1023-is-not-set&quot;&gt;CONFIG_AUFS_BRANCH_MAX_1023 is not set&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;config-aufs-branch-max-32767-is-not-set&quot;&gt;CONFIG_AUFS_BRANCH_MAX_32767 is not set&lt;&#x2F;h1&gt;
&lt;p&gt;CONFIG_AUFS_SBILIST=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_HNOTIFY=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_HFSNOTIFY=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_RDU=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_SP_IATTR=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_SHWH=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_BR_RAMFS=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_BR_FUSE=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_POLL=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_BDEV_LOOP=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_DEBUG=y&lt;&#x2F;p&gt;
&lt;p&gt;CONFIG_AUFS_MAGIC_SYSRQ=y&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;カーネルをコンパイル、インストールして再起動します。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~# modprobe aufs&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~# lsmod |grep auf&lt;&#x2F;p&gt;
&lt;p&gt;aufs                  464609  0 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;root@hana:~# modinfo aufs&lt;&#x2F;p&gt;
&lt;p&gt;filename:       &#x2F;lib&#x2F;modules&#x2F;2.6.38.2-64aufs01&#x2F;kernel&#x2F;fs&#x2F;aufs&#x2F;aufs.ko&lt;&#x2F;p&gt;
&lt;p&gt;version:        2.1-standalone.tree-38-20110404&lt;&#x2F;p&gt;
&lt;p&gt;description:    aufs -- Advanced multi layered unification filesystem&lt;&#x2F;p&gt;
&lt;p&gt;author:         Junjiro R. Okajima&lt;&#x2F;p&gt;
&lt;p&gt;license:        GPL&lt;&#x2F;p&gt;
&lt;p&gt;srcversion:     D52E89D4B96A545C9E3E064&lt;&#x2F;p&gt;
&lt;p&gt;depends:      &lt;&#x2F;p&gt;
&lt;p&gt;vermagic:       2.6.38.2-64aufs01 SMP mod_unload modversions&lt;&#x2F;p&gt;
&lt;p&gt;parm:           sysrq:MagicSysRq key for aufs (charp)&lt;&#x2F;p&gt;
&lt;p&gt;parm:           debug:debug print (int)&lt;&#x2F;p&gt;
&lt;p&gt;parm:           brs:use &#x2F;fs&#x2F;aufs&#x2F;si_*&#x2F;brN (int)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;インストールは以上です。Debian squeezeだとmountコマンドは最初からaufsをサポートしているようです（？要確認）&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;試してみます。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;テストディレクトリを作成する。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;mkdir &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base ベースディレクトリ、リードオンリーマウントする&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover  上から重ねるディレクトリ。書き込み可能&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt マウントポイント&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ベースディレクトリにテストディレクトリdir1、テストファイルfile1、file11を作成する。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;mkdir &#x2F;tmp&#x2F;base&#x2F;dir1&lt;&#x2F;p&gt;
&lt;p&gt;echo 1 &amp;gt; &#x2F;tmp&#x2F;base&#x2F;file1&lt;&#x2F;p&gt;
&lt;p&gt;echo 11 &amp;gt; &#x2F;tmp&#x2F;base&#x2F;dir1&#x2F;file11&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;aufsでマウントする。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;mount -t aufs -o br=&#x2F;tmp&#x2F;cover=rw:&#x2F;tmp&#x2F;base=ro none &#x2F;tmp&#x2F;mnt&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;mount|grep aufs&lt;&#x2F;p&gt;
&lt;p&gt;none on &#x2F;tmp&#x2F;mnt type aufs (rw,br=&#x2F;tmp&#x2F;cover=rw:&#x2F;tmp&#x2F;base=ro)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ディレクトリ構造は、それぞれ次のようになる。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;`-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;4 directories, 5 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;マウントしたディレクトリに新たにファイルを作成する。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;echo 2 &amp;gt; &#x2F;tmp&#x2F;mnt&#x2F;file2&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;リードオンリーの&#x2F;tmp&#x2F;baseは変わらずに、書き込み可能な&#x2F;tmp&#x2F;coverにfile2が作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- file2&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;|-- file1&lt;&#x2F;p&gt;
&lt;p&gt;`-- file2&lt;&#x2F;p&gt;
&lt;p&gt;4 directories, 7 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ファイルの削除&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&#x2F;file1を削除すると、&#x2F;tmp&#x2F;cover&#x2F;.wh.file1が作成され、&#x2F;tmp&#x2F;mnt&#x2F;file1が見えなくなる。&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&#x2F;file2を削除すると、単純に&#x2F;tmp&#x2F;coverからfile2が消える。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;rm &#x2F;tmp&#x2F;mnt&#x2F;file{1,2}&lt;&#x2F;p&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- .wh.file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;`-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;    `-- file11 &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;4 directories, 5 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;元とは違う内容で&#x2F;tmp&#x2F;mnt&#x2F;file1を作成すると、&#x2F;tm&#x2F;cover&#x2F;にもfile1が作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;echo x &amp;gt; &#x2F;tmp&#x2F;mnt&#x2F;file1&lt;&#x2F;p&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;4 directories, 6 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;それぞれのファイルの内容を確認すると、&#x2F;tmp&#x2F;base&#x2F;file1のみが元の内容のままで、&#x2F;tmp&#x2F;cover&#x2F;file1、&#x2F;tmp&#x2F;mnt&#x2F;file1は新しい内容になっていることがわかる。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;head &#x2F;tmp&#x2F;{base,cover,mnt}&#x2F;file1&lt;&#x2F;p&gt;
&lt;p&gt;==&amp;gt; &#x2F;tmp&#x2F;base&#x2F;file1  &#x2F;tmp&#x2F;cover&#x2F;file1  &#x2F;tmp&#x2F;mnt&#x2F;file1
x&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ディレクトリの削除&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&#x2F;dir1を削除すると&#x2F;tmp&#x2F;mntからはdir1が消え、&#x2F;tmp&#x2F;coverに.wh.dir1が作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;rm -r &#x2F;tmp&#x2F;mnt&#x2F;dir1&lt;&#x2F;p&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- .wh.dir1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;3 directories, 5 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;もう一度&#x2F;tmp&#x2F;mnt&#x2F;dir1を作成してみると、&#x2F;tmp&#x2F;coverにあった.wh.dir1が無くなり、新たに&#x2F;tmp&#x2F;cover&#x2F;dir1、&#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;.wh..wh..opqが作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;mkdir &#x2F;tmp&#x2F;mnt&#x2F;dir1&lt;&#x2F;p&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;    `-- .wh..wh..opq&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;5 directories, 5 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;.wh..wh..opq　の中身は空である。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;file &#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;.wh..wh..opq&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;.wh..wh..opq: empty&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&#x2F;dir1&#x2F;file11を作成してみると、&#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;file11が作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;echo xx &amp;gt; &#x2F;tmp&#x2F;mnt&#x2F;dir1&#x2F;file11&lt;&#x2F;p&gt;
&lt;p&gt;tree -a &#x2F;tmp&#x2F;{base,cover,mnt}&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;base&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;cover&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.aufs&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.orph&lt;&#x2F;p&gt;
&lt;p&gt;|-- .wh..wh.plnk&lt;&#x2F;p&gt;
&lt;p&gt;`-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;    |-- .wh..wh..opq&lt;&#x2F;p&gt;
&lt;p&gt;    `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;tmp&#x2F;mnt&lt;&#x2F;p&gt;
&lt;p&gt;|-- dir1&lt;&#x2F;p&gt;
&lt;p&gt;|   `-- file11&lt;&#x2F;p&gt;
&lt;p&gt;`-- file1&lt;&#x2F;p&gt;
&lt;p&gt;5 directories, 7 files&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;それぞれのディレクトリにあるfile11の内容は以下の通りで、&#x2F;tmp&#x2F;base&#x2F;dir1&#x2F;file11が元の内容、&#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;file11、&#x2F;tmp&#x2F;mnt&#x2F;dir1&#x2F;file11が新しい内容である。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;head &#x2F;tmp&#x2F;{base,cover,mnt}&#x2F;dir1&#x2F;file11&lt;&#x2F;p&gt;
&lt;p&gt;==&amp;gt; &#x2F;tmp&#x2F;base&#x2F;dir1&#x2F;file11  &#x2F;tmp&#x2F;cover&#x2F;dir1&#x2F;file11  &#x2F;tmp&#x2F;mnt&#x2F;dir1&#x2F;file11
xx&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;まとめ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;スタッカブルなファイルシステムaufsについて試してみた。リードオンリーなディレクトリの上に、読み書き専用のディレクトリを重ねてマウントできることが確認できた。&lt;&#x2F;p&gt;
&lt;p&gt;また、簡単な例のみであるが、ファイルの作成、削除、ディレクトリの作成、削除を行った際に、どのような動作をするのか何となくわかった。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>BloggerのDynamic viewがおしゃれ</title>
        <published>2011-04-07T00:00:00+00:00</published>
        <updated>2011-04-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/bloggerdynamic-view.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/bloggerdynamic-view.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/bloggerdynamic-view.html/">&lt;p&gt;このブログのは&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;&lt;&#x2F;a&gt;ですが、&lt;&#x2F;p&gt;
&lt;p&gt;末尾に&#x2F;viewを追加すると、おしゃれなページに早変わり。&lt;&#x2F;p&gt;
&lt;p&gt;現在、用意されているviewは以下の５つ。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;flipcard&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;flipcard&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;mosaic&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;mosaic&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;sidebar&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;sidebar&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;snapshot&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;snapshot&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;timeslied&quot;&gt;http:&#x2F;&#x2F;ktaka.blog.clustcom.com&#x2F;view&#x2F;timeslied&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;詳しくは&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;support&#x2F;blogger&#x2F;bin&#x2F;answer.py?answer=1229061&quot;&gt;ここ&lt;&#x2F;a&gt;と&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;support&#x2F;blogger&#x2F;bin&#x2F;answer.py?hl=en&amp;amp;answer=1227173&quot;&gt;ここ&lt;&#x2F;a&gt;にアナウンスがあります。&lt;&#x2F;p&gt;
&lt;p&gt;今後、ユーザーがview自体をカスタマイズできるようにもなるようです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>GNU tarでシンボリックリンクのタイムスタンプが保存されない - 1.24以降ならOK</title>
        <published>2011-04-07T00:00:00+00:00</published>
        <updated>2011-04-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2011/04/gnu-tar124ok.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2011/04/gnu-tar124ok.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2011/04/gnu-tar124ok.html/">&lt;p&gt;GNU tar 1.24以降であれば、タイムスタンプが保存されるようである。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;cgit&#x2F;tar.git&#x2F;plain&#x2F;NEWS?id=release_1_24&quot;&gt;http:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;cgit&#x2F;tar.git&#x2F;plain&#x2F;NEWS?id=release_1_24&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;** Symbolic link attributes When extracting symbolic links, tar now restores attributes such as last-modified time and link permissions, if the operating system supports this.  For example, recent versions of the Linux kernel support setting times on symlinks, and some BSD kernels also support symlink permissions.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Debian squeeze のtarは1.23である。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ tar --version&lt;&#x2F;p&gt;
&lt;p&gt;tar (GNU tar) 1.23&lt;&#x2F;p&gt;
&lt;p&gt;Copyright (C) 2010 Free Software Foundation, Inc.&lt;&#x2F;p&gt;
&lt;p&gt;License GPLv3+: GNU GPL version 3 or later .&lt;&#x2F;p&gt;
&lt;p&gt;This is free software: you are free to change and redistribute it.&lt;&#x2F;p&gt;
&lt;p&gt;There is NO WARRANTY, to the extent permitted by law.&lt;&#x2F;p&gt;
&lt;p&gt;Written by John Gilmore and Jay Fenlason.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;タイムスタンプがApr 1 00:00のシンボリックリンクを作成。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ mkdir p&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ for i in  a b c d e f g ; do ln -s &#x2F;tmp&#x2F;$i p&#x2F;$i; touch -ht 04010000 p&#x2F;$i ; done&lt;&#x2F;p&gt;
&lt;p&gt;ktaka@hana:~$ ls -la p&lt;&#x2F;p&gt;
&lt;p&gt;total 8&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x  2 ktaka ktaka 4096 Apr  8 03:03 .&lt;&#x2F;p&gt;
&lt;p&gt;drwx------ 79 ktaka ktaka 4096 Apr  8 03:03 ..&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 a -&amp;gt; &#x2F;tmp&#x2F;a&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 b -&amp;gt; &#x2F;tmp&#x2F;b&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 c -&amp;gt; &#x2F;tmp&#x2F;c&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 d -&amp;gt; &#x2F;tmp&#x2F;d&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 e -&amp;gt; &#x2F;tmp&#x2F;e&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 f -&amp;gt; &#x2F;tmp&#x2F;f&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 g -&amp;gt; &#x2F;tmp&#x2F;g&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;tarアーカイブを作成&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ (cd p; tar cf - .)|gzip &amp;gt; p.tgz&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;中身を確認すると、確かに正しいタイムスタンプでアーカイブが作成されている。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ tar ztvf p.tgz&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x ktaka&#x2F;ktaka       0 2011-04-08 03:03 .&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;f -&amp;gt; &#x2F;tmp&#x2F;f&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;c -&amp;gt; &#x2F;tmp&#x2F;c&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;g -&amp;gt; &#x2F;tmp&#x2F;g&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;a -&amp;gt; &#x2F;tmp&#x2F;a&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;e -&amp;gt; &#x2F;tmp&#x2F;e&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;d -&amp;gt; &#x2F;tmp&#x2F;d&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx ktaka&#x2F;ktaka       0 2011-04-01 00:00 .&#x2F;b -&amp;gt; &#x2F;tmp&#x2F;b&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;アーカイブをqディレクトリに展開&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ mkdir q; (cd q; tar zxf ..&#x2F;p.tgz) ; date&lt;&#x2F;p&gt;
&lt;p&gt;Fri Apr  8 03:16:26 JST 2011&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;タイムスタンプがアーカイブを展開した時刻になってしまう。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ ls -la q&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;total 8&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x  2 ktaka ktaka 4096 Apr  8 03:03 .&lt;&#x2F;p&gt;
&lt;p&gt;drwx------ 79 ktaka ktaka 4096 Apr  8 03:16 ..&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 a -&amp;gt; &#x2F;tmp&#x2F;a&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 b -&amp;gt; &#x2F;tmp&#x2F;b&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 c -&amp;gt; &#x2F;tmp&#x2F;c&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 d -&amp;gt; &#x2F;tmp&#x2F;d&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 e -&amp;gt; &#x2F;tmp&#x2F;e&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 f -&amp;gt; &#x2F;tmp&#x2F;f&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  8 03:16 g -&amp;gt; &#x2F;tmp&#x2F;g&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;GNU tar 1.24で試してみる。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ .&#x2F;tar-1.24&#x2F;_inst&#x2F;bin&#x2F;tar --version&lt;&#x2F;p&gt;
&lt;p&gt;tar (GNU tar) 1.24&lt;&#x2F;p&gt;
&lt;p&gt;Copyright (C) 2010 Free Software Foundation, Inc.&lt;&#x2F;p&gt;
&lt;p&gt;License GPLv3+: GNU GPL version 3 or later .&lt;&#x2F;p&gt;
&lt;p&gt;This is free software: you are free to change and redistribute it.&lt;&#x2F;p&gt;
&lt;p&gt;There is NO WARRANTY, to the extent permitted by law.&lt;&#x2F;p&gt;
&lt;p&gt;Written by John Gilmore and Jay Fenlason.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt; ディレクトリrに展開してみる。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ mkdir r; (cd r; ..&#x2F;tar-1.24&#x2F;_inst&#x2F;bin&#x2F;tar zxf ..&#x2F;p.tgz) ; date&lt;&#x2F;p&gt;
&lt;p&gt;Fri Apr  8 03:35:37 JST 2011&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ ls -la r&lt;&#x2F;p&gt;
&lt;p&gt;total 8&lt;&#x2F;p&gt;
&lt;p&gt;drwxr-xr-x  2 ktaka ktaka 4096 Apr  8 03:03 .&lt;&#x2F;p&gt;
&lt;p&gt;drwx------ 81 ktaka ktaka 4096 Apr  8 03:35 ..&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 a -&amp;gt; &#x2F;tmp&#x2F;a&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 b -&amp;gt; &#x2F;tmp&#x2F;b&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 c -&amp;gt; &#x2F;tmp&#x2F;c&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 d -&amp;gt; &#x2F;tmp&#x2F;d&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 e -&amp;gt; &#x2F;tmp&#x2F;e&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 f -&amp;gt; &#x2F;tmp&#x2F;f&lt;&#x2F;p&gt;
&lt;p&gt;lrwxrwxrwx  1 ktaka ktaka    6 Apr  1 00:00 g -&amp;gt; &#x2F;tmp&#x2F;g&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;正しいタイムスタンプで シンボリックリンクを展開することができた。&lt;&#x2F;p&gt;
&lt;p&gt;参考リンク&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.mail-archive.com&#x2F;bug-tar@gnu.org&#x2F;msg02281.html&quot;&gt;http:&#x2F;&#x2F;www.mail-archive.com&#x2F;bug-tar@gnu.org&#x2F;msg02281.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ファイル編集前の簡易バックアップ</title>
        <published>2010-09-15T00:00:00+00:00</published>
        <updated>2010-09-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2010/09/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2010/09/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2010/09/blog-post.html/">&lt;p&gt;Linuxの設定ファイルなどを編集する際に、編集前のファイルのバックアップを取って置きたいことがある。設定をしくじったりした場合に、元の設定に戻したいからだ。&lt;&#x2F;p&gt;
&lt;p&gt;私は、そのために、次のようなシェルコマンドを自作して利用している。&lt;&#x2F;p&gt;
&lt;p&gt;以下の内容で、~&#x2F;.functionsを作成する。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;bk ()&lt;&#x2F;p&gt;
&lt;p&gt;{&lt;&#x2F;p&gt;
&lt;p&gt;    file=${1##*&#x2F;};&lt;&#x2F;p&gt;
&lt;p&gt;    dir=${1%${1##*&#x2F;}};&lt;&#x2F;p&gt;
&lt;p&gt;    ( if [ &quot;$dir&quot; = &quot;&quot; ]; then&lt;&#x2F;p&gt;
&lt;p&gt;        true;&lt;&#x2F;p&gt;
&lt;p&gt;    else&lt;&#x2F;p&gt;
&lt;p&gt;        if [ -d &quot;$dir&quot; ]; then&lt;&#x2F;p&gt;
&lt;p&gt;            echo cd $dir;&lt;&#x2F;p&gt;
&lt;p&gt;            cd $dir;&lt;&#x2F;p&gt;
&lt;p&gt;        else&lt;&#x2F;p&gt;
&lt;p&gt;            echo &quot;No such directory: $dir &quot;;&lt;&#x2F;p&gt;
&lt;p&gt;            return 1;&lt;&#x2F;p&gt;
&lt;p&gt;        fi;&lt;&#x2F;p&gt;
&lt;p&gt;    fi;&lt;&#x2F;p&gt;
&lt;p&gt;    if [ -f &quot;$file&quot; ]; then&lt;&#x2F;p&gt;
&lt;p&gt;        mkdir -p .bk;&lt;&#x2F;p&gt;
&lt;p&gt;        echo cp -p $file .bk&#x2F;$file.$(date +&quot;%Y%m%d%H%M&quot; -r $file);&lt;&#x2F;p&gt;
&lt;p&gt;        cp -p $file .bk&#x2F;$file.$(date +&quot;%Y%m%d%H%M&quot; -r $file);&lt;&#x2F;p&gt;
&lt;p&gt;    else&lt;&#x2F;p&gt;
&lt;p&gt;        echo &quot;No such file: $file &quot;;&lt;&#x2F;p&gt;
&lt;p&gt;    fi )&lt;&#x2F;p&gt;
&lt;p&gt;}&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;この関数は、以下のような動作をするものである。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;バックアップを取りたいファイルが存在するディレクトリに.bk&#x2F;とサブディレクトリを作成する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ファイルの最終変更日時(mtime)をサフィックスにもつコピーを作成する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;使用例&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ktaka@hana:~$ . ~&#x2F;.functions&lt;&#x2F;p&gt;
&lt;p&gt;ktaka@hana:~$ ls -la &#x2F;home&#x2F;ktaka&#x2F;hello&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 ktaka ktaka 1048576000 May 27  2009 &#x2F;home&#x2F;ktaka&#x2F;hello&lt;&#x2F;p&gt;
&lt;p&gt;ktaka@hana:~$ bk &#x2F;home&#x2F;ktaka&#x2F;hello&lt;&#x2F;p&gt;
&lt;p&gt;cd &#x2F;home&#x2F;ktaka&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;cp -p hello .bk&#x2F;hello.200905270208&lt;&#x2F;p&gt;
&lt;p&gt;ktaka@hana:~$ ls -la &#x2F;home&#x2F;ktaka&#x2F;.bk&#x2F;hello.200905270208&lt;&#x2F;p&gt;
&lt;p&gt;-rw-r--r-- 1 ktaka ktaka 1048576000 May 27  2009 &#x2F;home&#x2F;ktaka&#x2F;.bk&#x2F;hello.200905270208&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt; ファイルの更新時をサフィックスに持つので、複数のバックアップファイルが存在する場合でも便利である。&lt;&#x2F;p&gt;
&lt;p&gt;~&#x2F;.bashrcで.functionsを読み込むようにしておくと良い。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;if [ -f ~&#x2F;.functions ]; then&lt;&#x2F;p&gt;
&lt;p&gt;        . ~&#x2F;.functions&lt;&#x2F;p&gt;
&lt;p&gt;fi&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>i3200でedacを使うには、カーネルを2.6.32にしなければならない。</title>
        <published>2010-01-16T00:00:00+00:00</published>
        <updated>2010-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2010/01/i3200edac2632.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2010/01/i3200edac2632.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2010/01/i3200edac2632.html/">&lt;p&gt;メモリが壊れているかな？&lt;&#x2F;p&gt;
&lt;p&gt;BIOSより、DMIログを覗いてみると。。。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Phoenix cME FirstBIOS Pro Setup Utility
Advanced
+---------+----------------------------------------------------------+---------+&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;DMI Event Log&lt;&#x2F;th&gt;&lt;th&gt;Help&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Event&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:44:12  Pre-Boot Error:                  ^&lt;&#x2F;td&gt;&lt;td&gt;ts of&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Event&lt;&#x2F;td&gt;&lt;td&gt;Keyboard Not Functional                            .&lt;&#x2F;td&gt;&lt;td&gt;og.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;.&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;View D&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:44:46  Single-Bit ECC Errors in DIMM#   .&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Event&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:45:45  Single-Bit ECC Errors in DIMM#   .&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:45:45  Pre-Boot Error:                  :&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Mark D&lt;&#x2F;td&gt;&lt;td&gt;Keyboard Not Functional                            :&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Clear&lt;&#x2F;td&gt;&lt;td&gt;:&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:46:28  Single-Bit ECC Errors in DIMM#   :&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:47:00  Single-Bit ECC Errors in DIMM#   :&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;01&#x2F;16&#x2F;2010  14:47:00  Pre-Boot Error:                  :&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Keyboard Not Functional                            .&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;[Continue]&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;+----------------------------------------------------------+&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;+------------------------------------------------------------------------------&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;せっかくなので、linuxのedacで検出してみる。&lt;&#x2F;p&gt;
&lt;p&gt;i3200でedacを使うには、カーネルを2.6.32にしなければならない。
ずっと前からコードはあったので、とっくにマージされていたと思っていました。&lt;&#x2F;p&gt;
&lt;p&gt;モジュールはこれ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;lenny64:~# lsmod |grep edac
i3200_edac              3599  0&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;エラー出力&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;lenny64:~# dmesg |tail
EDAC DEBUG: i3200_check: MC0: i3200_check()
EDAC MC0: CE page 0x0, offset 0x0, grain 1073741824, syndrome 0x54, row 1, channel 0, label &quot;&quot;: i3200 CE
EDAC DEBUG: i3200_check: MC0: i3200_check()
EDAC MC0: CE page 0x0, offset 0x0, grain 1073741824, syndrome 0x54, row 1, channel 0, label &quot;&quot;: i3200 CE
EDAC DEBUG: i3200_check: MC0: i3200_check()
EDAC MC0: CE page 0x0, offset 0x0, grain 1073741824, syndrome 0x54, row 1, channel 0, label &quot;&quot;: i3200 CE
EDAC DEBUG: i3200_check: MC0: i3200_check()
EDAC MC0: CE page 0x0, offset 0x0, grain 1073741824, syndrome 0x54, row 1, channel 0, label &quot;&quot;: i3200 CE
EDAC DEBUG: i3200_check: MC0: i3200_check()
EDAC MC0: CE page 0x0, offset 0x0, grain 1073741824, syndrome 0x54, row 1, channel 0, label &quot;&quot;: i3200 CE&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>VAIO X linuxでの輝度調整</title>
        <published>2009-11-09T00:00:00+00:00</published>
        <updated>2009-11-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/11/vaio-x-linux.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/11/vaio-x-linux.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/11/vaio-x-linux.html/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;garin.jp&#x2F;doc&#x2F;%E6%A9%9F%E7%A8%AE%E5%88%A5&#x2F;vaio_type_p&#x2F;bright&quot;&gt;ここ&lt;&#x2F;a&gt;を参考に。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;setpci コマンドで直接設定を行います。 VAIO type P では 00:02.0 F4.B が輝度用のデバイスです。
輝度の範囲は 00〜FF(暗い〜明い) です。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;VAIO Xでも同じだろうということでやってみると、やはりその通り。輝度調節できました。&lt;&#x2F;p&gt;
&lt;p&gt;最小はB=0だけど、そうすると真っ暗になってしまう。B=10前後がいいところか。
setpci -s 00:02.0 F4.B=10&lt;&#x2F;p&gt;
&lt;p&gt;最大はB=FF。
setpci -s 00:02.0 F4.B=FF&lt;&#x2F;p&gt;
&lt;p&gt;B=10の時の消費電力&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;grep-rate-proc-acpi-battery-bat0-state&quot;&gt;grep rate  &#x2F;proc&#x2F;acpi&#x2F;battery&#x2F;BAT0&#x2F;state&lt;&#x2F;h1&gt;
&lt;p&gt;present rate:            6104 mW&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;B=FFの時の消費電力&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;grep-rate-proc-acpi-battery-bat0-state-1&quot;&gt;grep rate  &#x2F;proc&#x2F;acpi&#x2F;battery&#x2F;BAT0&#x2F;state&lt;&#x2F;h1&gt;
&lt;p&gt;present rate:            7628 mW&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Lバッテリの場合&quot;design capacity: 33590 mWh&quot;なので、B=10にすれば、5時間ちょっとは使えそうです。&lt;&#x2F;p&gt;
&lt;p&gt;追記 cpufreqdの設定で、ACプラグON&#x2F;OFFで輝度が変わるようにしました。
&#x2F;etc&#x2F;cpufreqd.conf&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Profile]
name=Performance High
minfreq=100%
maxfreq=100%
policy=performance
exec_post=&#x2F;usr&#x2F;bin&#x2F;setpci -s 00:02.0 F4.B=ff
[&#x2F;Profile]&lt;&#x2F;p&gt;
&lt;p&gt;[Profile]
name=Powersave Low
minfreq=40%
maxfreq=40%
policy=powersave
exec_post=&#x2F;usr&#x2F;bin&#x2F;setpci -s 00:02.0 F4.B=10
[&#x2F;Profile]&lt;&#x2F;p&gt;
&lt;p&gt;[Rule]
name=AC Rule
ac=on
profile=Performance High
[&#x2F;Rule]&lt;&#x2F;p&gt;
&lt;p&gt;[Rule]
name=AC Off - Low Battery
ac=off
battery_interval=0-100
profile=Powersave Low
[&#x2F;Rule]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>vaio x + d31hw 電池の持ちは3.5時間</title>
        <published>2009-11-04T00:00:00+00:00</published>
        <updated>2009-11-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/11/vaio-x-d31hw-35.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/11/vaio-x-d31hw-35.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/11/vaio-x-d31hw-35.html/">&lt;p&gt;イーモバイルD31HWでロマンスカー車内から接続中。&lt;&#x2F;p&gt;
&lt;p&gt;消費電力は約10W。この調子だと、せいぜい3.5時間がいいところです&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:~# cat &#x2F;proc&#x2F;acpi&#x2F;battery&#x2F;BAT0&#x2F;state
present:                 yes
capacity state:          ok
charging state:          discharging
present rate:            10101 mW
remaining capacity:      32240 mWh
present voltage:         7992 mV&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;vaio xは店頭販売モデルなのでLバッテリが標準ですが、Xバッテリが欲しくなります。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>vaio xの駆動時間は実質4時間位か</title>
        <published>2009-11-03T00:00:00+00:00</published>
        <updated>2009-11-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/11/vaio-x4.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/11/vaio-x4.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/11/vaio-x4.html/">&lt;p&gt;メーカーのページにL型バッテリ駆動時間は約10時間とあるので期待して購入したvaio xですが、私の環境では、4時間位がいいところのようです。&lt;&#x2F;p&gt;
&lt;p&gt;環境　Debian Linux(カーネル2.6.31.5)&lt;&#x2F;p&gt;
&lt;p&gt;電池の容量は、33590 mWh&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:&#x2F;home&#x2F;ktaka# cat &#x2F;proc&#x2F;acpi&#x2F;battery&#x2F;BAT0&#x2F;info
present:                 yes
design capacity:         33590 mWh
last full capacity:      33590 mWh
battery technology:      rechargeable
design voltage:          7400 mV
design capacity warning: 3350 mWh
design capacity low:     120 mWh
capacity granularity 1:  0 mWh
capacity granularity 2:  1 mWh
model number:
serial number:
battery type:            Lion
OEM info:                Sony Corporation&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;800MHz動作時の、消費電力は、7669mW&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;cat-proc-acpi-battery-bat0-state&quot;&gt;cat &#x2F;proc&#x2F;acpi&#x2F;battery&#x2F;BAT0&#x2F;state&lt;&#x2F;h1&gt;
&lt;p&gt;present:                 yes
capacity state:          ok
charging state:          discharging
present rate:            7669 mW
remaining capacity:      4710 mWh
present voltage:         6928 mV&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;よって33590&#x2F;7669 = 4.38 時間が駆動時間。&lt;&#x2F;p&gt;
&lt;p&gt;CPUのクロックは、cpufreqdのおかげで、バッテリ駆動時は800MHzになっている。
ACアダプタ使用時 1.87GHz&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;cat-sys-devices-system-cpu-cpu-0-1-cpufreq-cpuinfo-cur-freq&quot;&gt;cat  &#x2F;sys&#x2F;devices&#x2F;system&#x2F;cpu&#x2F;cpu{0,1}&#x2F;cpufreq&#x2F;cpuinfo_cur_freq&lt;&#x2F;h1&gt;
&lt;p&gt;1866000
1866000&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;バッテリ駆動時 800MHz&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;cat-sys-devices-system-cpu-cpu-0-1-cpufreq-cpuinfo-cur-freq-1&quot;&gt;cat  &#x2F;sys&#x2F;devices&#x2F;system&#x2F;cpu&#x2F;cpu{0,1}&#x2F;cpufreq&#x2F;cpuinfo_cur_freq&lt;&#x2F;h1&gt;
&lt;p&gt;800000
800000&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;cpufreqd.confの内容&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[General]
pidfile=&#x2F;var&#x2F;run&#x2F;cpufreqd.pid
poll_interval=2
verbosity=4
[&#x2F;General]&lt;&#x2F;p&gt;
&lt;p&gt;[Profile]
name=Performance High
minfreq=100%
maxfreq=100%
policy=performance
#exec_post=echo 8 &amp;gt; &#x2F;proc&#x2F;acpi&#x2F;sony&#x2F;brightness
[&#x2F;Profile]&lt;&#x2F;p&gt;
&lt;p&gt;[Profile]
name=Powersave Low
minfreq=40%
maxfreq=40%
policy=powersave
[&#x2F;Profile]&lt;&#x2F;p&gt;
&lt;p&gt;[Rule]
name=AC Rule
ac=on                    # (on&#x2F;off)
profile=Performance High
[&#x2F;Rule]&lt;&#x2F;p&gt;
&lt;p&gt;[Rule]
name=AC Off - Low Battery
ac=off                   # (on&#x2F;off)
battery_interval=0-100
#exec_post=echo 3 &amp;gt; &#x2F;proc&#x2F;acpi&#x2F;sony&#x2F;brightness
profile=Powersave Low
[&#x2F;Rule]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Poulsbo (GMA 500)のグラフィックドライバ(psb)がバニラカーネルに取り込まれていない。
Ｕｂｕｎｔｕでは、カーネル2.6.28用のドライバが存在するようである。&lt;&#x2F;p&gt;
&lt;p&gt;今はLCDの輝度調節が効かないが、psbが使えれば、輝度を落とすことができ、もう少し長く使えるようになるかもしれない。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Debian Linux でイーモバイルD31HW使う</title>
        <published>2009-11-01T00:00:00+00:00</published>
        <updated>2009-11-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/11/debian-linux.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/11/debian-linux.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/11/debian-linux.html/">&lt;p&gt;下り最大21Mbps、上り最大5.8Mbpsのデータ通信カード(スティック)イーモバイルのD31HWを使ってみる。&lt;&#x2F;p&gt;
&lt;p&gt;事前調査によると、このカードは、ストレージとモデムの両方の機能を持っていて、とあるコマンドを送ることによりモードを切り替えられるとのこと。ストレージは、Windowsなどで最初に接続したときに、自動的にデバイスドライバをインストールするためのものであるとのこと。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;blog.37to.net&#x2F;2009&#x2F;01&#x2F;ubuntuemobiled21lc&#x2F;&quot;&gt;http:&#x2F;&#x2F;blog.37to.net&#x2F;2009&#x2F;01&#x2F;ubuntuemobiled21lc&#x2F;
&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;show-cha.seesaa.net&#x2F;article&#x2F;125815364.html&quot;&gt;http:&#x2F;&#x2F;show-cha.seesaa.net&#x2F;article&#x2F;125815364.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;カードを接続しlsusb で見ると、以下のエントリが現れる。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Bus 001 Device 004: ID 12d1:1446 Huawei Technologies Co., Ltd.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.draisberghof.de&#x2F;usb_modeswitch&#x2F;#download&quot;&gt;ここ&lt;&#x2F;a&gt;から、usb_modeswitchをダウンロードしインストール。
&#x2F;etc&#x2F;usb_modeswitch.conf を以下の内容で作成。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;emobile-d31hw&quot;&gt;Emobile D31HW&lt;&#x2F;h1&gt;
&lt;p&gt;DefaultVendor=  0x12d1
DefaultProduct= 0x1446
TargetVendor=   0x12d1
TargetProduct=  0x1429&lt;&#x2F;p&gt;
&lt;p&gt;MessageEndpoint=0x01
MessageContent=&quot;55534243000000000000000000000011060000000000000000000000000000&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;usb_modeswitchを実行すると&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;vaiox:~# usb_modeswitch&lt;&#x2F;p&gt;
&lt;p&gt;Looking for target devices ...
No devices in target mode or class found
Looking for default devices ...
Found default devices (1)
Accessing device 005 on bus 001 ...
Using endpoints 0x01 (out) and 0x81 (in)
Inquiring device details; driver will be detached ...
Looking for active driver ...
OK, driver found (&quot;usb-storage&quot;)
OK, driver &quot;usb-storage&quot; detached&lt;&#x2F;p&gt;
&lt;h2 id=&quot;received-inquiry-data-detailed-identification&quot;&gt;Received inquiry data (detailed identification)&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;vendor-string-huaweimodel-string-mass-storagerevision-string-2-31&quot;&gt;Vendor String: HUAWEI
Model String: Mass Storage
Revision String: 2.31&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;device-description-data-identification&quot;&gt;Device description data (identification)&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;manufacturer-huawei-technologiesproduct-huawei-mobileserial-no-not-provided&quot;&gt;Manufacturer: Huawei Technologies
Product: HUAWEI Mobile
Serial No.: not provided&lt;&#x2F;h2&gt;
&lt;p&gt;Setting up communication with interface 0 ...
Trying to send the message to endpoint 0x01 ...
OK, message successfully sent
-&amp;gt; Run lsusb to note any changes. Bye.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;lsusbで見てみると&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bus 001 Device 006: ID 12d1:1429 Huawei Technologies Co., Ltd.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;デバイスIDが1446から1429に変わっている。&lt;&#x2F;p&gt;
&lt;p&gt;カーネルモジュールをロードすると、&#x2F;dev&#x2F;ttyUSB0,1,2が作成される。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;ls-la-dev-ttyusb&quot;&gt;ls -la &#x2F;dev&#x2F;ttyUSB*&lt;&#x2F;h1&gt;
&lt;p&gt;ls: cannot access &#x2F;dev&#x2F;ttyUSB*: No such file or directory&lt;&#x2F;p&gt;
&lt;h1 id=&quot;modprobe-usbserial-vendor-0x12d1-product-0x1429&quot;&gt;modprobe usbserial vendor=0x12d1 product=0x1429&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;ls-la-dev-ttyusb-1&quot;&gt;ls -la &#x2F;dev&#x2F;ttyUSB*&lt;&#x2F;h1&gt;
&lt;p&gt;crw-rw---- 1 root dialout 188, 0 Nov  2 01:02 &#x2F;dev&#x2F;ttyUSB0
crw-rw---- 1 root dialout 188, 1 Nov  2 01:02 &#x2F;dev&#x2F;ttyUSB1
crw-rw---- 1 root dialout 188, 2 Nov  2 01:02 &#x2F;dev&#x2F;ttyUSB2&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;そして、pppの設定ファイルを作成&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;ppp&#x2F;peers&#x2F;provider&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;user &quot;em@em&quot;
connect &quot;&#x2F;usr&#x2F;sbin&#x2F;chat -v -f &#x2F;etc&#x2F;chatscripts&#x2F;pap -T &lt;em&gt;99&lt;&#x2F;em&gt;**1#&quot;
&#x2F;dev&#x2F;ttyUSB0
115200
defaultroute
persist
noauth
usepeerdns&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;接続してみる&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h1 id=&quot;pon&quot;&gt;pon&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;ps-ef-grep-ppp&quot;&gt;ps -ef |grep ppp&lt;&#x2F;h1&gt;
&lt;p&gt;root      2404     1  0 01:08 ttyUSB0  00:00:00 &#x2F;usr&#x2F;sbin&#x2F;pppd call provider
root      2410  2088  0 01:08 pts&#x2F;5    00:00:00 grep ppp&lt;&#x2F;p&gt;
&lt;h1 id=&quot;ip-add-show-dev-ppp0&quot;&gt;ip add show dev ppp0&lt;&#x2F;h1&gt;
&lt;p&gt;6: ppp0:&lt;&#x2F;p&gt;
&lt;p&gt;mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 3
link&#x2F;ppp
inet 114.48.27.146 peer 10.64.64.64&#x2F;32 scope global ppp0&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;接続できました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ＶＡＩＯ X用Linuxカーネルコンフィグ</title>
        <published>2009-11-01T00:00:00+00:00</published>
        <updated>2009-11-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/11/x.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/11/x.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/11/x.html/">&lt;p&gt;VAIO Xの各デバイスを認識させるためにとりあえず必要そうなもの。&lt;&#x2F;p&gt;
&lt;p&gt;PATA ＳＳＤ用のドライバ　(8086:811a System Controller Hub (SCH Poulsbo) IDE Controller)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CONFIG_PATA_SCH=y&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ＮＩＣドライバ(11ab:4380  Ethernet controller: Marvell Technology Group Ltd. Device 4380)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CONFIG_SKY2=m
CONFIG_SKY2_DEBUG=y&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;無線LANドライバ(168c:002b AR9285 Wireless Network Adapter (PCI-Express) )&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CONFIG_CFG80211=m
CONFIG_CFG80211_REG_DEBUG=y
CONFIG_CFG80211_DEBUGFS=y
CONFIG_LIB80211=m
CONFIG_LIB80211_DEBUG=y
CONFIG_MAC80211=m
CONFIG_MAC80211_DEFAULT_PS=y
CONFIG_MAC80211_DEFAULT_PS_VALUE=1
CONFIG_MAC80211_RC_PID=y
CONFIG_MAC80211_RC_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT=&quot;minstrel&quot;
CONFIG_MAC80211_LEDS=y
CONFIG_MAC80211_DEBUGFS=y
CONFIG_MAC80211_DEBUG_MENU=y
CONFIG_WLAN_PRE80211=y
CONFIG_WLAN_80211=y
CONFIG_ATH_COMMON=m
CONFIG_ATH5K=m
CONFIG_ATH5K_DEBUG=y
CONFIG_ATH9K=m
CONFIG_ATH9K_DEBUG=y&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;イーモバイルＤ３１ＨＷのために...&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CONFIG_USB_ACM=m
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;イーモバイルのデータカードはこれだけではダメで、usb_modeswitchによるモード切替が必要。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>VAIO X 購入しました</title>
        <published>2009-10-31T00:00:00+00:00</published>
        <updated>2009-10-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/vaio-x.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/vaio-x.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/vaio-x.html/">&lt;p&gt;薄くて、軽くて、電池が長持ち、SonyのネットブックVAIO Xを購入しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CPU Intel Atom Z540 (1.86GHz)&lt;&#x2F;li&gt;
&lt;li&gt;メモリー2GByte&lt;&#x2F;li&gt;
&lt;li&gt;SSD 64GByte&lt;&#x2F;li&gt;
&lt;li&gt;Lバッテリで約10時間駆動&lt;&#x2F;li&gt;
&lt;li&gt;重量　0.765kg&lt;&#x2F;li&gt;
&lt;li&gt;厚み　13.9mm&lt;&#x2F;li&gt;
&lt;li&gt;無線 IEEE802.11b&#x2F;g&#x2F;n&lt;&#x2F;li&gt;
&lt;li&gt;ＬＡＮ 1000Base-T&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;スペックは必要にして十分。CPUが64ビット対応でないのだけが残念。(仕事で必要なので。)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2009&#x2F;10&#x2F;vaio-x.html&#x2F;image&#x2F;img_0860.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;写真は、Let’ｓ note T7と、大きさを比較したもの。Let&#x27;s noteも1.2kgで電池の持ちも良かったんですが、VAIO Xはそれよりも上を(下を？)行く大きさと、軽さです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2009&#x2F;10&#x2F;vaio-x.html&#x2F;image&#x2F;img_0858.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;本当にノートを持ち歩く感覚です。&lt;&#x2F;p&gt;
&lt;p&gt;ソニーの宣伝文句は「余分はいらない。十分がほしい。」ということみたいなので、
早速、Windows 7を消して、Debianを入れました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>[備忘録] ノートパソコンの起動時間の短縮をしたい</title>
        <published>2009-10-26T00:00:00+00:00</published>
        <updated>2009-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/blog-post.html/">&lt;p&gt;Let&#x27;s note T7に Debianを入れたものを外出先で使っているのですが、Grubでカーネルを選択してから、Xが立ち上がるまでに1分近くかかっていました。その後emobileに接続したりと、メールやWebが見れるまでにはさらに時間がかかっていました。これだと、ちょこっと情報を確認したい時にはちょっと面倒です。
そこでiPhoneを導入し、それはそれで快適に使えているわけですが、ノートパソコンの方ももう少し起動時間短縮できるよう頑張ってみたいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;方針は&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;余分なサービスの停止&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;X windowが無くても何とかなるように&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;フレームバッファを使えるようにする&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;テキストコンソールでメールの読み書きができるように。候補emacs+wanderlust&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;テキストコンソールでWebの閲覧検索ができるように。候補はemacs+w3m&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;切換えはscreenで&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;カーネルをスリムに&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;SSD化、IntelのX-25M 80GB辺りを物色中&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;先ず、色々といらないサービスを起動しないようにします。
update-rc -f dhcpd3-server remove
update-rc -f tftpd-hpa remove
update-rc -f hogehoge remove&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;etc&#x2F;init.d&#x2F;rcで
CONCURRENCY=none → CONCURRENCY=shell&lt;&#x2F;p&gt;
&lt;p&gt;フレームバッファを使えるようにする
lspci
00:02.0 VGA compatible controller: Intel Corporation Mobile GM965&#x2F;GL960 Integrated Graphics Controller (rev 03)
00:02.1 Display controller: Intel Corporation Mobile GM965&#x2F;GL960 Integrated Graphics Controller (rev 03)
とあるので、intelfbを使うことにします。&lt;&#x2F;p&gt;
&lt;p&gt;おそらく関係するのはこの辺り
ktaka@lets:~&#x2F;Kernel&#x2F;linux-2.6.31.5$ egrep FB .config|egrep -v &quot;^#&quot;
CONFIG_FB=y
CONFIG_FB_DDC=y
CONFIG_FB_BOOT_VESA_SUPPORT=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_FOREIGN_ENDIAN=y
CONFIG_FB_BOTH_ENDIAN=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_INTEL=y
CONFIG_FB_INTEL_DEBUG=y
CONFIG_FB_INTEL_I2C=y&lt;&#x2F;p&gt;
&lt;p&gt;上記設定確認後、カーネルを再コンパイルしました。&lt;&#x2F;p&gt;
&lt;p&gt;そしてカーネルのオプションは、
video=intelfb:accel=0 vga=0x318
とすれば上手く行くことがわかりました。intelfbのデフォルトだとaccel=1になっていて、上手くいかないようです。&lt;&#x2F;p&gt;
&lt;p&gt;コンソールで日本語を表示する為に、jfbtermを使ってみる。&lt;&#x2F;p&gt;
&lt;p&gt;環境変LC_ALL=ja_JPでないと、日本語が表示できなかったりする。
コンソールでjfbtermを使わずにmanページを見ることもあるので、普段はLC_ALL=Cで使いたい。
.bashrcで、TERM=jfbtermの時のみLC_ALL=ja_JPにするよう設定します。&lt;&#x2F;p&gt;
&lt;p&gt;if [ &lt;code&gt;tty|sed -e &#x27;s&#x2F;.*tty.*&#x2F;tty&#x2F;g&#x27;&lt;&#x2F;code&gt; == &quot;tty&quot; ] ; then
export LC_ALL=C
fi&lt;&#x2F;p&gt;
&lt;p&gt;if [ $TERM == &quot;jfbterm&quot; ] ; then
export LC_ALL=ja_JP
export LANG=ja_JP.UTF-8
fi&lt;&#x2F;p&gt;
&lt;p&gt;以上の設定の後、
コンソールログイン→screen起動→emacs&#x2F;M-x w3mで日本語ページが表示できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;このページもその環境から編集していますが、bloggerにログインする際、クッキーが使えないと叱られた。
.emacsに
(setq w3m-use-cookies t)
と書くことで解決しました。&lt;&#x2F;p&gt;
&lt;p&gt;残りは、後日。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>[備忘録] jfbterm終了時に固まることがある件</title>
        <published>2009-10-26T00:00:00+00:00</published>
        <updated>2009-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/jfbterm.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/jfbterm.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/jfbterm.html/">&lt;p&gt;ここを参考に、以下のように変更&lt;&#x2F;p&gt;
&lt;p&gt;ktaka@lets:~&#x2F;SRC$ diff -c jfbterm-0.4.7_orig&#x2F;term.c jfbterm-0.4.7&#x2F;term.c
*** jfbterm-0.4.7_orig&#x2F;term.c   2003-09-16 00:45:31.000000000 +0900
--- jfbterm-0.4.7&#x2F;term.c        2009-10-26 23:09:54.000000000 +0900&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;*** 76,82 ****
void sigchld(sig) int sig; {
int st;
int ret;
!       ret = wait(&amp;amp;st);
if (ret == gChildProcessId || ret == ECHILD) {
tvterm_unregister_signal();
tterm_final(&amp;amp;gTerm);
--- 76,82 ----
void sigchld(sig) int sig; {
int st;
int ret;
!       ret = waitpid(gChildProcessId, &amp;amp;st, WNOHANG);
if (ret == gChildProcessId || ret == ECHILD) {
tvterm_unregister_signal();
tterm_final(&amp;amp;gTerm);&lt;&#x2F;p&gt;
&lt;p&gt;但し、asm&#x2F;page.hが無といわれたり、コンパイルが通らないので、
最新のデビアン用の&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ftp.de.debian.org&#x2F;debian&#x2F;pool&#x2F;main&#x2F;j&#x2F;jfbterm&#x2F;jfbterm_0.4.7-8.diff.gz&quot;&gt;パッチ&lt;&#x2F;a&gt;を当て、コンパイルを通す。&lt;&#x2F;p&gt;
&lt;p&gt;今のところ直っているようにみえる。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>[備忘録] テキストコンソールでWeb閲覧</title>
        <published>2009-10-26T00:00:00+00:00</published>
        <updated>2009-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/web.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/web.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/web.html/">&lt;p&gt;LinuxのテキストコンソールでWeb閲覧したい件
結局、&#x2F;dev&#x2F;tty1ならば、ssh-agent -&amp;gt; jfbterm -&amp;gt; screenと自動起動するようにしました。&lt;&#x2F;p&gt;
&lt;p&gt;export LC_ALL=ja_JP
export LANG=ja_JP.UTF-8&lt;&#x2F;p&gt;
&lt;p&gt;if [ &lt;code&gt;tty&lt;&#x2F;code&gt; == &quot;&#x2F;dev&#x2F;tty1&quot; ] ; then
exec ssh-agent jfbterm -e screen
fi&lt;&#x2F;p&gt;
&lt;p&gt;screenのwindowでemacsを開き、そこで&#x27;M-x w3m&#x27;とすれば、Webが閲覧できる。
日本語入力もemacs+skkのおかげでほぼ問題無さそうです。&lt;&#x2F;p&gt;
&lt;p&gt;screenの中からstartxでXが起動できないので、Xを使いたい時は、Alt+F[2-6]で他のttyに切り替えて使用することにします。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>巷で評判のiPhone 3GSを購入しました。</title>
        <published>2009-10-19T00:00:00+00:00</published>
        <updated>2009-10-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/iphone-3gs.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/iphone-3gs.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/iphone-3gs.html/">&lt;p&gt;外出先から会社のメールを確認する際、今までemobileでネット接続していました。
しかし、パソコンをブートするに時間がかかり、移動中の接続が面倒に感じていたので、思い切ってiPhoneを購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;スマートフォンの類は、表示に問題があったり文字入力が使い難かったりであまり期待していなかったのですが、iPhoneは私にとって問題のないレベルです。
Gmailと会社のメールが両方ともIMAPで簡単に使えるということも重要なポイントです。
会社のメールサーバはSSL&#x2F;TLSを使っているのですが、特にポート番号を指定しなくても、勝手に探して繋がってしまいました。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>keepalived-1.1.19がリリースされました</title>
        <published>2009-10-08T00:00:00+00:00</published>
        <updated>2009-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/10/keepalived-1119.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/10/keepalived-1119.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/10/keepalived-1119.html/">&lt;p&gt;10&#x2F;1にkeepalived-1.1.19がリリースされました。&lt;&#x2F;p&gt;
&lt;p&gt;keepalivedのvrrpの実装では、ネットワークリンクがダウンするとFAULT Stateに入ります。
ネットワークリンクがアップすると、FAULT StateからいきなりMASTERに昇格してしまい、コネクタの接触不良などの場合に、MASTERがバタバタ入れ替わってしまうという、かなり致命的な危険性がありました。&lt;&#x2F;p&gt;
&lt;p&gt;nopreemptオプションを有効にすることで、リンクの復旧時にBACKUPステートに入るようにでき、その様な危険性がなくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.keepalived.org&#x2F;changelog.html&quot;&gt;http:&#x2F;&#x2F;www.keepalived.org&#x2F;changelog.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>カーネル読書会に参加してきました。</title>
        <published>2009-02-24T00:00:00+00:00</published>
        <updated>2009-02-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/02/blog-post_25.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/02/blog-post_25.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/02/blog-post_25.html/">&lt;p&gt;先週の水曜になりますが、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ylug.jp&#x2F;modules&#x2F;pukiwiki&#x2F;&quot;&gt;ylug主催の第93回カーネル読書会&lt;&#x2F;a&gt;に参加してきました。&lt;&#x2F;p&gt;
&lt;p&gt;今回のお題は、&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;お題：Unique experiences as x86-64 maintainer (good things,  difficulties)
発表者：  Andi Kleen
内容： x86-64のメンテナーとしての苦労話などをいただきます。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ということで、最近売られているほとんどのパソコンがサポートしている64bit機能に対応した、Linuxカーネルを開発したメンテナーのお話を聞きました。Andi Kleenは30歳位(?)のドイツ人です。2000年頃から、x86-64のカーネルを開発しているとのことでした。&lt;&#x2F;p&gt;
&lt;p&gt;Linuxカーネル開発の裏話などいろいろ聞けて楽しかったのです。&lt;&#x2F;p&gt;
&lt;p&gt;始めた頃は、x86-64のCPUが世の中に存在せず、何年もの間、ソフトウェアシミュレーターを使ってコードを動かしていたと聞き、とても感心しました。
世の中には、すごい人がいるんだなぁと。&lt;&#x2F;p&gt;
&lt;p&gt;お話が終わった後は、ピザパーティでいろいろな人とお話させていただきました。&lt;&#x2F;p&gt;
&lt;p&gt;さて、ylugの勉強会はLinuxデベロッパーのすごい人が集まっていて、いつもレベルが高いのですが、
何でも、第100回の読書会(今秋？)には、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;torvalds-family.blogspot.com&#x2F;&quot;&gt;Linus Torvalds&lt;&#x2F;a&gt;をゲストに呼ぼうと計画しているそうです。&lt;&#x2F;p&gt;
&lt;p&gt;とても楽しみですね。&lt;&#x2F;p&gt;
&lt;p&gt;追記
当日、朝日新聞の取材が入っていたということで、何気に&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;d.hatena.ne.jp&#x2F;hyoshiok&#x2F;20090221#p2&quot;&gt;吉岡さんの記事&lt;&#x2F;a&gt;を辿ってみたところ。。。&lt;&#x2F;p&gt;
&lt;p&gt;げげ、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.asahi.com&#x2F;special&#x2F;net&#x2F;TKY200902200198.html&quot;&gt;自分が写ってしまっている&lt;&#x2F;a&gt;。しかも顔半分。。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2009&#x2F;02&#x2F;blog-post_25.html&#x2F;image&#x2F;blank.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intel Xeon 新モデル</title>
        <published>2009-02-24T00:00:00+00:00</published>
        <updated>2009-02-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/02/intel-xeon.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/02/intel-xeon.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/02/intel-xeon.html/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;japan.zdnet.com&#x2F;news&#x2F;hardware&#x2F;story&#x2F;0,2000056184,20388724,00.htm&quot;&gt;ここ&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;japan.zdnet.com&#x2F;news&#x2F;hardware&#x2F;story&#x2F;0,2000056184,20388724,00.htm&quot;&gt;のニュース&lt;&#x2F;a&gt;によると、クアッドコアXeonの低消費電力版が、ようやく発売されたようである。　&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;同社は米国時間2月22日、45Wからの低消費電力モデルとなるXeonプロセッサを2機種と、ハイエンドモデルとなるXeonを1機種、新たに追加した。&lt;&#x2F;p&gt;
&lt;p&gt;　L3110（3.00GHz）は、6MバイトのL2キャッシュを搭載しつつ、45Wという、Xeonプロセッサとしては、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;japan.zdnet.com&#x2F;company&#x2F;story&#x2F;0,3200081168,20014145,00.htm&quot;&gt;Intel&lt;&#x2F;a&gt;で最低レベルの熱設計電力（TDPまたは熱設計枠とも呼ばれる）を実現している。価格は224ドルとなっている。&lt;&#x2F;p&gt;
&lt;p&gt;　L3360（2.83GHz）は、12MバイトのL2キャッシュを搭載して、TDPは65W。価格は369ドルとなる。&lt;&#x2F;p&gt;
&lt;p&gt;　ハイエンドモデルのX3380（3.16GHz）は、12MバイトのL2キャッシュで、TDPは95W、価格は530ドルに設定されている。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;クアッドコアのXeon　X3360がTDP ９５Wだったので、TDP 65WのL3360にすることで、電流がおよそ0.3A抑えることができそうである。&lt;&#x2F;p&gt;
&lt;p&gt;さっそく、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;processorfinder.intel.com&#x2F;details.aspx?sSpec=SLGPF&quot;&gt;Intelのページ&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;processorfinder.intel.com&#x2F;details.aspx?sSpec=SLGPF&quot;&gt;にもスペック&lt;&#x2F;a&gt;が公開されている。&lt;&#x2F;p&gt;
&lt;p&gt;Yorkfieldを用いたサーバは、パーツの価格がこなれてきたこともあり、メインストリームがNehalemに移行するまで、まだまだ活躍しそうである。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>1月の労働時間</title>
        <published>2009-02-02T00:00:00+00:00</published>
        <updated>2009-02-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/02/1.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/02/1.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/02/1.html/">&lt;p&gt;年始に、年間の目標労働時間を4,500時間と定めました。&lt;&#x2F;p&gt;
&lt;p&gt;100%集中していなくてもいいですが、
とにかく仕事に向き合う時間を多くすることで、
少しでもアウトプットを出したいという思いからの試みです。&lt;&#x2F;p&gt;
&lt;p&gt;別の言い方をすると、いくら効率を上げようと努力しても、絶対時間が不足していては
なかなか仕事の成果が出てこない、という過去の反省からの目標設定でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかしながら、かなり、難しい目標設定だということがわかってきました。
年間で4,500時間を達成しようとすると、月当たり375時間必要ですが、
今月は、頑張ったつもりですが300時間にしかなりませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;この調子でいくと年間3,600時間程度にしかなりません。
せめて４,０００時間を目指したいところですが、そうすると、月当たり337時間程度必要です。&lt;&#x2F;p&gt;
&lt;p&gt;今月も頑張れればいいですが。。。心が折れないか心配です。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>メルマガ配信完了</title>
        <published>2009-02-02T00:00:00+00:00</published>
        <updated>2009-02-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/02/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/02/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/02/blog-post.html/">&lt;p&gt;いろいろと、ミスもありましたが、メルマガ配信完了しました。
ひとまず、やれやれといったところです。
今号のTopicは、
Intel SSD X25-E + RAID の記事と、Seagateのファームウェアアップデート方法に関する記事などです。&lt;&#x2F;p&gt;
&lt;p&gt;ご興味がありましたら、是非&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;marc.clustcom.com&#x2F;&quot;&gt;アーカイブページ&lt;&#x2F;a&gt;をご覧下さい。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>DDR3への完全移行は2010年以降となるらしいです</title>
        <published>2009-01-15T00:00:00+00:00</published>
        <updated>2009-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/01/ddr32010.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/01/ddr32010.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/01/ddr32010.html/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;northwood.blog60.fc2.com&#x2F;blog-entry-2568.html&quot;&gt;ネタ元&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;元々IntelもAMDもDDR3への完全移行を2009年としていたが、マザーボードメーカーの情報によると、現在ではどちらもDDR3のみ対応のチップを延期しており、2010年まで登場しないようだ。
DDR3メモリの価格がIntelが期待していたよりも下がらず、さらにCore i7とX58の需要も予想よりも下回ったため、IntelはDDR3のみの5 seriesチップセットを9月に延期した。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;このIntelの言い分は本当なのかな。&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;shop.kingston.com&#x2F;PartsInfo.asp?ktcpartno=KVR1066D3E7&#x2F;2G&quot;&gt;DDR3のメモリECC付きでも&lt;&#x2F;a&gt;結構安いと思いますが。&lt;&#x2F;p&gt;
&lt;p&gt;AMDと同じようにコンパチビリティの問題でもあるのかな？
あるいはCorei7自体があまりにも人気が無いとか。&lt;&#x2F;p&gt;
&lt;p&gt;TDPが90w位に下がってくれれば使ってみたい気がしますが。
まだ、時期尚早なんでしょうか？&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intelの爆速SSD</title>
        <published>2009-01-13T00:00:00+00:00</published>
        <updated>2009-01-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/01/intelssd.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/01/intelssd.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/01/intelssd.html/">&lt;p&gt;Intelの爆速SSD、X25-Eを評価中です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2009&#x2F;01&#x2F;intelssd.html&#x2F;image&#x2F;dscn7883_2.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;公称性能 シーケンシャルリード250MB&#x2F;s、シーケンシャルライト170MB&#x2F;s
結果は、やはり爆速でした。
詳しくは、&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.clustcom.com&#x2F;content&#x2F;view&#x2F;159&#x2F;32&#x2F;&quot;&gt;評価レポート&lt;&#x2F;a&gt;をご参照ください。&lt;&#x2F;p&gt;
&lt;p&gt;評価をしてくれたのは、アルバイトの須永くんです。
須永くんはSFCの3年生です。
須永くん、ありがとう。&lt;&#x2F;p&gt;
&lt;p&gt;これだけ速いと、RAIDで8本束ねれば、1GB&#x2F;s越えが狙えるかもしれませんね。
楽しみです。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>小さな会社の儲けのルール</title>
        <published>2009-01-02T00:00:00+00:00</published>
        <updated>2009-01-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/01/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/01/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/01/blog-post.html/">&lt;p&gt;という本があります。創業当時何度も読み返し、勇気をもらった一冊です。
その本を久々に開いてみると、こう書いてある&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「思いは実現する」に必要なこと
こういう話をすると大体「いやー、そんなに働かなくてもいいでしょう」と言われます。でも、一代で何かを成し遂げた人たちがどのくらい働いていたか知っていますか？世界の偉人伝などを読んで概算すると、エジソンは年間6500時間で、それを40年間。キュリー婦人も5000時間を35年はやっていますね。本田宗一郎さんは一代で世界の本田を作った人ですが、あの方も5500時間を35年やっています。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;年間6500時間というと一日17.8時間を365日、5000時間だとしても13.7時間を365日働き続けたことになる。&lt;&#x2F;p&gt;
&lt;p&gt;それに比べると何と自分の甘いことか。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>今年の目標</title>
        <published>2009-01-02T00:00:00+00:00</published>
        <updated>2009-01-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2009/01/blog-post_03.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2009/01/blog-post_03.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2009/01/blog-post_03.html/">&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;年間4,500時間働く&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;売り上げ4倍増&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;マーケティングがちゃんとできるようになる&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;体重15kg減&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;洋服に気を使う(毎月洋服を買う)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>本家Linuxカーネルに採用されました！</title>
        <published>2008-11-07T00:00:00+00:00</published>
        <updated>2008-11-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/11/linux.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/11/linux.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/11/linux.html/">&lt;p&gt;うちのmitake君が書いてくれたEDACドライバが、メインラインカーネルに採用になりました。
http:&#x2F;&#x2F;www.kernel.org&#x2F;pub&#x2F;linux&#x2F;kernel&#x2F;v2.6&#x2F;testing&#x2F;ChangeLog-2.6.28-rc3&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;commit df8bc08c192f00f155185bfd6f052d46a728814a
Author: Hitoshi Mitake
Date:   Wed Oct 29 14:00:50 2008 -0700&lt;&#x2F;p&gt;
&lt;p&gt;edac x38: new MC driver module&lt;&#x2F;p&gt;
&lt;p&gt;I wrote a new module for Intel X38 chipset.  This chipset is very similar
to Intel 3200 chipset, but there are some different points, so I copyed
i3200_edac.c and modified.&lt;&#x2F;p&gt;
&lt;p&gt;This is Intel&#x27;s web page describing this chipset.
http:&#x2F;&#x2F;www.intel.com&#x2F;Products&#x2F;Desktop&#x2F;Chipsets&#x2F;X38&#x2F;X38-overview.htm&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve tested this new module with broken memory, and it seems to be working
well.&lt;&#x2F;p&gt;
&lt;p&gt;Signed-off-by: Hitoshi Mitake
Signed-off-by: Doug Thompson
Signed-off-by: Andrew Morton
Signed-off-by: Linus Torvalds&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;先日本ブログで紹介したIntelの2in1サーバ(SR1520ML)には、X38チップセットが搭載されています。このチップセットはECCメモリに対応しているので、1ビットエラーは訂正、2ビットエラー以上は検出可能です。&lt;&#x2F;p&gt;
&lt;p&gt;Linuxカーネルでは、この様なECCイベントをEDACというモジュールで検出することが可能なのですが、今までは、X38用のEDACドライバが存在していなかったので、検出できていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;それをmitake君が書いてくれたと言う訳です。&lt;&#x2F;p&gt;
&lt;p&gt;いずれ世界中のLinuxマシンに彼の書いたプログラムがのるわけで、これって、とてもすごいことだと思います！&lt;&#x2F;p&gt;
&lt;p&gt;mitake君、おめでとう！&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>信用三本柱</title>
        <published>2008-11-02T00:00:00+00:00</published>
        <updated>2008-11-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/11/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/11/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/11/blog-post.html/">&lt;p&gt;コンピューターのパーツの中で、ハードディスクが一番壊れやすい。
弊社で販売したサーバのハードディスクが故障した場合に迅速に対応できるように、富山の置き薬を真似て、客先に予備のHDDを置かせて頂くサービスを開始した。&lt;&#x2F;p&gt;
&lt;p&gt;名付けて、「富山的電脳薬箱」&lt;&#x2F;p&gt;
&lt;p&gt;それに関連して、富山の薬売について、ネット上でいろいろ調べていたところ、次の様な商売の基本ともいえる心構えについての記述があったので、紹介したい。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.zenhaikyo.com&#x2F;history&#x2F;index.html&quot;&gt;「おきぐすりの歴史」&lt;&#x2F;a&gt;より。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;三本柱とは「商いの信用」、「くすりの信用」、そしてもうひとつが「人の信用」です。
　「商いの信用」の基本は、顧客との間にトラブルを起こさず、不正な商いをしないということです。一円の勘定も誤りなく正確に取引することで信頼関係が生まれます。
　「くすりの信用」は、有効で安全な品質の高いくすりを提供することです。そのために、絶えず顧客の求めるくすりをリサーチし、品質開発に努めなければなりません。
　「人の信用」はもっとも重視されました。顧客の悩み相談に乗って、適切なアドバイスを行ったり、励ましたりすることで信頼関係が作られています。
　「くすりを売るのではなく、人間を売れ。顧客は人間を見てくすりの信用、イメージをつくる」という考え方が、人材開発を促し、くすりの量産化につながり、販売の拡大をもたらしたのです。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;誠にもっともな考え方であり、しかも記憶にとどめやすい。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intel 2in1 サーバーはコストパフォーマンスが高い</title>
        <published>2008-11-02T00:00:00+00:00</published>
        <updated>2008-11-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/11/intel-2in1.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/11/intel-2in1.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/11/intel-2in1.html/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.clustcom.com&#x2F;content&#x2F;view&#x2F;153&#x2F;34&#x2F;&quot;&gt;IntelのベアボーンSR1520MLを使ったローコストサーバ。&lt;&#x2F;a&gt;
同等スペックの1Uサーバ二台分のよりも、10万円以上安価です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;11&#x2F;intel-2in1.html&#x2F;image&#x2F;dsc_0838.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Quad Core プロセッサ対応のマザーボード、X38MLが二枚搭載されています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;11&#x2F;intel-2in1.html&#x2F;image&#x2F;dsc_0840.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;X38MLは一枚で、Gigabit Ether 2ポート, IPMIオンボード搭載、メモリスロット4つ(最大容量8GByte)、高速なQuadCoreプロセッサを搭載可能等といった特徴があります。&lt;&#x2F;p&gt;
&lt;p&gt;電源共通のためメンテナンス性は若干落ちますが、省スペースで高性能。&lt;&#x2F;p&gt;
&lt;p&gt;HPCクラスタの計算ノードや、大規模WEBクラスタのノードにいかがでしょうか。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>Intelの2in1サーバがイケてる</title>
        <published>2008-09-20T00:00:00+00:00</published>
        <updated>2008-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/09/intel2in1.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/09/intel2in1.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/09/intel2in1.html/">&lt;p&gt;発売は一年近く前になりますが、Intelの2in1サーバ、SR1520MLが意外とイケてることに気付きました。奥行き短めの1Uサーバに、i3200X38ML(10&#x2F;2修正)のマザーボードが二枚はいります。何故最初はピンと来なかったのにイケてると思うようになったのか？&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;　45nmのハイスペッククアッドコアCPUがそこそこ安価になった。&lt;&#x2F;li&gt;
&lt;li&gt;　45nmのデュアルコアCPUが1万円以下で手に入るようになった。&lt;&#x2F;li&gt;
&lt;li&gt;　i3200x38 expressチップセット(10&#x2F;2修正)はLinux EDACによるメモリエラー検出ができなかったが、うちのmtk君がドライバを書いてくれた。近日メインライン(2.6.28位か？)にマージされると期待。&lt;&#x2F;li&gt;
&lt;li&gt;　2.5inch HDDが、それぞれ一個ずつしか載らないのがイケてないように思っていたが、WDのScorpio Black(7200rpm)が意外と速いことがわかった。(今時2.5inchHDDでも探せば速いのがある。VelociRaptorなんか、高いけど、超速そう～)&lt;&#x2F;li&gt;
&lt;li&gt;　BMCオンボードであることに気付いた。すなわちIPMI2.0で電源ON&#x2F;OFFとか、SOL(Serial (console) Over Lan)が使える。&lt;&#x2F;li&gt;
&lt;li&gt;　仕入値が意外と安いことに気付いた。同スペックのサーバx2 - 10万円で、販売できそう。
といったことが、理由です。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;つまり、ハイスペックCPU+省スペース+ローコスト+いろいろ便利、なサーバなわけです。&lt;&#x2F;p&gt;
&lt;p&gt;シングルソケットのNehalemが出回るまで、約一年。アレゲ(？)なサーバとして我が社でも商品化しようと思います。&lt;&#x2F;p&gt;
&lt;p&gt;WEBクラスタ、HPCクラスタのノードとして、結構良いかもと思っています。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>オリジナリティ</title>
        <published>2008-07-17T00:00:00+00:00</published>
        <updated>2008-07-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/07/blog-post_17.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/07/blog-post_17.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/07/blog-post_17.html/">&lt;p&gt;商売で何とか生き残るためには、オリジナリティとかクールさなんかなくても、顧客が求めるものを提供していくことが必要だと思う。でも、それだけじゃつまらないよね。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>「やらなければいけないこと」と「やりたいこと」の違いを意識しないといけない</title>
        <published>2008-07-02T00:00:00+00:00</published>
        <updated>2008-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/07/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/07/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/07/blog-post.html/">&lt;p&gt;例えば、日常のタスク次の様に属性分けしてみるとする。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;「やりたいこと」、「やりたくないこと」&lt;&#x2F;li&gt;
&lt;li&gt;「やれること」、「やれないこと」&lt;&#x2F;li&gt;
&lt;li&gt;「やらなくてもいいこと」、「やらなければいけないこと」&lt;&#x2F;li&gt;
&lt;li&gt;「やった方が良いこと」、「やらない方が良いこと」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;結局、取り掛かるのは、この中の「やりたいこと」「やれること」「やらなければいけないこと」、「やった方が良いこと」のいずれかの属性を持つものになるだろう。&lt;&#x2F;p&gt;
&lt;p&gt;当然、業務の中では「やらなければいけないこと」「やった方が良いこと」を、一生懸命やらないといけない。&lt;&#x2F;p&gt;
&lt;p&gt;しかしながら、中には、「やりたいこと」の属性しか持たないものばかりを、一生懸命やってしまう人がいる。「やりたいこと」に情熱を燃やすのは素晴らしいことだが、それが業務と勘違いしてはいけない。不幸のもとである。&lt;&#x2F;p&gt;
&lt;p&gt;自分も、若かりし頃、「やりたいこと」ばかりをやって、「仕事してるなぁー」と勘違いしていた記憶がある。&lt;&#x2F;p&gt;
&lt;p&gt;自分のやろうとしていることが、本当に業務として「やらなければいけないこと」なのか、単に自分が「やりたいこと」なのか、よくよく意識していないと不幸である。&lt;&#x2F;p&gt;
&lt;p&gt;その一方で、労働者としての自分自身を振り返ってみると、
「やりたいこと」をやりたい。
でも、「やらなければいけないこと」が残っている。
手が付かないので、「やれること」に取り掛かる。
そして、一日が終る。&lt;&#x2F;p&gt;
&lt;p&gt;こんなことばかり、繰り返して来た。
あーあ、「やりたいこと」しかやらなくて良い職業に付きたいよー、とぼやいてみてもそんなのある訳無い。&lt;&#x2F;p&gt;
&lt;p&gt;「やりたいこと」=「やらなければいけないこと」なら良いのに。&lt;&#x2F;p&gt;
&lt;p&gt;でも、そうじゃないことが多い。&lt;&#x2F;p&gt;
&lt;p&gt;Just Do itの精神で片っ端から片付けて行くしか無い。&lt;&#x2F;p&gt;
&lt;p&gt;ひでぇ文章。&lt;&#x2F;p&gt;
&lt;p&gt;追記： このエントリ自体が、「やらなければいけないこと」からの逃避に他ならない。仕事しろよ&amp;gt;自分&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>SupermicroのIPMI</title>
        <published>2008-04-28T00:00:00+00:00</published>
        <updated>2008-04-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/supermicroipmi.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/supermicroipmi.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/supermicroipmi.html/">&lt;p&gt;最近のIPMIカードは、KVM(Keyboard Video Mouse) over LANとかがついていて、HTTPとか、SSHとか喋るので非常に使いにくかったのですが、古き良き時代のベーシックなIPMIカードが、Supermicroより発売されました。Supermicroのエンジニアにしつこく催促したのが功を奏したのかも知れません。&lt;&#x2F;p&gt;
&lt;p&gt;http:&#x2F;&#x2F;www.supermicro.com&#x2F;manuals&#x2F;other&#x2F;AOC-SIMSOLC-HTC.pdf&lt;&#x2F;p&gt;
&lt;p&gt;UDPの623のみを、SMBusに流すというわかりやすい仕様なので、ホストと同じIPを使うのも問題無さそうな気がします。&lt;&#x2F;p&gt;
&lt;p&gt;ボンディング使用時には、別IPにした方が無難ですが。。。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>仮想化ブートキャンプ</title>
        <published>2008-04-20T00:00:00+00:00</published>
        <updated>2008-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_21.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_21.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_21.html/">&lt;p&gt;先週一週間、主要顧客のトップエンジニアの方々と、データセンターのサーバーを仮想サーバ上へ移行するための、インフラ開発作業を相模大野オフィスで行った。作業は、朝から夜の11時すぎ迄におよび、さながらブートキャンプの様相であった。
XenとKVM(Kernel Virtual Machine)の両睨みであるが、KVMの方が扱いやすいように思う。ツール群の充実、実績についてはXenの方が一歩先んじているが、KVMの場合は、ホストゲストともLinuxバニラカーネルで良くLinuxカーネルの機能がそのまま使え(例えばEDACなど)、非常に素直である。Xenの場合、Domain0カーネルは、2.6.18.8にパッチを当てまくったものを、xensourceで管理しておりこれが良くない。現時点で、3wareRAIDコントローラが全く使いものにならない。何で、バニラカーネル各バージョンへのパッチとして提供できないかな。
私個人としては、KVM最高、Xen最悪みたいな印象。
お客さんが一週間来るとさすがに気疲れします。最終日、相模大野叙々苑での焼肉パーティでリフレッシュ。おいしかった。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>メガネ購入</title>
        <published>2008-04-20T00:00:00+00:00</published>
        <updated>2008-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_5138.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_5138.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_5138.html/">&lt;p&gt;以前はメガネを使用していたのですが、ここ何年かずっと使い捨てのコンタクトレンズを使用していました。しかし、最近、目が充血することも多く、ちょっと前に は結膜炎にかかり目脂で目もほとんど開けられないような状態のなか、仕事をしなければならなかったこともあり、久々にメガネを作りました。
主に、休日ちょっと車で出かける時などに使用できれば良いので、ちょこっと色も入っています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;04&#x2F;blog-post_5138.html&#x2F;image&#x2F;p1000061.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>KVMフォーラム行きたい。。。</title>
        <published>2008-04-20T00:00:00+00:00</published>
        <updated>2008-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/kvm.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/kvm.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/kvm.html/">&lt;p&gt;けど、先立つものが。。。
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kforum.qumranet.com&#x2F;KVMForum&#x2F;about_kvmforum.php&quot;&gt;http:&#x2F;&#x2F;kforum.qumranet.com&#x2F;KVMForum&#x2F;about_kvmforum.php&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>仕事の中心</title>
        <published>2008-04-10T00:00:00+00:00</published>
        <updated>2008-04-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_10.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_10.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_10.html/">&lt;p&gt;仕事の中心は楽しさになければいけないと思う。
新しいことにどきどき、わくわくしながら挑戦できる。そんな会社にしたい。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>キャリアプランニング</title>
        <published>2008-04-10T00:00:00+00:00</published>
        <updated>2008-04-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_9960.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_9960.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_9960.html/">&lt;p&gt;最初に、スタッフのキャリアプランニングを一緒になって考えたい。
誰もが、一流のプロフェッショナルとして独り立ちできるように、成長して欲しい。
将来像が見えれば、モチベーションも高くなるだろうし、いわゆるself motivating personになるだろう。&lt;&#x2F;p&gt;
&lt;p&gt;会社の仕事はスタッフのキャリアパスにすり合わせるようにすべきだ。
スタッフが日々成長し結果を残せるようになれば、できないはずは無い。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ありがとう</title>
        <published>2008-04-08T00:00:00+00:00</published>
        <updated>2008-04-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_08.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_08.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_08.html/">&lt;p&gt;ありがとうと言われるような仕事をしたい。&lt;&#x2F;p&gt;
&lt;p&gt;お客に「ありがとうございます」と言うのが普通だと思われているかもしれないが、それは間違っている。何故なら、お客は金額以上の価値を感じるからこそ、購入を決めるから。本来「ありがとう」と言われるのは、サービスを提供する側で無ければならない。&lt;&#x2F;p&gt;
&lt;p&gt;そのためには、常にサービスの価値を高める努力をしなければならない。愛想も大切であるが、本来の努力を怠ってはならない。&lt;&#x2F;p&gt;
&lt;p&gt;また、お客に「ありがとう」と言われる商売程楽しいものはない。&lt;&#x2F;p&gt;
&lt;p&gt;Inspired by 神田昌典&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>人材の流動性</title>
        <published>2008-04-05T00:00:00+00:00</published>
        <updated>2008-04-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_5048.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_5048.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_5048.html/">&lt;p&gt;優れた才能の持ち主が、組織の中で腐っていったり、精神的に病んでしまうのは絶対おかしい。
企業側の飼い殺しは良くないし、雇われる側がフィットしないところにいつまでもしがみつくのはもっとダメ。&lt;&#x2F;p&gt;
&lt;p&gt;今の世論に逆らうようだけど、安定した正社員にこだわらずに、自分が活躍するところを求めて自由に転職できるようにならないといけないと思う。&lt;&#x2F;p&gt;
&lt;p&gt;そうしないと、才能が埋もれ、外国にどんどん引き離されてしまう。&lt;&#x2F;p&gt;
&lt;p&gt;新しい働き方、フリーエージェントなんかどうだろう？&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;かけ持ちで良い&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;勤務日には期待されるアウトプットをきっちり出すこと&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;かけ持ちを認めるが故に、情報をミックスしない心がけ、脳内iptablesが必要である&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;顧客や、契約に関する情報、顧客との取り決めで公にできない情報、公知でない新規技術情報等については、守秘義務を尊守する
それを実現するために必要なこと&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;個々のスキルが、一社のみならず、広く業界で通用することが必要。すなわち常にスキルアップする必要あり&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;経験が浅くスキルが完璧でなくても、その人なりに雇主からメリットと認められるアウトプットを出せることが必要&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;フィットしなければ、後腐れなく一端離れれば良い&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;うまくいかないことは、たまたまその時ニーズとスキルがマッチしないだけ
もちろん、正社員とそうでない人が同じ仕事をして、同じような成果を出した場合、給与に格差があってはならない。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;そもそも、正社員ってなんだろう？
ハローワークに募集要項を出す際には、フルタイムかパートタイムの区別しか無い。
労働基準法的には、正社員も契約社員も区別が無いって、社労士さんが言っていた(要確認)。&lt;&#x2F;p&gt;
&lt;p&gt;最近はそうでも無いのかも知れないが、キャリアの大半を一社のみで過ごし、ほとんど会社の人としか接することが無い人生なんて寂しくないか？
だから、私は会社を飛び出した。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>六本木ヒルズ</title>
        <published>2008-04-05T00:00:00+00:00</published>
        <updated>2008-04-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_8569.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_8569.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_8569.html/">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;04&#x2F;blog-post_8569.html&#x2F;image&#x2F;p1000020.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;昨日六本木ヒルズに行って来ました。&lt;&#x2F;p&gt;
&lt;p&gt;以前、半常駐的に仕事させて頂いていた客さんでの、新規案件の打ち合せです。&lt;&#x2F;p&gt;
&lt;p&gt;不思議なオブジェ。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;04&#x2F;blog-post_8569.html&#x2F;image&#x2F;p1000021.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;植え込みの花がきれいに咲いていました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ktaka.blog.ccmp.jp&#x2F;2008&#x2F;04&#x2F;blog-post_8569.html&#x2F;image&#x2F;p1000022.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ブログの情報は良くないこともある。</title>
        <published>2008-04-02T00:00:00+00:00</published>
        <updated>2008-04-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/04/blog-post_03.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/04/blog-post_03.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/04/blog-post_03.html/">&lt;p&gt;Linuxやネットワークなどの仕事をしていると、必要そうな技術情報はインターネット上に溢れている。なので、何かわからないことがあると、「グーグル先生に聞いてみよう♪」となることも多い。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、検索に引っかかって来た情報を鵜呑みにしてはいけないと思う。&lt;&#x2F;p&gt;
&lt;p&gt;時々うんざりするのが、「〜について調べといてくれない？」と頼んだ時に、日本語ブログのURLがいくつも返ってくること。&lt;&#x2F;p&gt;
&lt;p&gt;そういう人って、「こうすれば動くみたいだよ」的な答えしか持っていなくて、まあ、要するに良くわかっていない。&lt;&#x2F;p&gt;
&lt;p&gt;かく言う自分も、質問されて良くわからない時に、URLをもって答えとする(笑)ことがある(反省)。&lt;&#x2F;p&gt;
&lt;p&gt;そんなレベルなら、自分でグーグル先生に聞きますよ。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;少なくとも、自分の言葉で説明して欲しい&lt;&#x2F;li&gt;
&lt;li&gt;オフィシャルなドキュメント(あれば)かデベロッパーのメーリングリスト位あたって欲しい&lt;&#x2F;li&gt;
&lt;li&gt;願わくば、ソースを拾って来て、grepかけて欲しい
昔、WEBなんかまだ無かったころ、某F2研究所の上司が口をすっぱくして説いていたことを思い出す。(当時はCMOSのプロセスデバイスの研究をしていました。)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「オリジナルの論文をあたりなさい」&lt;&#x2F;p&gt;
&lt;p&gt;彼は、解説書すら否定していた。&lt;&#x2F;p&gt;
&lt;p&gt;何が言いたいかというと、なるべくオリジナルな一次情報にあたることが大切であるということ。&lt;&#x2F;p&gt;
&lt;p&gt;エセ技術情報が溢れているいま、一次情報を選別し、そこから体系的知識を学び取るスキルが必要である。&lt;&#x2F;p&gt;
&lt;p&gt;と書きつつ、「エセ技術情報」を垂れ流す自分に再び深く反省。&lt;&#x2F;p&gt;
&lt;p&gt;まあ、心がけということで。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>月末処理に忙殺される</title>
        <published>2008-03-31T00:00:00+00:00</published>
        <updated>2008-03-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/03/blog-post_31.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/03/blog-post_31.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/03/blog-post_31.html/">&lt;p&gt;月末の入金確認と請求書の発行。買掛支払い。給料、家賃の支払。毎月のことながら骨が折れる。こういう経理処理を任せられる人がいるとすごく助かるのだが、お金のことだけに気が引ける。ましてや、うちみたいに規模が小さいと、頑張れば、自分と奥さんとで何とかなってしまうので、なかなか人に任せることができない。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>毎日少しずつ書いてみよう</title>
        <published>2008-03-26T00:00:00+00:00</published>
        <updated>2008-03-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/03/blog-post_26.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/03/blog-post_26.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/03/blog-post_26.html/">&lt;p&gt;ブログをはじめようと思ったはいいけど、なかなか書けない。毎日必ず、書く時間を設けるようにしよう。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>クレーム</title>
        <published>2008-03-26T00:00:00+00:00</published>
        <updated>2008-03-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/03/blog-post_5074.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/03/blog-post_5074.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/03/blog-post_5074.html/">&lt;p&gt;神田昌典３６５日語録より、「クレームの質が変わっている。お客は品質ではなく、自分が大切にされないことに不満を抱いている。」
なるほど、技術的にトラブルを解決することも大切ですけど、相手の立場にたって対応することが大切なんだなぁ。&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ja">
        <title>ブログことはじめ</title>
        <published>2008-03-18T00:00:00+00:00</published>
        <updated>2008-03-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ktaka.blog.ccmp.jp/2008/03/blog-post.html/"/>
        <id>https://ktaka.blog.ccmp.jp/2008/03/blog-post.html/</id>
        
        <content type="html" xml:base="https://ktaka.blog.ccmp.jp/2008/03/blog-post.html/">&lt;p&gt;ブログと言うものを始めてみようと思います。どんな内容にしようかな。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自分の会社のこと&lt;&#x2F;li&gt;
&lt;li&gt;Linuxやネットワークのこと&lt;&#x2F;li&gt;
&lt;li&gt;その他、いろいろ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
</feed>
