カテゴリー: ガジェット Page 1 of 104

LAMPサーバの一覧を表示するワンライナー。

UbuntuのLAMPサーバの環境確認に使える一式のワンライナーの紹介です。

 echo -e "| Item | Version / Status |\n|:---|:---|\n| **OS** | $(lsb_release -d | cut -f2) |\n| **Memory** | $(free -h | awk '/^Mem:/ {print $2" (Used: "$3")"}') |\n| **Web Server** | $({ apache2 -v 2>/dev/null || nginx -v 2>&1; } | head -n 1 | sed 's/^[ \t]*//') |\n| **PHP** | $(php -v 2>/dev/null | head -n 1 | cut -d' ' -f1,2 || echo "Not Installed") |\n| **PHP-FPM** | $(systemctl list-units --type=service | grep -o 'php[0-9.]*-fpm' | tr '\n' ' ' | xargs || echo "Not Running") |\n| **DB** | $(mysql -V 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 | sed 's/^/MySQL /' || psql --version 2>/dev/null || echo "Not Installed") |\n| **Node.js** | $(node -v 2>/dev/null || echo "Not Installed") |\n| **Python** | $(python3 -V 2>/dev/null || echo "Not Installed") |\n| **Ruby** | $(ruby -v 2>/dev/null | cut -d' ' -f1,2 || echo "Not Installed") |"

全体の構造

このコマンドは echo -e を使用して、1つの大きな文字列を出力しています。

  • | Item | ... |:Markdownの表ヘッダーを作成しています。
  • $( ... )コマンド置換と呼ばれる仕組みです。カッコ内のコマンドを先に実行し、その結果を文字列の中に埋め込みます。

各項目の詳細解説

項目実行している処理の内容
OSlsb_release -d でOSの説明行を取得し、cut -f2 でタブ以降のOS名(Ubuntu…など)だけを抜き出しています。
Memoryfree -h でメモリ情報を取得。awk を使って「全容量($2)」と「使用量($3)」を抽出して整形しています。
Web Server{ apache2 -v || nginx -v } で両方を試し、見つかった方の1行目を表示。sed で行頭の余計な空白を消しています。
PHPphp -v の1行目から、cut を使って「PHP 8.x」のような名称とバージョンのみを取得しています。
PHP-FPMsystemctl で起動中のサービス一覧から php*-fpm に一致するものを探し、trxargs で横一列に並べています。
DBまず mysql -V を試し、バージョン番号を正規表現で抽出。それがなければ psql(PostgreSQL)を確認します。
Node / Pythonそれぞれ -v または -V オプションでバージョンを確認。インストールされていなければ "Not Installed" を返します。
Rubyruby -v の結果から、最初の2単語(例:ruby 3.x)だけを抜き出しています。

出力イメージ

実行すると、以下のような表がターミナル(またはMarkdown対応のエディタ)に表示されます。

ItemVersion / Status
OSUbuntu 24.04.4 LTS
Memory5.8Gi (Used: 3.8Gi)
Web ServerServer version: Apache/2.4.58 (Ubuntu)
PHPPHP 8.3.30
PHP-FPMphp8.3-fpm
DBMySQL 8.0.45
Node.jsv20.19.2
PythonPython 3.12.3
Rubyruby 3.2.3

サーバー構築直後の確認や、GitHubのIssueに環境情報を貼る際にとても重宝するものです。

Growi v7.5.0のアップデートメモ(nodeのアップデート含む)

Grwoiをv7.5.0にアップデートしたときのメモです。

アップデート概要

  • 対象バージョン: v7.4.7 → v7.5.0
  • 実行環境:
    • Ubuntu 24.04
    • Apache 2.4によるリバースプロキシー

主要な変更点:

  • Node アップデートによる Next.js v16 / Vite v6 / Turbopack への移行
  • リバースプロキシにy-websocket への変更、
  • RegExp.escape() の採用

前提

  • nvmでnodeのバージョンを管理していること。
  • リバースプロキシの変更手順が整っていること。

事前準備・環境更新

最新のGROWI要件に合わせ、Node.jsランタイムをアップデートしました。

-Node.jsの更新:

nvm を使用して v24.14.1 をインストール。 筆者はroot環境で実施しているため

sudo su -

で管理者権限になってから実施しました。

  • nvm バージョンアップ
nvm install 24

bash
nvm use 24

nvm alias default 24
  • ビルドツールの更新:

はまったポイントです。一度バージョンアップするとv24環境で pnpmが消えてしまうので再有効化します。

corepack enable
corepack prepare pnpm@latest --activate

ビルドプロセスの修正

後は基本的に筆者が行っているものに習います。

growiディレクトリに移動します

cd /home/www-data/growi && pwd

自分の環境に合わせます。(筆者環境/home/www-data/growi)

リリースタグを確認します。

  • リリースタグ取得
sudo git fetch --tags
  • リリースタグ確認
sudo git tag -l

スペースで確認していき、上記リリースサイトと同じバージョンがあることを確認します。

チェックアウトとインストールを行います。

  • 変更を一時的に退避
sudo git stash
  • チェックアウト
sudo git checkout 【バージョン】

リリースタグは再確認しましょう。今回は 2026/04/07にリリースされたv7.5.0を選択しました。

メモリ不足の対処

  • pnpm install 時のセキュリティ警告(sharpのビルド停止)およびメモリ不足対策を実施しました。
  • ネイティブバイナリの許可:
    ```bash
    pnpm approve-builds
リストから sharp を選択して許可

bash
pnpm install

- Turbopackによるビルド:

メモリ消費を抑えるため、上限を指定して実行。

bash
NODE_OPTIONS="--max-old-space-size=4096" pnpm run app:build

### リバースプロキシ (Apache) の修正


同時編集プロトコルが `y-websocket` に変更されたことに伴い、`growi.conf` の書き換えルールを厳密化しました。

修正内容: すべてのWS通信ではなく、`/yjs` パスのみをWSプロキシへ流すよう変更。

apache
# リバースプロキシー設定
RewriteEngine on

# 1. /yjs へのアクセスのみ WebSocket プロキシへ飛ばす
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{REQUEST_URI} ^/yjs [NC]
RewriteRule /(.) ws://localhost:3000/$1 [P,L]

# 2. それ以外の通常の HTTP リクエスト
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
```

起動スクリプトの修正

2度目のはまりポイントです。RegExp.escape is not a function エラー(Node.jsのバージョン不足)を解消するため、サービスが参照する PATH を更新しました。
(これは筆者環境なので)

growi-start.sh の修正:

# 旧: v20.19.2 -> 新: v24.14.1
export PATH="/root/.nvm/versions/node/v24.14.1/bin:$PATH"

Growiの再起動

  • Growiサービス開始
sudo systemctl restart growi.service
  • サービス開始確認
systemctl status growi.service

active(running)を確認します。

完了確認

  • [x] 管理画面「システム情報」にて GROWI 7.5.0 / Node.js 24.14.1 を確認。
  • [x] ページリストの取得エラー(APIエラー)が解消されたことを確認。
  • [x] ページ複製時の RegExp.escape エラーが解消されたことを確認。
  • [x] Elasticsearch v9 への接続および検索ができることを確認。

AIツールを狙ったログのメモ

筆者の公開VPSにて、昨今のトレンドと言えるようなログを確認しましたので解説です。

攻撃者のIPやホスト名をダミー(例: ATTACKER_IP, TARGET_IP)に置き換えています。わざわざIP晒しをしないのは「テロリストに名前を与えない」の精神からです。

[DATE] [security2:error] [client ATTACKER_IP_1] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/"]
[DATE] [security2:error] [client ATTACKER_IP_1] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/favicon.ico"]
[DATE] [security2:error] [client ATTACKER_IP_2] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/.git/config"]
[DATE] [security2:error] [client ATTACKER_IP_3] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/api/tags"]
[DATE] [security2:error] [client ATTACKER_IP_3] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/v1/models"]
[DATE] [security2:error] [client ATTACKER_IP_3] ModSecurity: Access denied... [id "10004"] [msg 
[DATE] [security2:error] [client ATTACKER_IP_3] ModSecurity: Access denied... [id "10004"] [msg "Host header is a numeric IP address"] [hostname "TARGET_IP"] [/update_weights_from_tensor]
"Host header is a numeric IP address"] [hostname "TARGET_IP"] [uri "/.well-known/mcp.json"]
[DATE] [security2:error] [client ATTACKER_IP_3] ModSecurity: Access denied... [id "10005"] [msg "Missing Host Header"] [hostname "example.com"] [uri "/"]

解説の前に

  • header is a numeric IP address
  • Missing Host Header

があることに気づく方はいるかと思います。

これは、筆者が導入しているMod_Securityに以下のカスタムルールを設けているからです。

# 1-3. IPアドレス直打ちアクセス対策 
# ポート番号が付いていても即座に拒否する
SecRule REQUEST_HEADERS:Host "@rx ^[\d.]+(:\d+)?$" \
    "id:10004,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Host header is a numeric IP address (incl port). Blocked immediately.',\
    tag:'application-attack',\
    tag:'PROTOCOL_VIOLATION/INVALID_HREQ'"

# Hostヘッダーが存在しない場合は即ブロック
SecRule &REQUEST_HEADERS:Host "@eq 0" \
    "id:10005,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Missing Host Header. Blocked immediately.'"

攻撃の全体的な意図:なぜ「IPアドレス」でアクセスしてくるのか?

ログの多くが 「HostヘッダーがIPアドレスである」 という理由でModSecurity(WAF)に遮断されています。これには以下の意図があります。

  • 無差別スキャン:
    • ドメイン名を知らなくても、IPアドレスの範囲(例: 192.168.0.0/16)を片っ端から叩くことで、管理が甘い「生」のサーバーを見つけ出そうとしています。
  • デフォルト設定の探索:
    • 多くのWebサーバーは、不明なドメインやIP直接指定でアクセスされた際に「デフォルトのバーチャルホスト」を表示します。ここにはテストページや管理ツールが放置されていることが多いため、そこを突こうとしています。
  • WAF/CDNの回避:
    • CloudflareなどのCDNを経由せず、サーバーの「本当のIP」に直接攻撃を仕掛けることで、上位の保護層をバイパスしようとする手法です。

各パス(URI)が狙われた理由とケーススタディ

情報漏洩の古典:/.git/config

  • 意図:
    • Gitリポジトリの露出確認。
  • 背景:
    • 開発者が誤って .git ディレクトリを公開サーバーにアップロードしてしまうミスを狙っています。これが取得されると、ソースコード、DBのパスワード、APIキー、過去の全変更履歴が盗まれます。

AI・LLM時代の新潮流:/v1/models, /api/tags, /api/version

  • 意図:
    • OllamaやLocalAI、OpenAI互換API などのエンドポイント探索。
  • 背景:
    • 昨今、自宅サーバー等でローカルLLMを動かす人が増えています。これらのツールはデフォルトで /v1/models などのパスを使用するため、認証なしでAIリソースを悪用(AI寄生)したり、モデル情報を盗んだりするためにスキャンされています。

2026年での最新トレンドの追跡:/.well-known/mcp.json, agent.json

  • 意図:
    • Model Context Protocol (MCP) 設定ファイルの探索。
  • 背景:
    • MCPは2024年末〜2025年にかけて普及し始めた、AIエージェントとツールを接続するための規格です。これがあるサーバーは「AIエージェントが操作可能なリソース」を持っている可能性が高いため、攻撃者は踏み台やデータ奪取の対象としてリストアップしようとしています。

AI学習モデルの改竄:/update_weights_from_tensor

  • 意図:
    • 学習済みモデルの「重み(Weights)」を外部から直接書き換えようとしています。
  • 背景:
    • もし成功すれば、攻撃者はサーバにインストールされているAIの判断を密かに操作できます。例えば「特定の条件の時だけ誤判定させる(バックドア)」や「特定の顔をスルーさせる」といった、AIジャックが可能です。

監視・インフラの隙:/metrics, /queue/status

  • 意図:
    • Prometheusや監視ツールの露出確認。
  • 背景:
    • /metrics にはサーバーの負荷、プロセス一覧、時には内部ネットワークの構成情報がプレーンテキストで出力されます。攻撃者にとっては、攻撃の戦略を立てるための「設計図」を手に入れるようなものです。

ここから得られること

総括

「攻撃者はドメイン名で選んでいるのではない。露出している機能(Git, AI API, 監視ツール)をポートスキャンとパス探索で機械的に探り当てている」

今後の教訓:

  • ホワイトリスト運用:
    • /api//metrics などのパスは、特定のIP以外からは404にしましょう。
  • 「隠しファイル」の禁止:
    • .git.env など、ドットで始まるディレクトリへのアクセスはWebサーバーレベルで一括拒否しましょう。

いくら最新の(今回のようなAIサーバ)を狙ったところで

  • 「対策の甘いところから狙われる」
  • 公開されたらヤバいところは共有される

という普遍性は同じ。それこそ『緋色の研究』でホームズが言う

「日の下に新しきものなし」 (Nihil novi sub sole)

ぐらいの勢いで、基本的な対策をしていきましょうという話でした。

TS-216GにSSL証明書を設定。

QNAP、Web管理画面へのアクセスがhttp通信のためブラウザで「保護されていない通信」と出てしまいます。

ローカル運用だからといっても多くのマルウェアは「ついでに」というより「こっちが本命」と言わんばかりにNASを狙うパターンが多いため、
(↑ 建前 ↑)
(↓ 本音 ↓)
こちらの美意識にそぐわないためSSL証明書を自前で設定します。

環境

別に以下の環境があることが要件です。

  • インターネットに接続されているLinuxサーバ。
    • Let's Encrypt(certbot)導入済み
  • 独自ドメインがあること。
    • そのDNSレコードを設定することができること。

さっくりとした手順

  1. certbotで証明書を発行します。
  2. 適切な手段でローカル環境に保存します。
  3. NAS(TS-216G)に適用します。

Let's Encryptで証明書を発行。

  • 証明書発行

以下、

  • -d ドメイン
  • -m 自分のメールアドレス

に置き換えます。

sudo certbot certonly --manual \
-d star.hoge.example.com \
-m hoge@example.com \
--agree-tos \
--key-type rsa \
--preferred-challenges dns-01

この、key-type rsaを付けなかったことがはまりポイントでした。というのも、ここ数年、Let's EncryptはECDSA方式をデフォルトで発行していますが、QNAPのOSは最新の暗号化に対応していません。そのため、RSAと「強度を下げて広く使われる形式」と明示する必要があります。

  • ドメイン所有者手続き

その後、DNSで、指定されたTXTレコードを登録せよという指示がありますので、それに従ってDNSを設定します。

このとき、TTLは60などと極めて短い時間にしておくと良いでしょう。(3600などとするとかなり待たされます)

証明書の整合性を確認

  • 90日の有効期限であることを確認します。

以下、自分が発行したドメインに基づく証明書や秘密鍵に読み替えます。

sudo openssl x509 -noout -dates -subject -in /etc/letsencrypt/live/star.hoge.example.com/fullchain.pem
notBefore=May 17 04:35:55 2025 GMT
notAfter=Aug 15 04:35:54 2025 GMT

のように90日間であることを確認します。

  • 確認1. 証明書から公開鍵データを確認
sudo openssl x509 -pubkey -in /etc/letsencrypt/live/star.hoge.example.com/fullchain.pem -noout | openssl md5
  • 確認2. 秘密鍵から公開鍵を取得
sudo openssl pkey -pubout -in /etc/letsencrypt/live/star.hoge.com/privkey.pem | openssl md5

→ 確認1/確認2で出てきた公開鍵のハッシュ値が一致していればOKです。

SSL証明書と秘密鍵をローカル環境に保存

発行されたら、以下のファイルを適切な方法でローカルに保存します。

  • /etc/letsencrypt/live/star.hoge.example.com/fullchain.pem
  • /etc/letsencrypt/live/star.hoge.com/privkey.pem

この時の保存はcatコマンドで表示して自分の環境にファイルを貼り付けるのが結果的に効率的ではありますが、privkey.pemは管理者権限でしか読めない(600)となっているため、

sudo cat /etc/letsencrypt/live/star.hoge.com/privkey.pem

としないと閲覧できません。

そうしてローカル環境に保存します。

QNAPへの運用

  1. ブラウザでQTSにログインし、[コントロールパネル] を開きます。
  2. [システム] > [セキュリティ] の順に進みます。
  3. 上部のタブから [証明書とプライベートキー] を選択します。
  4. [証明書の置換] ボタンをクリックします。
  5. 「証明書のインポート」を選択し、以下のファイルをそれぞれアップロードします。
  • 指定するファイルの対応表
項目ファイルの種類内容
プライベートキー**.key証明書発行時に生成した秘密鍵
証明書.crt または .pem認証局から発行されたドメイン証明書
中間証明書 (任意).crt または .pem認証局のチェーン証明書(推奨)
  1. [適用] をクリックします。これで、NASのWeb管理画面(HTTPS)に証明書が適用されます。

適用後の確認

設定が完了したら、以下の点を確認してください。

  • ブラウザの鍵マーク: NASにドメイン名(例:https://star.hoge.example.com:8081)でアクセスし、ブラウザのURL横にある鍵アイコンが正常(「この接続は保護されています」)になっているか確認します。
  • 有効期限: QTSの「証明書とプライベートキー」画面で、表示されている有効期限が正しいか確認します。

注意点とTips

証明書一式をインポートしたのに適用できない

ECDSA形式で発行しているパターンがほぼ大多数です。筆者はこれに一週間ほどハマり、「自分のブログメモ」に助けられました。

ポート開放とアクセス

自前証明書を適用しても、ローカルIPアドレス(192.168.x.x)でアクセスした場合は「保護されていない通信」と表示されます。必ず証明書に記載されたドメイン名でアクセスしてください。

しかし、これはある意味チャンスです。Let's Encryptは90日しか有効期限がないため、期限切れで

https://star.hoge.example.com:8081

とアクセスした場合、ブラウザでエラーが出ますが、ローカルIPアドレス直打ちはその範疇ではありません。

証明書の更新

自前の証明書(特に Let's Encrypt 以外を外部で取得したもの)は自動更新されません。有効期限が切れる前に、上記の手順で新しいファイルを再度インポートする必要があります。

myQNAPcloud を利用している場合

もし myQNAPcloud の DDNS 機能を利用している場合、QTS側で「myQNAPcloud証明書」が優先されていることがあります。その場合は、上記手順の「証明書の置換」で自前のものを優先するように設定を変更してください。

NAS移行後の展望。

  • 初期設定
  • NAS構築後のHDD初期不良

を乗り越え、無事に移行も完了。次のフェイズに関する簡単なメモです。

宅内サーバ環境の刷新。

さすがにUbuntu 20.04が動き続けるというのは忍びないので、これもHWを変えたいです。昨今、ミニPCも高くなってきているのでその辺は様子を見ながら。

それこそ転がっているノートPCあたりをベースにするのも視野に入れています。

旧NASの外部ディスク転用。

2015年に購入したNASですが、メインのストレージではなく、先のサーバ環境の外部ディスクとして用いるには十分。(さすがにこの際はディスクを変えないとですが)

いずれにしても、これまでのデータを複数取り込むことができたのはありがたい限り。

余談

膨大な写真データのなから、コーンウォールを訪れた際のこういう写真を発掘できたのは割と収穫です。

Growi環境:axiosサプライチェーンの影響確認。

2026年3月31日に発覚したaxiosのサプライチェーン攻撃

内容を聞くだけでゾッとする話だったので、調べつつ筆者がインターネット上に設置しているgrowiサーバでの影響を調べました。

筆者環境

  • Growi v7.4.7
  • npm 11.4.0
  • Apache 2.4によるリバースプロキシー
  • Ubuntu 24.04

自環境の白黒確認

まずは、動いている環境のaxiosバージョンを特定することが最優先。筆者はこのライブラリを恥ずかしながら聞くまで知らなかったのですが 、JavaScriptのデファクトスタンダード的なHTTPクライアントライブラリ と聞いたので「絶対に入っているだろう」の断定で動きました。

調査コマンド

  • Growiのルートディレクトリに移動
cd /path/to/growi

自分の環境に合わせます(筆者環境/home/www-data/growi)

  • インストール済みaxiosの調査 
npm ls axios

または

 cat pnpm-lock.yaml |grep axios
  • 調査結果
axios@1.11.0

axios@0.26.1

axios@0.21.4

判定:安全

影響を受けるバージョンは

  • axios@1.14.1
  • axios@0.30.4

そのため、攻撃対象となったaxiosを利用していない(つまり、攻撃コードは混入していない)ものとなっています。

念のための確認

ほぼないとは思いますが「npm updateを実行してしまったかも」の場合は、今回のケースで攻撃者が埋め込んだマルウェアが生成するディレクトリの有無を調べます。

find node_modules -name "plain-crypto-js"

結果、何もなければ物理的にもクリーンです。

また、筆者は該当vpsでBookStackやsnipe-itなどのLaravelライブラリを動かしていますが

cd /path/to/BookStack && pwd
npm ls axios
BookStack@ /home/www-data/BookStack

└── (empty)

と、いずれも(PHPメインであるためか)動いていない状態が分かりました。

サプライチェーン攻撃の危険さ

開発者が信頼している公式ツールをそのまま使っただけで感染する状態であった点にあります。供給者のツールに攻撃ツールを仕込んでいたということで「サプライチェーン攻撃」だそうで。(発覚後、npm が悪性 axios バージョンを削除)

シーケンス

これをmermaid.jsにまとめたのがこちら。

sequenceDiagram participant Dev as 開発者 / サーバー participant NPM as npm レジストリ participant Mal as 悪意のあるパッケージ<br/>(plain-crypto-js) participant C2 as 攻撃者サーバー<br/>(C2サーバー) Note over Dev, NPM: 1. 汚染された axios@1.14.1 を要求 Dev->>NPM: npm install (axios要求) NPM-->>Dev: axios と依存の plain-crypto-js を配信 Note over Dev: 2. インストール直後にフックが発動 Dev->>Dev: postinstall: node setup.js を自動実行 Note over Dev, C2: 3. OSを判別し、マルウェアを落とし込む Dev->>C2: 難読化解除 + OS情報送信 + 通信開始 C2-->>Dev: 各OS用ペイロード (Mac/Win/Linux) を送信 rect rgb(240, 240, 240) Note right of Dev: Linuxの場合: /tmp/ld.py を実行<br/>Windowsの場合: 隠しPowerShellを実行 end Note over Dev: 4. 証拠隠滅 (セルフデストラクト) Dev->>Dev: setup.js を削除 Dev->>Dev: package.json をクリーンな状態に書き換え Note over Dev: node_modules 内は<br/>一見シロに見える

恐ろしさのポイント

  1. 自動実行: npm install した瞬間に、何も操作せずともウイルス(RAT)が仕込まれます。
  2. OS別の狙撃: Linux、Windows、macOSそれぞれに最適な攻撃コードが送り込まれます。
  3. 証拠隠滅: 実行後に自分自身の痕跡(setup.js)を消去し、package.json を書き換えて「何事もなかったかのように」振る舞います。

今後の対策と教訓

たまたまGrowiのアップデートタイミングとずれていた、そして、 pnpm-lock.yamlがあるおかげで、意図しない汚染版の混入を防ぐことができました。

なお、今回のケースで「黒」だった場合は、該当axiosの除去に留まりません。

VPS乗の全ての認証情報

  • SSH鍵
  • APIトークン

などが漏洩されたものとして作り直す必要があります。

以上、4月1日に公開すべき内容ではないものでした。

TS-216Gセットアップ中の初期不良対応。2/2

NASセットアップ中に起きたHDD初期不良。

これに対してどのようなサポートをし、復旧させたかのメモです。

大前提

サポートを受けられる権利の確認。

これが一番大切です。そもそも、メーカーにしても代理店にしても「故障した」って連絡はまず受け取りたくないもの。

  • 購入したという証跡(レシートや注文番号)
  • 機器のシリアルナンバー

は必須です。特に、大手代理店やメーカーは、「これは確実にうちのメーカーの正当なものである」というデータベースを持っていますから、その紐付けのためにも上記二つは持っておきましょう。

現状維持。

また、機器の外箱や梱包材なども持っておいたことが今回のスムーズな解決につながります。購入したらすぐ捨てるという断捨離精神は「機器の移行」では命取りになりやすいです。

問い合わせの内容

上記、準備ができたらメールなり問い合わせフォームなどで確認。

サポートへの報告例の前の余談

買ったばかりの製品がいきなり故障。そら、感情的になります。「高い金払わせておいて」の気持ちが先に来るのは当然です。

しかし、前項で示した「バスタブ曲線」であるように、初期不良はつきものです。実際に秋葉原などのパーツ屋で「初期不良は○日以内」ということを聞いた方もいるでしょう。

  • 初期不良は起こり得るもの。だから販売店はその方法を明示している
  • であれば、そのプロトコルに則る

が、結果的に最速の復旧となります。

サポートへ聞いてみる

これは、筆者の祖母が生前によく言っていたことですが;

「丸い卵も切り様で四角。言葉も言い様で角が立つ」
「聞き間違いは言い手の責任。言い間違いは聞き手の責任」

は、今の大炎上時代を見越したとしか思えない言葉。

  1. サポート担当が「じゃあ、助けよう」と気持ちよく手配できる
  2. 互いに誤解を生まない表現

は必要です。

筆者はこんな感じでサポートに聞きました。

ご担当者様

お世話になっております。

○月X日、購入店(または購入サイト名)にて

- 購入したもの1
- 購入したもの2
- 購入したもの3...

を、注文番号:xxxxxxxx で購入いたしましたところ、以下の不良が発生しましたので対応をお願いしたいです。

【不良が起きた製品】

HDD (シリアルナンバー)

【状況概略】
セットアップ中、ディスク読み取りエラーとなって認識されない状況となっております。

【具体的なメッセージ】

TS-216Gの管理画面で
「1つ以上の回復不能な読み取り/書き込みエラーが検出されました。ディスクを交換することを検討してください

のエラーが発生しています。(添付をご参照ください)

QNAP本体もDisk2が赤く点灯しておりました。

〔QNAP本体のエラー〕
以下を確認しております。
エラー    2026-03-27    01:02:40    ---    ---    localhost    ---    Storage & Snapshots    Disk    [Storage & Snapshots] Disk "Host: 3.5" SATA HDD 2" failed. Volume: HOLD, Storage pool: 1.

【事象発生時の操作】
以下を行いました。

1. HDD装填
2. ディスクの認識
3. RAID構築
4. ボリューム作成
5. ボリューム作成後に上記エラーを発見。

【事象発生後に実施したこと】

1. QNAP本体の再起動 → 変化無し
2. ディスクのさし直し → 変化無し

【推定される事象と依頼】

初期不良と思われます。同品交換をお願いできますでしょうか。
または、そうでないならば、対応方法をご教示ください

ここでのポイント

5W1Hの確認

「いつ、どの様な操作で、何が起きたか」は確実に伝えましょう。

あくまでも人為的な/故意ではないことを伝える

これが「サポート埒外の操作をしていた」「ブチ切れて機器を床にたたき落とした」等は話を聞いてもらえないでしょう。

何をやっていたかは正常に伝えましょう。

事象の概略→詳報の順番。

相手は何百、何千と問い合わせに対応しています。その対応の是非をトリアージしています。なので「これは早急に対処が必要だ」という書き方のためにも

  1. まず何が起きたか
  2. 何をしたらこうなったか
  3. どうして欲しいか

の3点の順番で伝えると、担当者は「これはすぐに動かねば」となります。

サポートの対応結果

驚くほど迅速でした。

  1. 障害が起きたパーツ(HDD)を交換する
  2. その手配をしたので都合のつく日時を教えてほしい

旨を伝えられたので、それを連絡。

そして、すぐに到着。もちろん、それに備えて

  • 可能な限りの原状復帰
    • HDDを静電気保護袋
    • 梱包材
    • 外箱

に入れて、その中に

  1. 購入履歴のコピー
  2. 発生した障害のメモ

を添えて、担当者が分かりやすい様にしておきます。

状況解決

新しいHDDが到着して、ディスクをQNAPのベイに入れたところ無事認識!

RAIDの構築も正常に行えたので本当に良かったです。

今回のまとめ

構築中に起きた出来事に救われた

これに尽きます。移行時のミスだったので切り戻し、手戻りは容易です。
バスタブ曲線の最初の段階で起きたので迅速な対応ができました。

信頼できる店舗で買えたこと。

そもそも、15年以上も前のデータや父のデジタル遺産を引き継いだ背景もあり「製品の信頼性」が第一でした。
そのため、「どこで買うか」というのは「どのメーカーのもので買うか」以上に重要です。

今回、QNAP/WDという信頼と実績あるメーカーを、信頼できる店舗(TSUKUMO)で買ったのは、販売実績とサポートが厚いという2点によるところが大きいです。

本当のコストパフォーマンスとは

この言葉が叫ばれて久しいですが、筆者は「コストとやらの本質を見失っていないか」という疑問があります。

というのも、「近所のスーパーより10円安いから」といって卵を隣町のスーパーで

  • 交通費
  • 時間

をかけて手に入れるという行為は、「10円の価値があるのか?」です。特に人間というやつ、かかったコストは計算できてもかかった時間は無頓着になりがちです。

例えばこれが出所が怪しい店舗で、連絡手段がよくわからない店で買っていたら障害発生後の即交換は望めなかったでしょう。

新たな10年に向けて

購入して10年超というNASの移行はなかなかのドラマがありましたが:
新たなデータストレージの引き継ぎがなんとか解決に向かって一安心でした。

次の10年も無事に持つかどうか、それこそ、大切に適切に扱っていきたいです。

TS-216Gセットアップ中の初期不良対応。1/2

TS-216Gセットアップ中、まさかの事象が起き、それを解決しようとしたときのメモです。

  1. NASの初期設定を終えて
  2. ストレージプールとボリュームを作成し
  3. いよいよデータの移行をしよう

と、一番大事な写真データを新しいNASに移行し、目処が立ったところでNAS本体を確認すると「LEDが一つ赤点灯」。

「赤?」思いながらNASの管理画面を見ると

2026-03-27 01:02:40 --- --- localhost --- Storage & Snapshots Disk [Storage & Snapshots] Disk "Host: 3.5" SATA HDD 2" failed. Volume: vol01, Storage pool: 1.

と、マウントしていない旨の連絡。更に、ディスクの状況でも

「ディスクS.M.A.R.T情報を読み取ることができません。全てのディスクが公式互換性リストに登録されていることを確認してください。
ディスクアクセス履歴:エラー
ディスクS.M.A.R.T情報:エラー

また、ストレージプールを見ても「メンバーではない」という状況です。

導入して1週間も経っていないので、対応を行います。

やったこと

NAS本体の再起動

この手のハードウェア初期構築時の基本です。

しかしNG。

ディスクのさし直し

幸い、RAID1で組んだディスクは「ホットスワップ」可能です。つまり、1本ダメでももう1本が正常であれば機器の通電中だろうとディスクの取り外しと交換が可能です。

しかしこちらもNG。

導かれる結論:初期不良

バルク品だろうとリテール品だろうと発生する「初期不良」にとっ捕まりました。いわゆる「バスタブ曲線」の最初の高い位置にあるところです。

そもそもバスタブ曲線とは?

以下、Geminiによる解説。

  • 初期故障期 (Infant Mortality Period)
    • 使い始めの時期に発生する故障です。
      • 特徴: 稼働開始直後は故障率が高く、時間の経過とともに急速に減少します。
      • 主な原因: 設計ミス、製造不良、不適切な部品の混入など。
  • 偶発故障期 (Random Failure Period)
    • 初期故障が収まり、故障率が低く安定している時期です。
      • 特徴: 故障がいつ起こるか予測しにくく、一定の低い故障率を維持します。
      • 主な原因: 予期せぬ過負荷、操作ミス、落雷などの外部要因。
  • 摩耗故障期 (Wear-out Failure Period)
    • 長期間の使用により、故障率が再び上昇し始める時期です。
      • 特徴: 部品の寿命や劣化が原因で、故障が多発します。
      • 主な原因: 摩耗、疲労、腐食、酸化などの物理的・化学的な劣化。

この、「初期故障機」に捕まりました。

嘆いていっても事態が変わるわけでもなし。やれることをやっていきます。

『未来戦隊タイムレンジャー』の

未来は変えられなくたって、自分達の明日ぐらい変えようぜ!

の精神。それに、「初期対応が可能な帰還。それも移行中」にこの不良が見つかったのはむしろ幸いと言えます。正当な権利として購入店に対応を依頼できるのですから。

というわけで、次のエントリーではこの対応のメモを記します。

TLSの矛盾で読み解くエージェント偽装の対応。

筆者はUbuntu環境のApache設定で

  • 不審なIP/NWをブロック
  • 過剰にアクセスしてくるクローラーをエージェントで判別してブロック

というセキュリティ対策を取っています。(詳細)

しかし、これは相手もその辺りの呼吸をわきまえていて、

  • まだブロックされていない/もしくは攻撃者がよく使うASN「ではない」アクセス元から
  • 正常なアクセスを装って
  • 情報を袖手したり攻撃の糸口をつかもうとする

パターンが割とあります。今回、それを検知した時のお話。

不自然に見えたログ

例によってURLとIPアドレスはダミーですが、以下のような奇妙なログを見つけました。

192.0.2.10 - - [27/Mar/2026:10:28:03 +0900] "GET /images/?1770681132 HTTP/1.1" 404 5506 "-" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.4601.1280 Mobile Safari/537.36"

一見、ただの404エラーではありますが、強烈な違和感を覚えました。

違和感1「古いAndroid端末」

Android 5.0は、2018年頃に公式セキュリティサポート終了。GooglePlay開発者サービスも2024年7月には終わっています。

違和感2「古いChrome」

同じくChrome60。これも2017年と古いバージョンです。

違和感3「TLS1.3貫通」

そんな古いAndroidが筆者のサイトにアクセスできるということはまず、あり得ません。種を明かしてしまうと、筆者のWebサイトは

#SSL対応
  SSLEngine on
    Protocols h2 http/1.1
SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2

として、TLS1.3未満のアクセスができないようになっています。 この暗号化形式をサポートするようになったのはAndroid10以降。

結論:エージェント偽装。

古いAndroidが新しいSSL暗号が施されたサイトには、そもそもアクセス不可能です。リクエストの段階でハンドシェイクが拒否されるため、404エラーどころかWebサイトそのものが見られません。

しかし、上記のアクセスログは「古いAndroidのバージョンからTLS1.3のSSLログが残る」。つまり、残る結論はほぼ「エージェントを偽装してくるクローラー」に限られます。

アプリ開発者が Conscrypt(Google製のセキュリティライブラリ)などをアプリに同梱している場合は、Android 4.4以降の古い端末でもアプリ単位でTLS 1.3通信を行える場合がありますが、そんな回りくどい方法はないでしょう

措置:新たなエージェント拒否を追加。

筆者の「厄介なエージェントを拒否する」仕組みがこちら。

  • apache側
(省略)
    # botのアクセスリストを外部ファイルから読み込む
    Include /etc/apache2/conf-enabled/bad-bot-list.conf
(省略)
        <RequireAll>
            # bad_bot変数がセットされていたらアクセスを拒否
            Require not env bad_bot
            # それ以外は許可
            Require all granted
        </RequireAll>
  • bad-bot-list.conf
SetEnvIfNoCase User-Agent "facebookexternalhit/1\.1" bad_bot dontlog
SetEnvIfNoCase User-Agent "SemrushBot/7~bl" bad_bot dontlog
SetEnvIfNoCase User-Agent "AhrefsBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "MJ12bot" bad_bot dontlog
SetEnvIfNoCase User-Agent "DotBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Baiduspider" bad_bot dontlog
SetEnvIfNoCase User-Agent "YandexBot" bad_bot dontlog
SetEnvIfNoCase User-Agent "Sogou web spider" bad_bot dontlog

等。この、SetEnvIfNoCase User-Agentの箇所に、以下を加えます。

# Android 10.0未満  を排除する
SetEnvIfNoCase User-Agent "Android [1-9]\." bad_bot dontlog

# 10年以上前の古いOS(Windows XP/Vista等)を装うボットも排除
SetEnvIfNoCase User-Agent "Windows NT [3-5]\." bad_bot dontlog

# その他、不自然な挙動を示すUA群
SetEnvIfNoCase User-Agent "^$" bad_bot dontlog

後は

sudo apache2ctl configtest
sudo systemctl reload apache2.service

で、上記、不自然なログのアクセスはピタリと止まりました。

まとめ

不正アクセスにはユーザーのみならず

  • IPアドレス
  • ドメイン

はもとより、OSやエージェントを偽装してくる輩も多いので。

だが…………
マヌケは見つかったようだな

ぐらいの勢いでアクセスログを観察していきましょうというお話でした。

TS-216Gセットアップ完了。

昨日からの作業ログです。

ストレージ基盤の確定

※先日からのステータス

  • RAID同期完了:
    • RAID 1 (ミラーリング) のビルドが正常終了。

ボリューム、ドライブ作成

  • ボリューム作成:
    • ドライブの確認
      • タイプ: シックボリューム (Thick Volume)
      • 任意の名前のエイリアス
      • 容量: 4.2 TB (プール残容量 1.62 TB をバッファとして確保)

設定後、構築・フォーマット完了、「準備完了」を確認。

ネットワーク・セキュリティ設計

  • ドメイン連携:
    • 独自ドメインでの名前解決を確認。
  • SSL証明書省略:
    • 直接インポート試行時に手持ちのWebサイト用のワイルドカード証明書をインポートしようとしましたが、ECDSA アルゴリズム非対応によるエラーを確認。
    • 運用負荷(3ヶ月更新)と汎用性を考慮し、この段階でのWeb画面のSSL設定はオミット。リバースプロキシを試すなりを行います。

システムメンテナンス

  • ファームウェア更新:
    • バージョン: 5.1.5.2645 → 5.2.9.3410 (Build 20260214)

最新状態へのアップデートおよび再起動を実施。

最終疎通確認

  • SMBアクセス:
    • Windowsエクスプローラーより \\NASのドメイン へのアクセスおよび Public/work フォルダの視認を確認。

Page 1 of 104

Powered by WordPress & Theme by Anders Norén