
今回はプレイに比して余り得点が出なかったというのが正直なところ。
『タラデッキ』を用いて31点。
- 無駄な手を一手取ってしまったのが最後まで響いた。
- 長老により魚の収入が狂った
が主なところです。
とはいえ、ミスのリカバリーもできていたのでそこは評価しておきたいです。

今回はプレイに比して余り得点が出なかったというのが正直なところ。
『タラデッキ』を用いて31点。
が主なところです。
とはいえ、ミスのリカバリーもできていたのでそこは評価しておきたいです。
元々大好きな作品『真打』のソロプレイ可能版が、さらに凄まじいブラッシュアップを遂げていました。

プレイヤーは若手の落語家となり、ライバルとネタを出し合います。季節に応じた8回の落語会の中で、
寄席を最も盛り上げた者が勝者となります。
一見、風流なテーマゲームに見えますが、その実態はガチガチの条件戦が絡み合うトリックテイキング(トリテ)。しかも、本来ソロプレイが成立しないはずのこのジャンルを、見事な仕掛けで「1人極上パズル」へと昇華させていました。
本作の最大の魅力は、「トリテの複雑なシステムが、落語のテーマと完璧にシンクロしている点」に尽きます。
カードの数値はすべてユニークで、それぞれに「滑稽噺」「人情噺」「怪談」といったスート(色)が存在します。落語の大ネタほど数値が高く、前座噺は低いため、「『牛ほめ』と『芝浜』だったら、どっちがトリ(勝利)を取るか」が直感的にわかります。初心者には見えにくい「勝ちどころ」が、テーマのおかげで自然と見えてきます。
さらに、以下の要素がトリテのシステムと見事に合致しています。
初心者が忌み嫌い、上級者が好むトリテの「複雑な条件戦」を、落語というテーマが見事に受け止めています。
普通のトリテ以上に、「負けること」に強い意味があるのも特徴的です。
トリを取った(トリックの勝者)プレイヤーほどカードの補充が後回しになるシステムのため、「ここぞという本番で勝つために、今はあえて美しく負ける」という場作りが重要になります。
これがソロプレイ(変則ドラフト)になると、さらにカウンティングによる「勝敗のコントロール」が肝となり、脳のメモリをフル活用させられます。
ボーナス要素である「称号」の獲得条件には、以下のようなものが含まれます。
これにより、「トリック(勝負)には負けているのに、全体の得点(評価)では勝っている」という不思議な状況がゲームをさらに面白くさせています。
トリックテイキングとは、本質的に「相手の手札と意思決定を読む」ゲームです。相手が何を持っているか、どのタイミングで勝ちに来るかという「他者との心理戦」が核にあるため、本来はソロプレイが最も成立しにくいジャンルです。
ところが本作は、その読み合いの代替物を「変態的(褒め言葉)」な2つの仕掛けで成立させています。
ソロモードは、ライバルに勝つこと以上に「自分の得点をどこまで伸ばせるか」という、自分自身との極限の戦いになります。「どの落語会でどの演目を出すか」「季節ボーナスをどう拾うか」が複雑に絡み合うため、「このシナリオでは全力で勝ちに行く」「ここは勝ち数をコントロールする」というジレンマが、1人プレイでも完璧に再現されています。
前作のPocketにはなかった新要素が、プレイヤーの計算を狂わせます。
これらにより、対人戦の「相手が何をしてくるか分からない不確実性」を、ランダム性+強制効果で見事に再現しています。
現に私がプレイした際、「よし、年末に満を持して『芝浜』を出したぞ!」と思った瞬間、『インタラクティブ死神』が発動。相手に『芝浜』を奪われて演じられ、理不尽に負けるというドラマが起きました。この、ほぼ必勝のパターンが引っくり返される異様さ(理不尽さ)こそが、最高に巧妙で、ゾクゾクしました。
コストカットやパッケージを極限まで抑えるためとはいえ、ルールを読むためにインターネット環境が必要なのは少々残念です(とはいえ、10分ほど読み込めばすっと頭に入っていく美しい導線ですが)。
カードが主体のコンポーネントゆえの宿命ですが、カードを保護するためにスリーブに入れると、元々のコンパクトなパッケージに収まらなくなってしまいます。(尤も、カードサイズが特殊すぎた初代『真打』の苦労に比べれば、贅沢な悩みではあるのですが……!)
元々あった「落語の要素」を見事に抽象化した粋なイラストや、ルールそのもののシンプルさはシリーズ共通の魅力として健在です。
その上で、
が見事に融合した、実に入り組んだ、そして見事な作品でした。
トリテに悲喜こもごもがあるかた、そして「制限の中で最適解を叩き出すパズル」が好きな方には刺さる作品です。
先ほどのエントリーの続きです。
「実際に筆者が施している」
Apache設定を元に「どういう動きをしているのか」を紹介します。
サイト名やIPアドレスなどはダミーにしています。
# ============================================================
# 【HTTP: 80番ポート】常時HTTPS(SSL/TLS)へのリダイレクト
# ============================================================
<VirtualHost *:80>
ServerName example.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
# ============================================================
# 【HTTPS: 443番ポート】要塞化されたメインサーバー設定
# ============================================================
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/html/public
# --------------------------------------------------------
# 1. アクセスログの間引き(ノイズカット)設定
# --------------------------------------------------------
# 自身の監視用IPなど、ログに記録させたくないIPを指定
SetEnvIf Remote_Addr "192.168.1.100" dontlog
SetEnvIf Remote_Addr "10.0.0.1" dontlog
# 検索エンジンのクローラー(健全なBot)もログから除外してノイズを減らす
SetEnvIfNoCase User-Agent "Googlebot" dontlog
SetEnvIfNoCase User-Agent "GoogleOther" dontlog
# 【外部ファイル連携】定期的・自動的に更新する悪質ボットのリストを読み込む
# ※ファイル内で「SetEnv bad_bot 1」などのフラグを立てる想定
Include /etc/apache2/conf-available/blacklist-bots.txt
# dontlogフラグが付いたアクセスは記録しない
CustomLog /var/log/apache2/example_access.log combined env=!dontlog
ErrorLog /var/log/apache2/example_error.log
# --------------------------------------------------------
# 2. メインディレクトリ制御(mod_rewrite × 環境変数)
# --------------------------------------------------------
<Directory /var/www/html/public>
Options -MultiViews
AllowOverride All
# 大量の拒否アクセスによるエラーログ肥大化を抑制(重大エラーのみ記録)
LogLevel authz_core:crit
<IfModule mod_rewrite.c>
RewriteEngine On
# 【攻撃検知】特定の動的ページに対する「大量のタグ連結」などのボット挙動を迎撃
# 例:特定のURLパスにアクセスがあり、かつクエリにURLエンコードされたカンマ等が大量に含まれる場合
SetEnvIf Request_URI "^/search/tags" is_target_page
SetEnvIf Query_String "tag=.*(%2c|,|%e3%80%81).*(%2c|,|%e3%80%81).*(%2c|,|%e3%80%81)" bad_tag_stacking
# 条件に合致したら、ログを残さず「404 Not Found(存在しない)」を返して虚無へ葬る
RewriteCond %{ENV:is_target_page} 1
RewriteCond %{ENV:bad_tag_stacking} 1
RewriteRule ^ - [E=dontlog:1,R=404,L]
# 【外部ファイル連携】スパムIPアドレスのブラックリストを読み込んで404を返す
Include /etc/apache2/conf-available/spam-ips.txt
</IfModule>
# 【アクセス拒否】上記の設定や外部リストで「bad_bot」と判定された通信を遮断
<RequireAll>
Require not env bad_bot
Require all granted
</RequireAll>
</Directory>
# 403 Forbidden(拒否)を返すと攻撃者に「防御されている」とバレるため、
# 403の際も「404 Not Found(最初から何も無い)」として処理する
ErrorDocument 403 /404.html
# --------------------------------------------------------
# 3. セキュリティヘッダーの強化(mod_headers)
# --------------------------------------------------------
Header always set Strict-Transport-Security "max-age=63072000"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
# --------------------------------------------------------
# 4. Nepenthes(ウツボカズラ)トラップ設定(mod_alias)
# --------------------------------------------------------
# 攻撃者が盲目的にスキャンしてくる「脆弱性のあるパス」を、ダミーの静的ファイルへ吸い込ませる
<IfModule mod_alias.c>
# WordPressを使っていない(または構成が違う)のに狙われるパス
Alias /wp-login.php /var/www/nepenthes/dummy_login.html
Alias /wp-admin /var/www/nepenthes/dummy_login.html
Alias /wordpress /var/www/nepenthes/dummy_login.html
# 漏洩すると致命的な .git ディレクトリへのスキャン対策
Alias /.git /var/www/nepenthes/dummy_git.html
# robots.txtで「巡回禁止」にしているにもかかわらず、
# 行儀悪くスクラップ(収集)しにくるAI自動巡回エージェント用のトラップ
Alias /assets-archive /var/www/nepenthes/dummy_login.html
# トラップ用ディレクトリへのアクセスを許可
<Directory /var/www/nepenthes>
Require all granted
</Directory>
</IfModule>
# --------------------------------------------------------
# 5. SSL/TLS暗号化プロトコル設定
# --------------------------------------------------------
SSLEngine on
Protocols h2 http/1.1
# 安全性の低い古いプロトコルを徹底排除(TLS 1.2 / 1.3 のみ許可)
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
# --------------------------------------------------------
# 6. WAF(ModSecurity)のチューニング
# --------------------------------------------------------
<IfModule security2_module>
SecRuleEngine On
# ファイルアップロードの容量制限を引き上げ(必要に応じて調整)
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000
SecRequestBodyNoFilesLimit 524288000
# --- 偽陽性(誤検知)の除外ルール ---
# ※システム(RedmineやWordPressなど)の特性に応じて、正常な通信が遮断されないよう調整
SecRuleRemoveById 920420 # 特定JavaScriptの誤検知対策
SecRuleRemoveById 200004 # マルチパート解析エラーの除外
SecRuleRemoveById 920300 # HTTPプロトコル違反の除外
SecRuleRemoveById 920260
SecRuleRemoveById 920270
SecRuleRemoveById 920240
# --- 記憶抹消刑(Damnatio Memoriae)システム ---
# あらかじめリスト化した凶悪なIP(negativelist.txt)からのアクセスは、
# 404エラーを返しつつ、Apacheのログ(auditlog等含む)に一切記録させず存在を抹消する
SecRule REMOTE_ADDR "@pmFromFile negativelist.txt" "phase:1,id:2,status:404,msg:'Damnatio Memoriae',nolog,noauditlog"
</IfModule>
</VirtualHost>
では、各設定の意図は後回しにして、「どういう動きなのか」を見てみましょう。
http(80番)で来たアクセスを強制的にhttps(443)に転送します。
悪意を持たないアクセスには正常に通信します。
スクレイピングや事前に設定していた悪質なボットにどう立ち向かうのかがこちらです。
と、このように、
「“アクセス”は通す
“攻撃”は阻止する
ミドルウェアで“両方”やるというのは
そう難しいことじゃあないな」
と言えるのが「個人VPSでApacheを使う理由」と言えます。
次は、それらを可能にする仕組みについて解説します。
Webサーバの中核ミドルウェアは
の二つですが、近年のトレンドは間違いなくNginx。
Nginxはなぜここまでもてはやされるのかを軽くひもといて見ます。
Nginx(エンジンエックス)が現在、Webサーバーのシェアでトップ争いをするほどもてはやされ、多くの開発者や企業に支持されているのには明確な理由があります。
主な意見やメリットをWeb上の情報からまとめると、理由は大きく分けて以下の4点に集約されます。
かつて主流だったWebサーバー(Apacheなど)は、アクセス(リクエスト)ごとに「プロセス」や「スレッド」を立ち上げて処理する方式でした。そのため、同時に大量のアクセスが来るとサーバーのメモリを使い果たしてしまい、サーバーがダウンしたり極端に遅くなったりする「C10K問題(クライアント1万台問題)」が発生していました。
これに対し、Nginxは「イベント駆動型(非同期シングルスレッド)」というアーキテクチャを採用しています。
HTMLファイル、画像、CSS、JavaScriptなどの「静的コンテンツ」をユーザーに返すスピードが圧倒的です。
ベンチマークによっては、従来のWebサーバーと比べて数倍〜十数倍以上のパフォーマンスを発揮すると言われており、リソースの消費を抑えながらWebサイトの表示速度を大幅に向上させることができます。
Nginxは単なるWebサーバーとしてだけでなく、
としての機能が非常に優れています。
現代のWebシステムでは、以下のような「役割分担」をする構成(構成例を以下に示します)がトレンドとなっています。
動的な処理(WordPressや各種Webアプリなどの重い処理)は後ろのアプリケーションサーバーに任せ、Nginxは「表に立って大量のアクセスを交通整理する」という役割を担うことで、システム全体の安定性と速度を極限まで高めることができます。
長年の歴史を持つApacheなどは、多機能である反面、設定ファイルが複雑化しがちでした。
一方、Nginxの設定は記述ルールがスマートで、直感的で分かりやすい構成になっています。軽量でコンテナ(Dockerなど)との相性も抜群に良いため、現代のクラウドネイティブな開発環境において非常に好まれています。
と、ここまで書いたらメリットしかないように感じられるNginxですが、
方にはApacheの方が優れているケースが多々あります。
「単一VPS(リソースが限られている)での個人利用」という条件に絞ると、実はApacheを選ぶ明確なメリット(むしろApacheの方が楽で優れている点)があります。
なぜ筆者のように単一VPSの個人利用ではApacheが有利になるのか、主な理由を3つに分けて解説します。
.htaccess (include)による手軽さと柔軟性個人利用、特に1台のVPSでブログやポートフォリオなど複数のサイトを試行錯誤しながら運用する場合、Apacheの .htaccess(分散設定ファイル)や include(内部ファイル) は圧倒的に便利です。
.htaccess や include(内部ファイル)ファイルを置くだけで即座に反映できます。nginx.conf)に記述する必要があり、変更のたびにサーバーの再起動(リロード)が必要です。記述を間違えるとサーバー全体が落ちるリスクがあります。個人VPSでよく使われるWordPress(PHP)を動かす場合、Apacheの方が構築が圧倒的にシンプルです。
mod_php による一体型処理:
歴史が長いApacheは、ネット上にあるトラブルシューティングや逆引きの設定情報が膨大です。
.htaccess を自動書き換えする」 仕様になっています。Apacheであればプラグインを入れるだけで勝手に設定が完了します。.htaccess の記述(Apache用)を、自分でNginx用の設定構文に翻訳して nginx.conf に手動で追記しなければならないケースが多々あります。「でも、Nginxの方が軽いし速いのでは?」と思われるかもしれませんが、「個人利用のアクセス規模」であれば、体感できるほどの差はまず出ません。
が余りにも強いから、に尽きます。
mod_rewrite という「最強のアーミーナイフ」mod_rewrite は、URLの書き換えやリダイレクトを自由自在に行える、Apache史上最も強力なモジュールのひとつです。個人VPSでWebサイトを運営する際、これほど頼りになるツールはありません。
.htaccess(inlude) との相乗効果:
.htaccess に書けるため、Webサーバー全体の設定を汚すことなく、Webアプリケーション側(WordPressなど)が自身をコントロールするためにフル活用できます。rewrite 指令はありますが、Apacheの mod_rewrite ほど複雑な条件分岐(複数条件の組み合わせや、ファイル・ディレクトリの存在チェックを挟んだ高度なルーティング)をスマートに書くのが難しく、設定が肥大化・複雑化しやすいという弱点があります。mod_security(WAF)との「歴史的・機能的な相性の良さ」個人VPSは常に世界中からのサイバー攻撃(ブルートフォースアタック、SQLインジェクション、クロスサイトスクリプティングなど)に晒されるため、オープンソースのWAF(Webアプリケーションファイアウォール)である mod_security の存在は非常に大きいです。
mod_security はApacheのモジュールとして開発された歴史があるため、Apacheとの親和性は抜群です。インストールも容易で、挙動も非常に安定しています。mod_security(最新はv3)を動かすには、多くの場合ソースコードからモジュールを自分でコンパイル(ビルド)して組み込む必要があり、バージョンアップのたびにメンテナンスの手間が発生するなど、個人運用のハードルがかなり高くなります。Nginxが「大量の荷物を最速で右から左へ捌くプロフェッショナル」だとすれば、
Apacheは「どんな要求にもその場で柔軟に応え、自分で自分の身を守る武装も完璧な万能戦士」です。
個人VPSという「限られた1台の環境」だからこそ、
mod_security でガッチリ身を守り、mod_rewrite で複雑なURL設計をスマートにこなし、.htaccess で手軽に設定を変えるというApacheの特性が120%活きます。「もてはやされているから」という理由だけでNginxを選ぶと、このあたりの「痒いところに手が届く便利さ」を全て手動の泥臭い設定(あるいはコンパイル作業)で補うことになり、途中で挫折してしまうケースも少なくありません。
では次回の記事から、筆者が実際にVPSで運用している「mod_rewrite による超柔軟なURL制御」と「mod_security による鉄壁の防御設定」の具体例を、コードを交えてご紹介します
自分のサーバでその場で障害状況を見るための道具を洗練させています。
#!/bin/bash
# --- カラー定義 ---
GREEN='\033[0;32m' # 緑:正常・低負荷
RED='\033[0;31m' # 赤:高負荷・警告
BLUE='\033[0;34m' # 青:ヘッダ・情報
YELLOW='\033[1;33m' # 黄:中負荷・注意
NC='\033[0m'
BOLD='\033[1m'
# --- デフォルト設定 ---
TOP_N=10
MODE="all"
# --- ヘルプ表示 ---
usage() {
echo -e "${BLUE}Usage: $0 [-c] [-m] [-n NUM] [-i]${NC}"
echo " -c : CPU使用率順で表示"
echo " -m : メモリ使用率順で表示"
echo " -n : 表示行数 (Default: ${TOP_N})"
echo " -i : 対話式モード (Interactive)"
exit 0
}
# --- 対話モード (Interactive Mode) ---
interactive_mode() {
echo -e "${BLUE}${BOLD}=== 対話設定モード ===${NC}"
# モード選択
echo -e "表示モードを選択してください:"
echo " 1) 全て表示 (デフォルト: Enter)"
echo " 2) CPUのみ"
echo " 3) メモリのみ"
read -r -p "選択 [1-3]: " mode_choice
case "$mode_choice" in
2) MODE="cpu" ;;
3) MODE="mem" ;;
*) MODE="all" ;;
esac
# 行数指定
read -r -p "表示行数を入力してください (デフォルト: 10): " input_n
if [[ "$input_n" =~ ^[0-9]+$ ]]; then
TOP_N="$input_n"
else
TOP_N=10
fi
echo ""
}
# --- CPU情報の表示 ---
show_cpu_info() {
echo -e "${BLUE}${BOLD}--- 💻 CPU Information ---${NC}"
if [ -f /proc/cpuinfo ]; then
# メーカー名 / モデル名
local model_name
model_name=$(grep -m 1 "model name" /proc/cpuinfo | cut -d: -f2 | sed 's/^[ \t]*//')
# 物理コア数 (無い場合はソケット数等からフォールバック)
local cores
cores=$(grep -c "^processor" /proc/cpuinfo)
# 周波数 (MHz から GHz に変換して見やすく)
local cpu_mhz
cpu_mhz=$(grep -m 1 "cpu MHz" /proc/cpuinfo | cut -d: -f2 | sed 's/^[ \t]*//')
echo -e " ${YELLOW}Model:${NC} ${model_name:-Unknown}"
if [ -n "$cpu_mhz" ]; then
# 簡易的にGHz変換(小数点以下2桁)
local cpu_ghz
cpu_ghz=$(awk -v mhz="$cpu_mhz" 'BEGIN {printf "%.2f", mhz/1000}')
echo -e " ${YELLOW}Speed:${NC} ${cpu_ghz} GHz (${cpu_mhz} MHz)"
fi
echo -e " ${YELLOW}Cores:${NC} ${cores} threads"
else
echo -e "${RED}/proc/cpuinfo が見つかりません。${NC}"
fi
echo ""
}
# --- Memory & zRAM ---
show_memory_status() {
echo -e "${BLUE}${BOLD}--- 🧠 Memory & zRAM Status ---${NC}"
# free -h の表示
echo -e "${YELLOW}[Physical Memory]${NC}"
free -h | awk 'NR==1{print " " $0} NR>1{print $0}'
echo ""
# zramctl の表示
if command -v zramctl > /dev/null; then
echo -e "${YELLOW}[zRAM Compression Status]${NC}"
zramctl --output-all
else
echo -e "${RED}zramctlはこの環境にはありません。${NC}"
fi
echo ""
}
# --- ディスク使用量 (Storage Status) ---
show_disk_status() {
echo -e "${BLUE}${BOLD}--- 💾 Disk Usage Status ---${NC}"
# 主要なファイルシステム(tmpfs等を除く実ディスク)を抽出して表示
df -h -x tmpfs -x devtmpfs -x squashfs 2>/dev/null || df -h
echo ""
}
# --- プロセス監視 (Process Tracking) ---
show_top() {
local sort_key="$1"
local title="$2"
echo -e "${BLUE}${BOLD}--- ${title} (Top ${TOP_N}) ---${NC}"
# Header (見出し列の幅を調整してズレを防止)
printf "${BLUE}%-6s %-6s %-8s %-12s %-20s %s${NC}\n" "%CPU" "%MEM" "PID" "USER" "UNIT" "COMMAND"
echo "------------------------------------------------------------------------------------------"
# ps コマンド。head/tailのロジックを整理し、空文字による awk の挙動エラーを防止
ps -e -o pcpu,pmem,pid,user,unit:20,args --sort="${sort_key}" | \
tail -n +2 | head -n "$TOP_N" | \
awk -v red="$RED" -v green="$GREEN" -v yellow="$YELLOW" -v nc="$NC" '
{
cpu=$1; mem=$2; pid=$3; user=$4; unit=$5;
# カラー判定
color=nc;
if (cpu > 50.0 || mem > 50.0) color=red;
else if (cpu > 10.0 || mem > 10.0) color=yellow;
else color=green;
# 6列目以降のコマンド引数を結合
cmd=""; for(i=6;i<=NF;i++) cmd=cmd" "$i;
# 先頭の余分なスペースを削除
sub(/^ /, "", cmd);
printf "%s%-6s %-6s %-8s %-12s %-20s %-50s%s\n", color, cpu, mem, pid, user, unit, substr(cmd,1,50), nc
}'
}
# --- 引数解析 ---
# オプション指定がない場合はデフォルトで対話モードを起動
if [ $# -eq 0 ]; then
interactive_mode
else
while getopts "cmn:ih" opt; do
case $opt in
c) MODE="cpu" ;;
m) MODE="mem" ;;
n) TOP_N="$OPTARG" ;;
i) interactive_mode ;;
h|*) usage ;;
esac
done
fi
# --- 実行 ---
clear
echo -e "${GREEN}監視を開始します。${NC}\n"
# システム情報の表示 (常に表示)
show_cpu_info
show_memory_status
show_disk_status
# プロセス情報の表示
case $MODE in
cpu) show_top "-pcpu" "CPU Consumers" ;;
mem) show_top "-pmem" "Memory Consumers" ;;
all)
show_top "-pcpu" "CPU Consumers"
echo ""
show_top "-pmem" "Memory Consumers"
;;
esac
echo -e "\n${GREEN}プロセスが表示されました${NC}"
-c や -m など)が指定された場合は、その設定に従います。usage(ヘルプ表示)使い方を間違えた時や、-h オプションを付けた時に、コマンドのオプション一覧を表示してスクリプトを終了します。
interactive_mode(対話設定モード)引数なしで実行された時に呼ばれます。read コマンドを使ってユーザーに入力を促し、表示したいモード(全て/CPUのみ/メモリのみ)や、ランキングを何件表示するか(デフォルト10件)を動的に決定します。
show_cpu_info(CPU情報の表示)Linuxのシステムファイル /proc/cpuinfo を読み込んで解析します。
awk を使って計算し GHz 単位に変換して見やすく表示します。show_memory_status(メモリとzRAMの状況)free -h コマンドで、人間が見やすい単位(GBやMB)で物理メモリの空き状況を表示します。zramctl コマンドがある環境(メモリ圧縮技術 zRAM が有効な環境)では、その圧縮ステータスも同時に表示します。show_disk_status(ディスク使用量)df -h コマンドでストレージの残量を表示します。-x tmpfs などを指定することで、メモリ上の仮想ファイルシステムを除外した「実際の物理ディスク(SSDやHDD)だけ」を狙って表示する工夫がされています。show_top(プロセス監視のコア処理)ps コマンドで現在動いているプロセスの一覧を、指定されたリソース(CPUまたはメモリ)の消費量が多い順に並び替えて取得します。tail と head を使って、指定された件数(デフォルト10件)だけを切り出します。awk を使ってデータを1行ずつ処理し、CPUまたはメモリの使用率が50%を超えていれば「赤」、10%を超えていれば「黄」、それ以下なら「緑」に文字色をリアルタイムに変化させて出力します。実行する際のオプションによって、動きを切り替えることができます。
| オプション | 実行例 | 動き |
|---|---|---|
| (なし) | ./script.sh | 対話モード。画面の指示に従って入力する。 |
-c | ./script.sh -c | CPU使用率の高いプロセスをトップ10で表示する。 |
-m | ./script.sh -m | メモリ使用率の高いプロセスをトップ10で表示する。 |
-n [数値] | ./script.sh -c -n 5 | CPUの高いプロセスを上位5件だけ表示する。 |
-h | ./script.sh -h | ヘルプ(使い方の説明)を表示する。 |
LinuxサーバーやPCの健康状態を、コマンド一つでパッと色鮮やかに確認できる非常に実用的かつ便利なものに仕上げた自負があります。
今回の東武ワールドスクウェアでの日帰りはいつもとちょっと異なったものをいただきました。

地元企業、岩下食品とのタイアップメニュー。あの新生姜をこんな量を入れた原価はどうなっているんだと考えたくなるラーメン。
ショウガの刺激、酸味が豚骨ベースのスープによく似合い、更に、麺もショウガを練り込んでいるという徹底ぶり。
合間に載せたキャベツがいいアクセントとなって、豚骨ベースなのに後味が軽いという不思議なラーメン。
付け合わせの餃子にしても、刻み生姜がたっぷり添えられて、餃子の油を打ち消してくれるパーツとして機能しています。

また、この時いただいたコロッセオ近くのカフェのアイスも甘みとコクがよく合いますし、何より目の前にコロッセオやパルテノン神殿、ヴァチカンまで見られるという異国情緒の盛り合わせでした。
好んで筆者が訪れる東武ワールドスクウェア。

この、適度な広さやスケール感は非常に好きな施設。1/25のサイズ感となっている建物群は、それぞれフィギュアがストーリーを紡いでいるのですが……

ローマ、コロッセオのフィギュア群は人だかりができています。右側にカメラクルー、コロッセオ近くに二人乗りのベスパがあることから映画『ローマの休日』の撮影を再現したもの。
こういう見立て、物語も楽しめるなと思ったら、何かありました。

人混みの中に紛れたTシャツ。細かい文字でのこれは
『黄金の風』。しかも、しっかりここで戦っているブチャラティ。しれっとおかっぱ頭になっているというのも見逃せません。
こう、作り手はここまで細かいところを形作っているのかというクラフトマンシップを見ることができました。
BBC NewsのRSSフィードを取得するスクリプトを改修しました。
-m フラグの処理:
-m が指定された場合、インタラクティブモード(対話式)の関数を呼び出します。#!/bin/bash
# デフォルト値の設定
default_section="world"
default_count=3
# メインセクションのリスト
main_sections=("world" "uk" "business" "politics" "health" "education" "science_and_environment" "technology" "entertainment_and_arts")
# グローバルセクションのリスト
global_sections=("africa" "asia" "europe" "latin_america" "middle_east" "us_and_canada")
# 全セクションのリストを統合
all_sections=("${main_sections[@]}" "${global_sections[@]}")
# --- [新規] 対話式メニュー関数 ---
interactive_menu() {
echo "=== BBC News RSS セクション選択 ==="
# セクション一覧を番号付きで表示
for i in "${!all_sections[@]}"; do
printf "%2d) %s\n" "$((i+1))" "${all_sections[$i]}"
done
# セクションの入力受付
while true; do
read -p "セクションの番号を選択してください (1-${#all_sections[@]}): " sec_num
if [[ "$sec_num" =~ ^[0-9]+$ ]] && [ "$sec_num" -ge 1 ] && [ "$sec_num" -le "${#all_sections[@]}" ]; then
section="${all_sections[$((sec_num-1))]}"
break
else
echo "無効な入力です。正しい番号を入力してください。"
fi
done
# 件数の入力受付
read -p "表示する件数を入力してください (デフォルト: ${default_count}): " input_count
if [[ "$input_count" =~ ^[0-9]+$ ]] && [ "$input_count" -gt 0 ]; then
count=$input_count
else
count=$default_count
fi
echo "--------------------------------------------------"
}
# --- 引数の処理 ---
if [[ "$1" == "-m" ]]; then
# 対話モードの起動
interactive_menu
elif [[ "$1" =~ ^[0-9]+$ ]]; then
section=$default_section
count=$1
else
section=${1:-$default_section} # 引数1が指定されていない場合はデフォルト値を使用
count=${2:-$default_count} # 引数2が指定されていない場合はデフォルト値を使用
fi
# 引数の短縮形を対応する正式名に変換 (通常モード用)
case "$section" in
"usa" | "n-usa") section="us_and_canada" ;;
"me") section="middle_east" ;;
"latam" | "la") section="latin_america" ;;
"eu") section="europe" ;;
"science") section="science_and_environment" ;;
"entertainment") section="entertainment_and_arts" ;;
*) section=$section ;; # その他はそのまま
esac
# セクションの検証
if [[ ! " ${all_sections[@]} " =~ " ${section} " ]]; then
echo "Error: Invalid section '${section}'. Valid sections are: ${all_sections[*]}"
exit 1
fi
# URLの構築
if [[ " ${main_sections[@]} " =~ " ${section} " ]]; then
url="https://feeds.bbci.co.uk/news/${section}/rss.xml"
else
url="https://feeds.bbci.co.uk/news/world/${section}/rss.xml"
fi
# 最初に一度だけRSSフィードをダウンロードし、変数に格納する
xml_content=$(curl -s "$url")
# コンテンツが取得できなかった場合はエラー終了
if [ -z "$xml_content" ]; then
echo "Error: No headlines found for section '${section}'. Please check the section name or try again later."
exit 1
fi
# フィードの最終更新日時を取得し、フォーマットする
feed_date_raw=$(echo "$xml_content" | xmllint --xpath "string(//channel/lastBuildDate)" - 2>/dev/null)
if [ -n "$feed_date_raw" ]; then
# JSTに変換して表示フォーマットを整える
feed_date_formatted=$(date -d "$feed_date_raw" '+%Y/%m/%d %H:%M:%S %Z')
fi
# 見出しを取得
headlines=$(echo "$xml_content" | xmllint --xpath "//item/title/text()" - 2>/dev/null | sed -e 's/<!\[CDATA\[//g' -e 's/\]\]>//g' | head -n "$count")
# 見出しの表示
echo "BBC News - ${section} section (${count} headlines)"
# 取得した日付を表示
if [ -n "$feed_date_formatted" ]; then
echo "As of: ${feed_date_formatted}"
fi
echo "--------------------------------------------------" #区切り線
echo "$headlines"
引数をそのまま渡せば、セクションごとに件数を表示してくれます。
./bbc_headline.sh business 5
-m を付けて実行します。
./bbc_headline.sh -m
実行イメージ:
=== BBC News RSS セクション選択 ==
1) world
2) uk
...
15) us_and_canada
セクションの番号を選択してください (1-15): 3
表示する件数を入力してください (デフォルト: 3): 5
--------------------------------------------------
BBC News - business section (5 headlines)
...
私が便利だと思ったから乗せています。実際、/etc/update-motdに仕込むことで、「今はこういう出来事が起こっている」をリアルタイムで知ることができるからです。
サイトの命綱であるSSL証明書を簡単にチェックするRubyスクリプトを更に改良しました。
このRubyスクリプトの動きを解説してください
#!/usr/bin/env ruby
require 'openssl'
require 'socket'
require 'date'
require 'uri'
require 'timeout'
require 'net/http'
# ANSIカラーコード
COLORS = {
red: "\e[31m",
yellow: "\e[33m",
green: "\e[32m",
reset: "\e[0m"
}.freeze
# 1. 引数のURL/ドメインを適切にパースするメソッド
def parse_to_uri(input)
clean_input = input.strip
url = clean_input.match?(%r{\Ahttps?://}) ? clean_input : "https://#{clean_input}"
URI.parse(url)
rescue URI::InvalidURIError
nil
end
# 2. リダイレクトを追跡して最終的なURIを返すメソッド
def fetch_effective_uri(uri, limit = 5)
return nil if limit == 0
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.open_timeout = 5
http.read_timeout = 5
http.head(uri.path.empty? ? '/' : uri.path)
end
case response
when Net::HTTPRedirection
redirect_uri = URI.join(uri, response['location'])
fetch_effective_uri(redirect_uri, limit - 1)
else
uri
end
rescue => e
nil
end
# 3. 証明書の有効期限を取得するメソッド(エラー箇所を修正)
def fetch_certificate_expiry(uri)
Timeout.timeout(5) do
# ポートが明示されていない場合は、スキーマがhttpsなら443、それ以外なら80にする
port = uri.port || (uri.scheme == 'https' ? 443 : 80)
# TCPSocket.open はブロックを渡すと自動クローズしてくれます
TCPSocket.open(uri.host, port) do |tcp_socket|
ctx = OpenSSL::SSL::SSLContext.new
# .open ではなく .new を使用し、ブロックの代わりに ensure でクローズする形に修正
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ctx)
ssl_socket.hostname = uri.host
begin
ssl_socket.connect
cert = ssl_socket.peer_cert
expiration_date = cert.not_after.to_date
days_remaining = (expiration_date - Date.today).to_i
[expiration_date, days_remaining]
ensure
ssl_socket.close rescue nil
end
end
end
rescue Timeout::Error
[nil, "サーバーへの接続がタイムアウトしました。"]
rescue => e
[nil, e.message]
end
# 4. 結果を表示するメソッド
def print_result(uri, expiration_date, days_remaining)
if expiration_date
formatted_date = expiration_date.strftime("%Y/%m/%d")
color = case days_remaining
when ...14 then COLORS[:red]
when ...30 then COLORS[:yellow]
else COLORS[:green]
end
puts "サイト #{uri} の有効期限は #{formatted_date} です。#{color}残り #{days_remaining} 日です。#{COLORS[:reset]}"
else
puts "#{COLORS[:red]}サイト #{uri} の証明書取得に失敗しました: #{days_remaining}#{COLORS[:reset]}"
end
end
# メイン処理
def main
inputs = ARGV.empty? ? [print("チェックしたいサイト(ドメイン/URL)を入力してください: "), gets].last.to_s : ARGV
inputs.each do |input|
next if input.strip.empty?
uri = parse_to_uri(input)
if uri.nil?
puts "#{COLORS[:red]}無効な入力です: #{input}#{COLORS[:reset]}"
next
end
puts "Checking: #{uri} ..."
final_uri = fetch_effective_uri(uri)
if final_uri.nil?
puts "#{COLORS[:red]}サイト #{uri} にアクセスできませんでした。#{COLORS[:reset]}"
next
end
unless final_uri.scheme == 'https'
puts "#{COLORS[:yellow]}最終遷移先がHTTPSではないため、スキップします: #{final_uri}#{COLORS[:reset]}"
next
end
expiration_date, days_remaining = fetch_certificate_expiry(final_uri)
print_result(final_uri, expiration_date, days_remaining)
end
end
main if __FILE__ == $PROGRAM_NAME
このスクリプトを実行するには、Rubyがインストールされた環境(MacのターミナルやLinux、Windowsのコマンドプロンプトなど)が必要です。
上記のコードをコピーし、任意の場所にファイルとして保存します。
check_cert.rb使い方は「引数でまとめて指定する」か「実行後に入力する」の2パターンあります。
調べたいサイトをスペース区切りで並べて一気に実行できます。URLでもドメインだけでもOKです。
ruby check_cert.rb google.com github.com https://rubygems.org
引数を何も渡さずに実行すると、画面上で入力を求められます。
ruby check_cert.rb
実行すると チェックしたいサイト(ドメイン/URL)を入力してください: と表示されるので、そこに yahoo.co.jp などを入力してEnterを押します。
スクリプトを実行すると、内部で通信が行われ、結果がターミナルに以下のように表示されます。残り日数に応じて自動で文字に色がつくため、一目で状況がわかります。
Checking: https://google.com ...
サイト https://google.com の有効期限は 2026/07/15 です。残り 50 日です。(←緑色で表示)
Checking: https://example.com ...
サイト https://example.com の有効期限は 2026/06/05 です。残り 10 日です。(←赤色で表示)
Checking: http://http-only-site.com ...
最終遷移先がHTTPSではないため、スキップします: http://http-only-site.com (←黄色で表示)
Checking: https://invalid-domain-xyz.com ...
サイト https://invalid-domain-xyz.com の証明書取得に失敗しました: Failed to open TCP connection to invalid-domain-xyz.com:443(←赤色で表示)
http://github.com と入力しても、自動的に https://github.com へ転送(リダイレクト)されたことを検知し、最終的なHTTPSのページに対して証明書をチェックします。筆者はLinuxターミナルの/etc/update-motd.dに仕込むことで自サイトの証明書更新のタイミングを計っています。何せ、Let's Encryptはわずか90日。更に短くなるというのもほぼ確定しましていますから。
そして、筆者が、ここまで執拗にこれをチェックするのは「私怨」が本質。
自分をかなり追い詰めていき、体と心を大きく崩してしまった前の職場。その元職場が
という、IT系会社にあるまじき状態を鼻で笑うためというのもこのスクリプト作成のきっかけ。
という更にお察し状態なのはまた別のお話。
現Xで見かけてしまったツール、Paprika。
Paprikaは、分散ワーカー上のChrome(実ブラウザ)をPlaywright経由で操作し、LLM/Vision(AI)を使ってページ内の画像・動画・構造化データを根こそぎ剥ぎ取る、極めて執拗な自動化プラットフォームです。
scroll=True で遅延ロードを発火させ、画像や動画ストリームを「丸ごと一括ダウンロード」するため、サーバーの帯域やCPU(コスト)に莫大な負荷をかける点。仕様書には「利用規約の遵守」や「正当な目的での利用」と美しく免責事項が書かれていますが、提供されている機能はあきらかに「大量かつ高速なコンテンツのブッコ抜き」を目的としています。この「建前と本音の圧倒的なギャップ」が「趣味が悪い」と断じた理由です。
一般的なクローラー(Googlebotなど)は、robots.txt のルールを守り、正体を名乗って巡回します。
しかしPaprikaは、JavaScriptの完全実行、遅延ロード(スクロール動作)への追従、Cookieの永続化による会員限定ページの突破を平然と行います。
サイト側が「毎日ボタンの配置(CSS)を変える」といったボット対策をしても、AIエージェントがそれを学習して乗り越えてきます。さらに、分散IPで「一見、たくさんの一般ユーザーが同時にアクセスしてきた」ように見せかけるため、従来のWAFやIP制限が非常に効きにくいのが最大の問題です。
AIエージェントが画面スクロールや walk(サイト内巡回)を繰り返すことで、一般ユーザーの快適な閲覧環境を圧迫する、一種のDoS状態のツールです。
以下、筆者環境です。
の2つがあれば基本的には対処可能です。ApacheのMod_rewriteは、アーミーナイフのような問題です。
sudo a2enmod rewrite
sudo systemctl reload apache2.service
彼らがもしデフォルトの名称(PaprikaやPlaywright)をUser-Agentに残して突っ込んできた場合、もっとも軽量な処理で済みます。
apacheの.confファイルに以下を突っ込んでおきます。
# ─── 層1: 既知のAI自動化ツール・ライブラリのUAを拒否 ───
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (paprika|Playwright|Stagehand|Browser-Use|Browserable) [NC]
RewriteRule ^ - [F,L]
</IfModule>
「言いがかり」を完全に無力化するため、サイトのフッター等に「AIエージェントや実ブラウザ偽装による一括ダウンロードをDoS行為とみなし、検知した場合は即座にアクセス制限を適用する」旨を記載しておきましょう。
そもそも、上記のDoSツールを使ってくるものが「正常な閲覧者」である理由はありません。
robots.txt に罠を仕掛ける:まともなクローラーは rogotx.txt に書かれたDisallow を守ります。しかし、こんな輩がこれを律儀に守るということはまずありません。
そこで、それを逆手に取り、品性のないAIエージェントだけを炙り出すための罠のパスを設定します。
robots.txtに以下のような罠を設けておきます。
User-agent: *
Disallow: /assets-archive/
悪意あるクローラーは「robots.txtにわざわざ書くということは、ここに大事な情報があるに違いない」と判断します。
踏んだクローラーに対し、403(拒否)ではなく「404(存在しない)」を返すことで、「そんなものはありません」と先んじておきます。
# robots.txtを無視して歩き回る(walk)AIエージェントへの罠
<IfModule mod_rewrite.c>
RewriteEngine On
# robots.txtで禁止した領域に足を踏み入れた者は、一律で404(Not Found)
RewriteRule ^assets-archive/?$ - [R=404,L]
</IfModule>
「正当な目的」を謳えば他人のリソースを奪えばいいというツール。
崇高な目的とやらにDoSツールをばらまくというその厚顔無恥ぶりは『メリー・ポピンズ』の
Not at all attractive to my way of thinking
この言葉を借りるまでもなく悪趣味の一言。
Web管理者側もただ怯えるのではなく、相手の仕様の「執着」を逆手に取り、エレガントに虚無(404)へ引きずり込む防衛術がお役に立てれば幸いです。
Powered by WordPress & Theme by Anders Norén