既存CGIを一切触らずに、前段にアクセス制御やアクセスロガーをつけたいとかの用途でラッパーCGIを使うと上手くいくので、その方法を書く。
なお前段が動くことしか試していないが、備考に後段で処理をさせる方法についても軽く触れている。
動作機序
CGIはコマンドライン引数、環境変数、標準入力を受け取り、何かを処理した結果を標準出力するプログラムである。
つまりラッパーCGIはコマンドライン引数、環境変数、標準入力を受け取り、それをラッピングするCGIにそのまま受け渡し、このCGIの標準出力をリダイレクトできればよい。
やり方
以下のようなコードを書き、exec()前に前段の処理を書けばよい。
#!/usr/bin/perl
use strict;
use warnings;
#
# ここに実行前に挟みたい処理
#
my $original_cgi = './hoge.cgi';
exec($original_cgi) or die "Cannot exec $original_cgi: $!";
今回実際に作ったサンプル
adiaryにはアクセス制限をする機能がなく、本体を弄るのが嫌だったので前段に処理を入れることで実現した。
#!/usr/bin/perl
use strict;
use warnings;
# 以下のコマンドでIP::Geolocation::MMDBをインストールしていることが前提
# cpanm -l extlib IP::Geolocation::MMDB
use lib './extlib/lib/perl5';
use IP::Geolocation::MMDB;
# https://download.db-ip.com/free/dbip-city-lite-YYYY-MM.mmdb.gz
# ex. https://download.db-ip.com/free/dbip-city-lite-2026-01.mmdb.gz
my $db = IP::Geolocation::MMDB->new(file => './DBIP-City.mmdb');
my $country_code = $db->getcc($ENV{REMOTE_ADDR});
# 日台韓は許可する方針(怪しい挙動を見たことがないため)
my @allow_country_codes = ('JP', 'TW', 'KR');
my $user_agent = $ENV{HTTP_USER_AGENT};
# 許可する国コードかチェック
my $is_allowed_country = grep { $_ eq $country_code } @allow_country_codes;
# 許可するBOTのUAパターン
my @allowed_bot_patterns = (
qr/bot/i,
qr/curl/i,
qr/wget/i,
qr/google/i,
qr/bing/i,
qr/mastodon/i,
qr/misskey/i,
qr/pleroma/i,
qr/akkoma/i,
qr/lemmy/i,
qr/activitypub/i,
qr/hatena/i,
qr/github/i,
qr/tumblr/i,
qr/meta/i
);
# 許可するBOTかチェック
my $is_allowed_bot = 0;
for my $pattern (@allowed_bot_patterns) {
if ($user_agent =~ $pattern) {
$is_allowed_bot = 1;
last;
}
}
# 許可国でもなく、許可BOTでもなければエラーにする
if (!$is_allowed_country && !$is_allowed_bot) {
# 未知のSNS BOTを将来的に許可するために、BOTくさいUAのログを集めておく
if ($user_agent !~ /Windows|Mac OS|Linux|Android|iOS|iPhone|iPad/i) {
# OGP取得BOTに間違いなく含まれない文字列が入ってるものはログに入れない
my $deny_ua_log_file = './deny_ua.log';
if (open my $fh, '>>', $deny_ua_log_file) {
my $time = localtime();
my $remote = $ENV{REMOTE_ADDR} // 'unknown';
my $uri = $ENV{REQUEST_URI} // 'unknown';
print $fh "[$time]\t\"$user_agent\"\t$country_code\t$remote\t$uri\n";
close $fh;
}
}
print "Status: 403 Forbidden\n";
print "Content-Type: text/plain; charset=UTF-8\n\n";
print "Access denied.\n";
exit;
}
# adiary呼び出し
my $original_cgi = './adiary.cgi';
exec($original_cgi) or die "Cannot exec $original_cgi: $!";
備考
perldocを読んだ感じ、互換性に問題が出る可能性も少なからずあるようだ。
perldocのexec関数の説明を見る感じ、ENDブロックや、オブジェクトのDESTROYメソッドを起動しないとあるので、実装方法次第では正しく動かない可能性もあるのかもしれない。
また「戻って欲しい場合には、execではなく system関数を使ってください」とあるため、もし後処理をしたい場合はexec関数でなくsystem関数を使うとよいと思う。
あとがき
レンタルサーバーではWAFが自由に使えないため、なんちゃってWAFの様なものを作りたいとか、レンタルサーバーを新規に始めたく、CGIにバナー広告を差し込みたいといったケースがある場合に、今回のような手法は便利だろう。
今時、往年のレンタルサーバーを新規に始め、それもバナー広告を出したいと考える人物がいるかどうかは謎だが、共通的に何かを差し込みたいなど、何かしら活用方法はあるかもしれない。
ググって出てきた記事が軒並み古くて役に立たなかったので、令和八年最新版として書いておく。
やり方
- CPANMのインストール
curl -L https://cpanmin.us | perl - App::cpanminus - CPANMのパスを
.cshrcに書く
私はZSHを使っているため.zshrcに書いているが、デフォルト環境はcshのはずなので.cshrcに書けば成り立つと思う。echo PATH=${HOME}/perl5/bin:${PATH} - local::libをインストールする
local::libはroot以外にあるCPANモジュールを使うためのものらしい。これを自分のホームディレクトリ配下に入れるようにコマンドを流す。cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
使い方
以下のようなコマンドを流すとパスを指定してCPANモジュールを取得・展開できる。
# 書式
cpanm -l <パス> <モジュール名>
例えば以下を流すとpwd配下にextlibディレクトリが生成され、IP::Geolocation::MMDBがダウンロードされて展開される。勿論、依存関係も勝手に解決してくれる。
cpanm -l extlib IP::Geolocation::MMDB
モジュールを利用するときはライブラリの配置されているルートを指定し、次にモジュール名を指定するとうまくいくようだ。
use lib './extlib/lib/perl5';
use IP::Geolocation::MMDB;
あとがき
https://cpanmin.us/を見に行くと以下の記述があり、辿ってみると日本の人が作っていてちょっと驚いた。
# This is a pre-compiled source code for the cpanm (cpanminus) program.
# For more details about how to install cpanm, go to the following URL:
#
# https://github.com/miyagawa/cpanminus
先日2026年のBluesky予測という記事が発表され、とても素晴らしい理念だと思ったので感想をつづってみる。
SNS疲れについては過去にもネット疲れの一つのような感じで軽く触れたが、昨今SNSに疲れを感じている人は少なくないと思う。本記事では、Blueskyが提唱する『インターネットを再び良くする』という理念への個人的な感銘を書いていく。
情報の掃きだめの打破
現在のSNSは憂鬱で、攻撃的で、人間味のない「情報の掃き溜め」になってしまい、Instagramではフォローしている投稿がほとんど表示されなくなり、Xでは非同意ポルノが氾濫している。オンラインコミュニティは延々とスクロールし続けて可処分時間を溶かす装置となった。
これらの実装は全て人間がやってきたことだから、つまり同じ人間により覆すことができるという考えをBlueskyは持っているようだ。
Blueskyでは似た分野の投稿を集める機能を開発する予定があるそうで、これによって見知らぬ人たちと一緒にライブ体験を共有し、瞬時に友人になったかのような感覚を味わうことができると言っている。
きっとこれは、かつてMMORPGにあった祭りのようなものだろう。その場の熱気で見知らぬ人が集まり、思い思いに熱狂する、そういった事ができるのだろう。
つまりBlueskyは玉石混交で様々な情報がごちゃごちゃになった場所、自分がその時に見たい情報やフォロイーの動静といった、自分が求める情報だけが整然と並ぶ場所を目指しているのだろう。
南アフリカにはポンテタワー[1]と呼ばれるビルがある。ポンテタワーは中央の吹き抜けに数階分のゴミが堆積した高層ビルだ。今のSNSはまさにそういった状態で、Blueskyとしてはそういった状況を打破したい、この現状はよくないと思っているというわけだ。
これはある意味でXのおすすめタブのような新しい出会いに出会う機会は減るが、逆に言えば常に新規性のある情報に触れ続け、それを浪費し、三日前に見たもののことなど既に覚えてすらいないような状況より、遥かに健全だ。
インターネット上の小さな奇跡との出会い
Blueskyでは「ウェブ上で見つけたり自分で作った素晴らしいものを共有するための場所」を目指したいと考えているそうで、それは「『これはすごい!』と感動できるような、デジタルの小さな奇跡に出会う場所」だそうだ。
これが何かというと、恐らく個人の創作や、簡単なプログラム開発といった趣味の成果物の話だと私は考えている。
つまりバズることを目的に、世間を煽る創作をしたり、コンビニの冷蔵庫に入ったりすることではないということだ。みんな芸人をやめて普通に振舞おうということかもしれない。
Xではきわどいネタを無限に投稿しバズっている人がいるが、あの人たちが本心でやっているかというと、個人的には懐疑的だ。広告塔になり、自分の製品が売れるからとか、単に目立って承認欲求が満たされるからしている可能性は十分にあるだろう。
私は千人、一万人にリーチするより、ごく限られた数名にリーチする方が価値があると思う。これは人口に膾炙してしまうと聞きたくない意見が聞こえてきたり、そもそも全部を全部見るのが不可能になるからだ。
「あなたの記事で助かりました」「あなたのイラストのここが好きです」と数回言われる分には把握できるし、もしその人がずっと見ていてくれれば、友達や仲間になれるかもしれない。しかし数が多いとどうだろう?もはや個人を意識することはないだろう。数字が伸びたから満足みたいなところに行きつくと思う。
勿論、商業ならそれでいいだろう。企業や個人事業主、大手同人サークルで売れれば売れるほどいいならそれでいい。でも趣味ならどうか?むしろひっそりやりたくないか?というのは思う。
主役はSNSではなく、その先にあるものである
ソーシャルプラットフォームが自らを「ワールドワイドウェブの主役」だと思い込み始めた時から、インターネットはおかしくなり始めました。
そう思い込んでいるのかどうかはわかりかねるが、これも非常に共感できた部分だ。
例えばイラストレーターはpixivに絵を上げ、一般人は日々の体験をTwitterに書き、動画はYoutubeやInstagramにアップする。つまり以前はWebサイトで発信していた事柄が創作も発信もSNS上で完結するようになった。
それに情報を探すときですらSNSが使われるようになっている。例えば2022年3月2日の日経にあるアメリカでは検索ワードにRedditをつける話や、2016年2月19日の日本の若者はGoogleを使わずにTwitterで検索をするという話も出ていることから、SNSは徐々にワールドワイドウェブの主役として、のし上がってきたことがうかがえる。
しかしプラットフォームでは大半の人は見るだけで、投稿者は再生数や売り上げを競うゲームになっている。その為に対立が煽られ炎上したりもするし、フォローしてもフォローしたコンテンツでないものが流れてきたり、コンテンツを見ていて気が付いたら全く違う場所にいたりする。
果たしてこんなものが主役であっていいのかという思いがある。勿論、古い人間の考え、老害の言うことだという意見もあるだろう。実際にそうだと思うし、だからこそ私はBlueskyの言うことに共感しているのだと思う。
私はSNSを無限にスクロールしコンテンツを浪費することよりは、たまにフィードに流れてきた興味深いリンクをクリックして、小さな奇跡を見つける方がより価値があると思う。
それはSNSで見つかる小さな奇跡と何が違うのかと言われれば、それを上手く説明することはできない。しかし、インターネット老人としてはそう思うのだ。
Blueskyで見つけたものに刺激を受け、Blueskyでの活動が減る
穏やかで、非消費的な世界では小さな奇跡を見つけ、それに刺激を受け、何かに取り組むことも増えるかもしれない。
そういった中ではSNSの滞在時間は減る。別の取り組みが始まるのだ。すると、人はきっとSNSで受けた刺激をもとに何か生産的な活動を行い、それをSNSに投稿する再生産を行うようになるだろう。
すると、SNSは穏やかになるかもしれない。何故なら活動中はSNSを利用していないからだ。
結果としてSNSは脇役となり、メインのアクティビティは別のものになるだろう。SNSに誘導され、SNSの利益になる活動ではなく、自身の利益になる、より有益な活動が生まれるはずだ。
Blueskyは次のように、ユーザーをSNSに閉じ込める罠をなくし、可処分時間を自分が意図したことに有効活用できるようになるということを述べている。これは実に素晴らしい考えだと思う。人間は他人に操作され、あたかも自分が思っていると勘違いした状態で行動すべきではないのだ。
ユーザーを罠にかけて閉じ込めるように設計されたプラットフォームから離れ、「インターネットは生活を消費するために構築されるべきではない」とはっきり言えるような空間へと人々が移動するにつれ、ダラダラとしたスクロールは減り、より意図的な利用が増えると予測しています。
あとがき
内容には感動したが、反面どこで儲けるのかが気になった。自鯖勢は自分で運用コストを負担しているので別として、一般の人々は本体側に行くだろうからね。
まぁそこはさておきとして、元記事中にある次の文章はとても美しい文章だと思った。
しかし、もし人間の選択によってインターネットが悪くなったのであれば、人間が別の何かを選択することで、インターネットを再び良くすることができるはずです。
インターネットを形作ってきたのは人間です。
そして、人々はそれをより良くすることができるはずです。
また次の文章も非常に気が利いていて面白い。
このために、皆様から絶えずご要望をいただいている下書き機能を追加します。
どうしてそんなに時間がかかったの?という質問に対しては、まだ気の利いた答えを用意している最中ですが、準備ができしだい公開予定です。
- 南アフリカの都市である、ヨハネスブルグで最も治安が悪いといわれるヒルブロウ地区にあるタワーマンション。かつては中央の吹き抜けに地上五階までゴミが溜まっていたといわれている。以前は入って五秒で殺されるなど、非常に治安が悪いことで知られていたが、近年では観光ツアーが組まれるほどに改善している。 ↩
投稿日:
他のサーバーを見ていて、ウチでもMastodonに翻訳ボタンを生やして機能させたくなったのでやってみた結果のログ。
内容としてはDeepLのアカウントを作成し、APIキーを取得し、Mastodonの.env.productionに追記して反映するだけなので、5分くらいあればできる。
月50万文字まで翻訳できるので、たまに短文の翻訳に使う程度なら必要十分だろう。
確認環境
- Mastodon v4.5.4
やり方
- DeepL ProのAPIタブを開き、無料プランに登録する。クレジットカードが必要だが、意図的にProプランにしなければ課金されないらしいので、恐らく害はないだろう。


- 適当にDeepLのAPIキーを取得する。
xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx:fxみたいな形式のやつ - 以下のコマンドで疎通確認
export API_KEY={APIキー} curl -X POST https://api-free.deepl.com/v2/translate \ --header "Content-Type: application/json" \ --header "Authorization: DeepL-Auth-Key $API_KEY" \ --data '{ "text": ["Hello world!"], "target_lang": "JA" }'
- Mastodonの
.env.productionに下記を追記DEEPL_PLAN=free DEEPL_API_KEY=XXXXXX-XXXX-XXXXX:fx - リビルド
RAILS_ENV=production bundle exec rails assets:clobber RAILS_ENV=production bundle exec rails assets:precompile - 再起動
sudo systemctl restart mastodon-web - 動作確認して動いていればOK


トラブルシューティング
クレカ登録時に「決済手段を認証できませんでした。別の決済手段を選択してやりなおしてください。 (Error Code: OFQUTG)」と言われる
ブラウザを変えるといける可能性がある。
これはWindows Edgeで試してこう言われ、何度試しても無理だったが、Android Edgeで試したら一発で行けたからだ。原因としては、StripeのSDKが以下のようなエラー吐いてたのが関係していたのではないかと思っている。
Applying inline style violates the following Content Security Policy directive 'style-src 'self''. Either the 'unsafe-inline' keyword, a hash ('sha256-XXXXXXXXXXXXXXXXXX='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present. The action has been blocked.
あとがき
別にEdgeについてるBing翻訳機能でもいいのだが、こっちのほうが操作が楽だし、DeepL翻訳がうまくいかなければ、Bing翻訳という手も使えると思えばアリだろう。
2026-01-30追記
Misskeyをはじめとした互換性のないサーバーからの投稿配信すべてに翻訳ボタンが生えてきて邪魔なので結局取り去ることに…。翻訳ボタンが必要なケースは私のユースケースでは少ないので、この結果は微妙だった…。
