From Azure Functions to FreeBSD

2025/12/08 17:02

From Azure Functions to FreeBSD

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

著者は、Rust ベースの Web サービス(EndBASIC、EndTRACKER、および今後リリース予定の ZFS‑auto‑unlock サービス)を Azure Functions から自己ホスト型 FreeBSD 14.x サーバへ移行した理由を説明しています。
Azure の Flex Consumption プランは 2028 年 9 月 30 日に終了し、3 つすべてのアプリで使用されていたフリーティアも廃止予定です。また、カスタム Rust ハンドラをサポートしていませんでした。著者は GitHub Actions CI/CD を利用してサービスを Rust バイナリとして実行していました。
感謝祭の日に発生した Azure Functions ランタイムの障害と、Microsoft SQL Server サーバーレスで TLS がサポートされていない(

sqlx
コネクタがアップストリームでパッチできなかった)問題により PostgreSQL への切替えを余儀なくされました。PostgreSQL に移行する際、著者は「開発専用」の $600 超のオプションではなく、月額 $15 のインスタンスを選択しました。
新しいデプロイメントは、著者のガレージにある 2×36 コア Xeon E5‑2697 FreeBSD サーバ(64 GB RAM、2 TB NVMe + 4×4 TB HDD)で稼働しています。Rust バイナリは
daemon(8)
を使って PID ファイルを管理し、ログローテーション(
-H
フラグ)、非特権実行、および
/usr/local/etc/endbasic.conf
での設定を行います。ログローテーションは FreeBSD の
newsyslog(8)
を利用しており、ログをリネームした後に SIGHUP が必要です。
TLS 終端は Cloudflare Tunnels により処理され、CORS ヘッダーはサーバ側ではなく Cloudflare 上で AI 生成の変換ルールを使って設定します。
移行後、著者はパフォーマンスが向上し Azure の課金が発生せず(電気代のみ)、ただし HA、スロットデプロイメント、およびプッシュデプロイ自動化を Azure が提供していたものと同等に再実装する必要があります。
ユーザー側ではサービスの信頼性とコスト削減が期待でき、企業側では自己ホスティングで費用を抑えられることは示されますが、HA、バックアップ、およびデプロイメントツールの管理を自前で行う必要があります。

本文

FreeBSD の「サーバーとしての力」を試す

感謝祭の朝、ウェブサービスの一つが利用不可になったことに気づいた。
HTTP リクエストはすべて 503 Service Unavailable で失敗し、コンソールへログインしても Runtime version: Error とだけ表示され、原因を突き止める手立ても見つからなかった。

多くの時間を費やしたくなく、サポートに連絡する気もない。ダッシュボード上部にある小さな黄色警告の裏側に別のメッセージが隠れていたので注意深く読んだ:

Migrate your app to Flex Consumption as Linux Consumption will reach EOL on September 30 2028 and will no longer be supported.

数週間前から、すべての Azure Functions アプリは「死刑列車」に乗っていると知っていた。
無料プランは廃止される予定で、Rust で書かれたカスタムハンドラをサポートする代替策も見つからず、3年は残っていたが、ある障害が行動を促した。

今では全てのウェブサービスをガレージに置いた FreeBSD サーバー上で稼働させ、コードベースは僅かに変更しただけ。ここが移行物語だ。


どうやってここまで来たか?

2021 年、EndBASIC 言語の開発を続けているうちに、ファイル共有サービスを作りたいと思った。
ユーザー満足度を高めると同時に、ウェブサービスへ踏み込む必要があったからだ。

その頃私は Microsoft で Azure Storage を担当しており、学習用に年間 $300 のクレジットが付与された。
シンプルなアプリならこの額で十分だと判断し、Azure が最適だと思った。

サーバーレスの「無限無料」層を利用するため、Rust 版関数を Linux ランタイムへデプロイする方法を見つけてすぐにベースサービスを構築した。
そこから EndTRACKER(分析サービス)や、最近では暗号化された ZFS ボリュームの自動アンロックを行う新機能を追加していった。

3 年間は Azure で問題なく稼働し、GitHub Actions とデュアルステージング/本番展開で「プッシュオングリーン」を実現した。だが…


クラウドデータベース

計算リソースは十分だった:Azure Functions は低コストで動作し、$300 のクレジットをほぼ使い切らなかった。
しかしウェブサービスにはデータベースも必要だった。

2021 年に唯一の無料層として サーバーレス Microsoft SQL Server (MSSQL) を見つけたが、未経験で PostgreSQL や MySQL 風だと勘違いしていた。

sqlx
の TLS 対応を追加するために 2 週間費やしたものの、PR はマイクロソフト側の戦略と衝突し却下された。
さらに機能不足やバグが次々現れ、MSSQL 方言に挫折した。

そこで Azure の管理 PostgreSQL を利用することに決めた。オンボーディングウィザードは冗長で高価なインスタンスを勧めてくるが、設定を下げ「リスクを受け入れ」$15/月 で自分のトラフィックに合ったサーバーを手に入れた。


障害と引き金

約 2 ヶ月前に ZFS ボリュームの自動アンロックサービスを作り始めた。
デプロイ時に「選択したプランは 2028 年に廃止予定」という警告が表示された。

書き込みの時点では 3 年後という距離で問題と感じていなかったが、感謝祭の日に分析サービスが動かなくなり、すべての HTTP API が 503 を返した。
新しいビナリをデプロイしても改善しない。ダッシュボードで Runtime version: Error を探しても何も見つからず、結局は運用上のトラブルだった。


速やかに Azure Functions から離れた理由

二年前に中古 ThinkStation(2×36 コア Xeon E5‑2697、64 GB RAM、2 TB NVMe、4 × 4 TB HDD)を購入した。
本来は開発サーバーだったが、最終的には FreeBSD 14.x 上でサービスをホストすることになった。


サーバーレスからセルフホストへ

Azure Functions は

FUNCTIONS_CUSTOMHANDLER_PORT
で指定されたポートに HTTP サーバーを起動する Rust(または Go)バイナリを実行する。
バイナリとメタデータ JSON を ZIP にまとめて Azure にアップロードすると、ランタイムが TLS 終了処理・マイクロ VM での起動・リクエスト転送を担当してくれる。

Azure Functions ランタイムを削除したので、自前サーバーはスタンドアロンで稼働させる必要があった。
バイナリはすでに HTTP サーバー機能を持っているため、以下の点だけを設定すればよかった。

目的実装
設定変数注入
daemon
-P
/
-o
で PID とログファイルを指定し、
. /usr/local/etc/endbasic.conf
で環境変数を読み込む。
特権昇格解除
-u endbasic
で非特権ユーザーとして起動。
プロセス管理FreeBSD の
daemon(8)
を利用し、
rc.d
スクリプトで自動起動・再起動を実装。
ログローテーション
-H
newsyslog(8)
を呼び出し、ログファイルを安全に回転させる。
daemon \
    -P /var/run/endbasic.pid \
    -o /var/log/endbasic.log \
    -H \
    -u endbasic \
    -t endbasic \
    /bin/sh -c '
        . /usr/local/etc/endbasic.conf
        /usr/local/sbin/endbasic'

rc.d
スクリプト例:

#! /bin/sh
# PROVIDE: endbasic
# REQUIRE: NETWORKING postgresql

. /etc/rc.subr

name="endbasic"
command="daemon"
rcvar="endbasic_enable"
pidfile="/var/run/${name}.pid"
start_cmd="endbasic_start"

required_files="
    /usr/local/etc/endbasic.conf
    /usr/local/sbin/endbasic"

endbasic_start()
{
    [ ! -f /var/log/endbasic.log ] && {
        touch /var/log/endbasic.log
        chmod 600 /var/log/endbasic.log
        chown endbasic /var/log/endbasic.log
    }

    echo "Starting ${name}."
    daemon \
        -P "${pidfile}" \
        -o /var/log/endbasic.log \
        -H \
        -u endbasic \
        -t endbasic \
        /bin/sh -c '
            . /usr/local/etc/endbasic.conf
            /usr/local/sbin/endbasic'
}

load_rc_config $name
run_rc_command "$1"

sysrc endbasic_enable="YES"
service endbasic start
でサービスが起動する。


ログローテーション

-H
はログ回転を有効にするオプション。
Unix ではプロセスがファイルハンドルを保持したまま名前変更や削除を行うと、書き込みは継続し残りファイルが参照できなくなるためディスクがいっぱいになる。

daemon(8)
newsyslog(8)
を呼び出してローテーションを実施し、プロセスに SIGHUP を送ってログファイルを再オープンさせる。
例として
/usr/local/etc/newsyslog.d/endbasic.conf
の設定は次のようになる。

/var/log/endbasic.log endbasic:wheel 600 7 * @T00 JC /var/run/endbasic.pid

数字で保持期間、ローテーション頻度、圧縮方法を制御する(詳細はマニュアル参照)。


TLS 終了

以前は Azure Functions が TLS を終端していた。
ランタイム無しのため自前で設定するかしないかの選択肢が出た。

Cloudflare Tunnels を利用すれば、

cloudflared
をインストールし
http://localhost:PORT
へ転送させるだけで TLS と DDoS 防御を Cloudflare が担う。
第三者にトラフィックが見える点はリスクだが、Azure Functions と同様だったので問題ないと判断した。


CORS

Cloudflare をフロントエンドに使ったため CORS の設定が必要になった。
サーバー側で設定しても効果がなく、実際には Cloudflare で Edge Rule を作成し必要なヘッダーを付与した。

AI が提案したルール例:

# Sample Cloudflare transformation rule to set CORS response headers

「クラウド外に出さない」方式で機能することを確認した。


移行後の実感

取得できたもの捨てたもの
予測可能性 – プライベート環境でアップグレードを自分で管理。可用性/冗長性 – マルチリージョンフェイルオーバーがなく、移行後に 2 時間の停電を経験。
パフォーマンス – 常駐サーバーはサーバーレス起動より高速。運用負荷 – 手動デプロイ・データベース管理・ログ監視が必要。
コスト削減 – Azure の月額約 20 USD がほぼゼロに。既存ハードウェアは他用途でも使える。機能 – Azure のサーバーレスランタイム、オートスケール、統合モニタリングを失う。

結論

Azure Functions から FreeBSD サーバーへ移行するには数時間で完了できる。

daemon(8)
newsyslog(8)
、Cloudflare Tunnels、Edge Rule を組み合わせれば、TLS 終端と CORS の設定も簡単に実装できる。

手動管理のコストは増えるが、自己ホストなら費用を抑えつつ予測可能な運用が可能になる。
感謝祭の朝に行った移行作業は、自由度と安定性のバランスを再確認する良い機会となった。

同じ日のほかのニュース

一覧に戻る →

2025/12/14 7:58

Linux Sandboxes and Fil-C

## Japanese Translation: メモリ安全性とサンドボックスはプログラムの異なる部分を保護するため、両方が強力なセキュリティに必要です。純粋な Java プログラムはメモリ安全であってもファイルシステムの syscalls を通じて任意のファイルを書き込むことができるし、逆にすべての能力を取り消したアセンブリプログラムでもメモリバグがある場合がありますが、カーネルが特権 syscalls を殺すためサンドボックスから逃げられません。サンドボックスは意図的に許容範囲を広く設計しているため、攻撃者は残されたメモリ安全性のバグを利用してブローカー・プロセスへ到達することができるので、両方の防御を組み合わせるとより強固な保護が得られます。 本書では、C/C++ 用に設計され、システムコールまで安全性を保証し、init や udevd などの低レベルコンポーネントで使用できるメモリ安全ランタイム「Fil‑C」への OpenSSH の seccomp ベース Linux サンドボックス移植方法について説明します。OpenSSH は既に chroot を採用し、`sshd` ユーザー/グループとして特権なしで実行し、`setrlimit` を使用し、非許可 syscalls を `SECCOMP_RET_KILL_PROCESS` で殺す seccomp‑BPF フィルタを適用しています。Fil‑C はその runtime 内で自動的にこれらの syscalls を許可することで簡素化します。背景スレッドは存続させつつスレッド生成を防ぐため、Fil‑C は API `void zlock_runtime_threads(void)` を追加し、必要なスレッドを事前確保してシャットダウンを無効にします。 OpenSSH の seccomp フィルタは強化されています。失敗時の挙動が `SECCOMP_RET_KILL` から `SECCOMP_RET_KILL_PROCESS` に変更され、mmap 許可リストに新たに `MAP_NORESERVE` フラグが追加され、`sched_yield` が許可されています。サンドボックスは二つの `prctl` コール(`PR_SET_NO_NEW_PRIVS` と `PR_SET_SECCOMP`)で構築され、エラー検出も行われます。Fil‑C のランタイムは `filc_runtime_threads_handshake` で全スレッドとハンドシェイクし、各スレッドが no_new_privs ビットと seccomp フィルタを持つことを保証します。複数のユーザー スレッドが検出された場合、安全エラーが発生します。 メモリ安全性とサンドボックスを組み合わせることで、OpenSSH はより厳格な隔離を実現し、メモリバグによる権限昇格リスクを低減します。このアプローチは他のセキュリティクリティカルプロジェクトにも採用を促す可能性があります。

2025/12/14 9:34

An Implementation of J

## Japanese Translation: ## 改訂版要約 本書は、技術仕様の構造化された目次であり、以下のように整理されています。 1. **第0章 – はじめに** 2. **第1章 – 文を解釈する** - 1.1 単語生成 - 1.2 構文解析 - 1.3 トレイン(列車) - 1.4 名前解決 3. **第2章 – 名詞** - 2.1 配列 - 2.2 型 - 2.3 メモリ管理 - 2.4 グローバル変数 4. **第3章 – 動詞** - 3.1 動詞の構造 - 3.2 ランク - 3.3 原子(スカラー)動詞 - 3.4 オブヴァース、同一性、および変種 - 3.5 エラー処理 5. **第4章 – 副詞と接続詞** 6. **第5章 – 表現** - 5.1 原子表現 - 5.2 ボックス化された表現 - 5.3 木構造表現 - 5.4 線形表現 7. **第6章 – ディスプレイ** - 6.1 数値表示 - 6.2 ボックス化表示 - 6.3 フォーマット済み表示 主要セクションの後に、付録A〜F(インキュナブルム、スペシャルコード、テストスクリプト、プログラムファイル、外国接続詞、およびシステム概要)が補足資料として提供されます。書末には参考文献・用語集・索引が付されています。 この構成(目次 → 詳細セクション → 付録 → 参照資料)は、読者に全体枠組みを最初に把握させたうえで、必要に応じて詳細へ掘り下げたり補足資料を参照したりできる明確かつ階層的な道筋を提供します。

2025/12/14 8:39

Closures as Win32 Window Procedures

## Japanese Translation: **改訂版要約:** この記事では、Win32 のウィンドウプロシージャに追加のコンテキストポインタを渡す方法を示しています。これは、WndProc が通常 4 つしか引数を取らないため、ネイティブ API には備わっていない機能です。著者は x64 アセンブラで小さなトランスペイル(trampoline)を作成し、実行時に JIT コンパイルして 5 番目の引数スロットを挿入し、呼び出し前に必要なコンテキストを格納します。これにより、各ウィンドウがグローバル変数や `GWLP_USERDATA` を使わずに独自の状態を保持できるようになります。トランスペイルは GNU アセンブラで書かれ、`.exebuf` セクション(`bwx` フラグ付き)から 2 MiB の実行可能バッファが確保されます。C ヘルパー関数 `make_wndproc(Arena *, Wndproc5, void *arg)` は 2 つのバイトオフセットプレースホルダーを修正してトランスペイルを生成します。作成後は `set_wndproc_arg(WNDPROC p, void *arg)` を使ってコンテキストを変更できます。アロケータ例では、異なる状態オブジェクト用に複数のトランスペイルを生成したり、動的に切り替えたりする方法を示しています。この手法は、トランスペイルがアンウインドテーブルを持たないため Windows Control Flow Guard 下でも安全に機能し、グローバル変数を使わずにウィンドウごとのデータを付与する低レベルの手段を示しています。