- 技術 💻
Railwayとは|使い方・料金・デプロイ手順とエラー対処を実例で
結論
Railwayは、GitHubやCLIからアプリとDBをまとめてデプロイできるPaaSです。料金は使った分の従量課金で、Hobbyは月5ドルからです。
この記事でわかること
- 用語6つの表と、GitHubからデプロイする6手順
- 料金4プランと、月額を試算した3つの例
- ポート・ヘルスチェックの失敗8通りの再現と直し方
コードを GitHub に push するか railway up で送ると、Railway がコンテナイメージを作って起動し、PORT で待っているアプリに公開用の URL をつなぎます。
flowchart TD
A[GitHub に push<br>または railway up] --> B[Railpack か<br>Dockerfile でビルド]
B --> C[コンテナを起動<br>PORT を渡す]
C --> D[ヘルスチェック<br>2xx なら切り替え]
D --> E[xxx.up.railway.app<br>で公開]
C --> F[(PostgreSQL など<br>同じプロジェクト)]
急いでいる人向けに、目的ごとの方法を先にまとめます。
| やりたいこと | 方法 | 詳しい節 |
|---|---|---|
| GitHub のアプリを公開 | New Project → GitHub repo → Deploy Now | 始め方 |
| 公開 URL を付ける | Settings → Networking → Generate Domain | ドメインとポート |
| DB を足す | + New → PostgreSQL、${{Postgres.DATABASE_URL}} |
PostgreSQL |
| 手元からデプロイ | npm i -g @railway/cli → railway up |
railway CLI |
| 502 で開けない | 0.0.0.0 と PORT で待つ |
よくあるエラー |
| データを残す | ボリュームを付ける(例 /app/data) |
ボリューム |
| 無料で試す | トライアル 5ドル(30日)→ Free 月1ドル | 料金 |
| 設定をファイルで管理 | .railway/railway.ts(railway.json は2026年12月1日まで) |
設定をコードで管理 |
確認環境:Ubuntu 24.04.4・Node.js 22.22.2・npm 10.9.7・@railway/cli 5.71.0(npm の latest、2026年10月22日時点)・railway(IaC の TypeScript SDK)3.16.0・TypeScript 7.0.2・pg 8.23.1・PostgreSQL 16.15・Python 3.11.15。railway CLI は npm で入れて --version・--help を実行しました(ログインが要る操作はしていません)。Railway と同じ形のアプリ(PORT を読む Node.js)を手元で起動し、ポート・待ち受けアドレス・ヘルスチェック・SIGTERM・DATABASE_URL の失敗を再現しました。ヘルスチェックは、Railway のドキュメントにある条件(Host が healthcheck.railway.app、2xx で成功、時間内に返らなければ失敗)をまねたスクリプトで確かめました。料金・画面の操作・Railpack・ドメイン・ボリュームの仕様は docs.railway.com・railway.com/pricing・railpack.com で、他社の値は各社の公式ページで確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Railwayとは|使い方・料金・デプロイ手順とエラー対処を実例で」
Railwayとは:何ができるPaaSか
この節では、Railway が何を受け持つサービスで、何を自分で用意するかが分かります。
Railway(レイルウェイ)は、Web アプリ・API・データベース・定期実行のジョブなどを、サーバーを管理せずに動かせる PaaS(Platform as a Service)です。 公式のクイックスタートは、GitHub のリポジトリを選ぶか、CLI で railway init → railway up を実行するだけでデプロイできる流れを示しています。英単語の railway(鉄道)とは別物で、この記事では開発者向けのサービス railway.com を扱います。
利用者が用意するのは、アプリのコードと「どのポートで待つか」の2つです。ビルド・コンテナの起動・HTTPS・公開 URL は Railway が受け持ちます。
1設定なしでビルド
Railpack がコードの言語(Node・Python・Go・PHP・Java・Ruby など)を見分け、依存の導入・ビルド・起動コマンドを決めます。Dockerfile があればそれを使います。
2DB を同じ画面で足せる
PostgreSQL・MySQL・Redis・MongoDB を追加でき、接続文字列を参照変数でアプリに渡せます。
3使った分だけの課金
CPU・メモリ・ボリューム・外向きの通信量を秒単位の単価で数えます。ビルドにかかる分は課金されません。
4環境とプレビュー
production のほかに staging などの環境を作れ、プルリクエストごとの一時的な環境も作れます。
静的なサイトだけでなく、常に動き続けるサーバー(Express・FastAPI・Rails・Spring Boot など)や WebSocket、ワーカー、cron のジョブも置けます。ここが、静的サイトとサーバーレス関数が中心のサービスとの大きな違いです(後の「違い」の節で表にします)。
常に動かすアプリは、Hobby(月5ドル)以上が前提になる(料金の節)
新しい書き方は .railway/railway.ts(Infrastructure as Code)
ドメインは xxx.up.railway.app の形。独自ドメインも追加できる
Railwayの用語:プロジェクト・サービス・環境・変数・ボリューム・ドメイン
この節では、Railway の画面と CLI に出てくる6つの言葉の関係が分かります。
Railway は「プロジェクト」の中に「環境」があり、環境ごとに「サービス」が並ぶ形です。
flowchart TD
P[プロジェクト] --> E1[環境 production]
P --> E2[環境 staging]
E1 --> S1[サービス web<br>ドメイン付き]
E1 --> S2[(サービス Postgres)]
S2 --> V[ボリューム<br>データを保存]
| 用語 | 何か | 例・ポイント |
|---|---|---|
| プロジェクト(Project) | 関連するサービスをまとめる単位。画面ではキャンバスに並ぶ | 「shop」プロジェクトに web・api・Postgres |
| サービス(Service) | 1つのコンテナで動くもの。GitHub・Docker イメージ・ローカルのフォルダから作る | web・worker・Postgres |
| 環境(Environment) | サービスと変数の組を丸ごと分ける単位。作成時は production がある |
staging・PR ごとの一時的な環境 |
| 変数(Variables) | サービスに渡す環境変数。ビルド中と実行中の両方で読める | DATABASE_URL・API_KEY |
| ボリューム(Volume) | 再デプロイしても消えない保存場所。1サービスに1つ | /app/data にマウント |
| ドメイン(Domain) | 公開用の URL。*.up.railway.app か独自ドメイン |
ターゲットポートを1つ選ぶ |
環境は互いに切り離されています。 staging で変数を変えても production には影響しません。環境ごとに専用のプライベートネットワークがあり、同じ環境のサービスどうしは サービス名.railway.internal で通信できます。
ほかに、デプロイ1回ごとの記録を「デプロイメント(Deployment)」と呼びます。画面のサービスの Deployments タブに一覧が出て、そこからロールバックや再起動をします。
Railwayの料金:無料トライアル・Free・Hobby・Pro(2026年10月22日時点)
この節では、2026年10月22日時点のプランと、何にいくらかかるかが分かります。
Railway の料金は「プランの月額」と「使った分の利用額」の組み合わせです。 Hobby と Pro は、月額と同じ金額の利用分が含まれ、超えた差額だけが加わります。料金ページと docs.railway.com の「Plans」で確かめた値です。
| プラン | 月額 | 含まれる利用分 | 1サービスの上限(主なもの) |
|---|---|---|---|
| Free | 0ドル | 月1ドル(最初の30日はトライアル5ドル) | 1 vCPU・0.5GB・ボリューム 0.5GB・レプリカ1 |
| Hobby | 5ドル | 月5ドル | 48 vCPU・48GB・ボリューム 5GB・レプリカ6 |
| Pro | 20ドル | 月20ドル | 1,000 vCPU・1TB・ボリューム 1TB・レプリカ42 |
| Enterprise | 個別見積もり | 個別 | 2,400 vCPU・2.4TB・レプリカ50 |
課金されるのは「割り当て」ではなく、実際に使った CPU とメモリです。料金ページは、ビルドの CPU・メモリ・イメージの保存は課金しないと書いています。
プランごとの違い(ログ・ドメイン・ロールバック)
| 項目 | Free・トライアル | Hobby | Pro |
|---|---|---|---|
| ログの保存 | 3日(トライアル中は7日) | 7日 | 30日 |
| ロールバックできる期間 | 24時間 | 72時間 | 120時間 |
| 独自ドメイン | トライアルは合計1つ | 1サービス2つ | 1サービス20個(申請で増やせる) |
| 再起動ポリシー | Always は使えない・最大10回 | すべて使える | すべて使える |
| リージョン | 複数リージョンは使えない | 選べる | 同時に複数を使える |
(料金ページ・「Plans」・「Working with Domains」・「Restart Policy」による。)
無料トライアルとFreeプラン
- トライアル:最初に1回だけ5ドル分。30日か5ドルを使い切ったところで Free に移ります。トライアル中のクレジットは30日で失効します。
- Full と Limited:GitHub アカウントの確認が通ると Full trial(コード・DB を外向きの通信つきで動かせる)、通らないと Limited trial(外向きの通信と使えるポートが制限される)です。確認は自動で、railway.com/verify からいつでも受けられます。
- Free:毎月1ドル分。繰り越しはありません。
- データ:トライアルのボリュームは、クレジットの失効から30日後に削除されます。Hobby をやめた場合は60日後、Pro は90日後です。
月額の試算(Python で計算)
秒単価をそのまま掛けた目安です。
# Railway の月額の目安(料金ページの秒単価:2026年10月22日時点)
CPU = 0.00000772 # $ / vCPU / 秒
RAM = 0.00000386 # $ / GB / 秒
VOL = 0.00000006 # $ / GB / 秒
EGRESS = 0.05 # $ / GB
SEC = 30 * 24 * 60 * 60 # 30日
def usage(vcpu, ram_gb, vol_gb=0, egress_gb=0):
return vcpu * CPU * SEC + ram_gb * RAM * SEC + vol_gb * VOL * SEC + egress_gb * EGRESS
def bill(u, plan):
fee = {"Hobby": 5, "Pro": 20}[plan] # 月額=含まれる利用分
return max(fee, u) # 含まれる分を超えた差額だけ増える
cases = [
("小さなAPI(平均0.02vCPU・150MB)", [(0.02, 0.15, 0, 1)]),
("API+PostgreSQL(DB 1GB)", [(0.05, 0.30, 0, 5), (0.02, 0.20, 1, 0)]),
("常に忙しいAPI(0.5vCPU・512MB)", [(0.5, 0.5, 0, 10)]),
]
print(f"1vCPU 30日 = ${CPU*SEC:.2f} / 1GB 30日 = ${RAM*SEC:.2f} / ボリューム1GB 30日 = ${VOL*SEC:.3f}")
for name, svcs in cases:
u = sum(usage(*s) for s in svcs)
print(f"{name}: 利用額 ${u:.2f} → Hobby ${bill(u,'Hobby'):.2f} / Pro ${bill(u,'Pro'):.2f}")
1vCPU 30日 = $20.01 / 1GB 30日 = $10.01 / ボリューム1GB 30日 = $0.156
小さなAPI(平均0.02vCPU・150MB): 利用額 $1.95 → Hobby $5.00 / Pro $20.00
API+PostgreSQL(DB 1GB): 利用額 $6.81 → Hobby $6.81 / Pro $20.00
常に忙しいAPI(0.5vCPU・512MB): 利用額 $15.51 → Hobby $15.51 / Pro $20.00
小さな API なら Hobby の5ドルに収まり、DB を足すと少し超える、という目安です。Free の月1ドルでは、1つ目の例(1.95ドル)でも足りません。実際の使用量は、サービスの Metrics タブや railway usage で確かめられます。
料金を抑える設定
- Serverless(以前の App Sleeping):外向きの通信が5分ないとサービスを眠らせ、次のリクエストで起こします。実際に眠るのは最後の通信から5〜10分後で、起きる最初のリクエストは遅れたり 502 になったりすることがあります。DB への常時接続など、外向きの通信があると眠りません。
- 使っていないデプロイを Remove:Deployments の三点メニューの Remove で、そのデプロイの利用が止まります。
- 使用量の上限:
railway usage limit statusで、ワークスペースに設定した上限を確かめられます(CLI のヘルプより)。
Railwayの始め方:GitHubからデプロイする手順
この節では、アカウント作成から公開 URL が付くまでの流れが分かります。
railway.com でアカウントを作る
GitHub アカウントで登録すると、リポジトリの連携とトライアルの確認(Full trial)が同時に進みます。
New Project → GitHub repo
ダッシュボードの New Project から GitHub repo を選び、リポジトリを検索して選びます。
Deploy Now か Add variables
すぐ動かすなら Deploy Now。API キーなどが要るなら Add variables で先に変数を入れ、キャンバス上部の Deploy を押します。
ビルドログを見る
サービスの Deployments でビルドとデプロイのログを見ます。失敗したら最初のエラー行を探します。
Generate Domain で URL を付ける
Settings → Networking → Public Networking の Generate Domain で xxx.up.railway.app が付きます。
以降は push で自動デプロイ
連携したブランチに push するたびに、ビルドとデプロイが走ります。
CLI で始める場合は、プロジェクトのフォルダで次の3つを実行します(クイックスタートの手順)。
railway init # 空のプロジェクトを作り、このフォルダと結びつける
railway up # フォルダを圧縮して送り、ビルドとデプロイをする
railway open # ブラウザーでプロジェクトのキャンバスを開く
railway up は .gitignore に書いたファイルを送りません(--no-gitignore で変えられる)。GitHub 連携とローカルからの railway up の違いは、関連記事「デプロイとは|ビルド・リリースとの違いとロールバックを実例で解説」で扱っています。push のたびにテストを通してから出す流れは、関連記事「CI/CDとは|GitHub Actionsで最初のパイプラインを作るまで」で扱っています。
Railwayで動くアプリの形(PORTを読むNode.jsで実演)
この節では、Railway に置くアプリが守る2つの約束と、手元で同じ形のアプリを動かした結果が分かります。
Railway に置くアプリは「環境変数 PORT のポートで」「0.0.0.0(すべてのアドレス)で」待ち受けます。 Railway は PORT を自動で入れ、ヘルスチェックもその値を使います(「Healthchecks」「Application Failed to Respond」)。
サンプルのアプリ
railway-demo/
├── package.json … "start": "node server.mjs"、依存は pg だけ
└── server.mjs … PORT で待ち、/health と /db を返す
{
"name": "railway-demo",
"version": "1.0.0",
"type": "module",
"engines": { "node": "22.x" },
"scripts": {
"start": "node server.mjs"
},
"dependencies": {
"pg": "^8.16.0"
}
}
// server.mjs:Railway と同じ形で動く最小の Web サーバー
import http from "node:http";
import pg from "pg";
const port = Number(process.env.PORT) || 3000; // Railway が PORT を入れる
const host = process.env.HOST || "0.0.0.0"; // 外から届くように全アドレスで待つ
const pool = process.env.DATABASE_URL
? new pg.Pool({ connectionString: process.env.DATABASE_URL })
: null;
const server = http.createServer(async (req, res) => {
if (req.url === "/health") { // ヘルスチェック用
res.writeHead(200, { "content-type": "text/plain" });
return res.end("ok");
}
if (req.url === "/db") {
if (!pool) { res.writeHead(500); return res.end("DATABASE_URL is not set"); }
try {
const { rows } = await pool.query("select current_database() as db, version() as v");
res.writeHead(200, { "content-type": "application/json" });
return res.end(JSON.stringify({ db: rows[0].db, version: rows[0].v.split(" ").slice(0, 2).join(" ") }));
} catch (e) { // DB に届かなくてもプロセスは落とさない
console.error("db error:", e.code, e.message);
res.writeHead(503); return res.end("database unavailable");
}
}
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({
message: "hello from railway-demo",
service: process.env.RAILWAY_SERVICE_NAME ?? "(local)",
environment: process.env.RAILWAY_ENVIRONMENT_NAME ?? "(local)",
}));
});
server.listen(port, host, () => console.log(`listening on ${host}:${port}`));
// 再デプロイのとき Railway は SIGTERM を送る。受けたら新しい接続を止めて終わる
process.on("SIGTERM", () => {
console.log("SIGTERM received, closing server");
server.close(async () => {
await pool?.end();
console.log("closed");
process.exit(0);
});
});
手元で動かした結果
PORT なしと、PORT と Railway が入れる変数(RAILWAY_SERVICE_NAME など)を付けたときで起動しました。curl は、ループバックではない IP アドレス(192.0.2.2)から呼んでいます。
$ node server.mjs
listening on 0.0.0.0:3000
$ PORT=32401 RAILWAY_SERVICE_NAME=web RAILWAY_ENVIRONMENT_NAME=production node server.mjs
listening on 0.0.0.0:32401
$ curl -i http://192.0.2.2:32401/
HTTP/1.1 200 OK
content-type: application/json
{"message":"hello from railway-demo","service":"web","environment":"production"}
$ curl http://192.0.2.2:32401/health
ok
kill -TERM で止めると、SIGTERM の処理が動いて終了コード 0 で終わりました。
SIGTERM received, closing server
closed
Number(process.env.PORT) || 3000 の形にしておくと、手元では 3000 番、Railway では渡された番号で動きます。Node.js で環境変数を読む方法は、関連記事「Node.jsコマンドライン引数と環境変数|process.argv・env」で扱っています。
言語ごとの起動コマンド
ドキュメント「Application Failed to Respond」「No start command could be found」に載っている書き方です。
| 言語・フレームワーク | 起動コマンド・書き方 |
|---|---|
| Express | app.listen(port, "0.0.0.0")(port は PORT を数値にしたもの) |
| Next.js | next start -H 0.0.0.0 -p $PORT |
| Nuxt | node .output/server/index.mjs |
| FastAPI(Uvicorn) | uvicorn main:app --host 0.0.0.0 --port $PORT |
| Django(Gunicorn) | gunicorn myproject.wsgi |
| Rails | bundle exec rails server -b 0.0.0.0 -p $PORT |
| Vite のビルド結果 | serve --single --listen $PORT dist |
| Go(net/http) | http.ListenAndServe(":"+os.Getenv("PORT"), handler) |
Gunicorn は gunicorn -b 0.0.0.0:$PORT main:app のように、待ち受けのアドレスとポートを明示する書き方もできます。
PostgreSQLを追加してDATABASE_URLでつなぐ
この節では、DB をプロジェクトに足し、アプリへ接続文字列を渡す方法と、つながらないときの実際のエラーが分かります。
PostgreSQL を足す
キャンバスの + New か、コマンドメニュー(Ctrl/Cmd + K)から PostgreSQL を選びます。CLI なら railway add --database postgres です。
アプリのサービスに参照変数を作る
web サービスの Variables で DATABASE_URL を作り、値に ${{Postgres.DATABASE_URL}} と書きます。入力欄に候補が出ます。
変更をデプロイする
変数の追加は「ステージされた変更」になり、確認して Deploy すると反映されます。
PostgreSQL のサービスには PGHOST・PGPORT・PGUSER・PGPASSWORD・PGDATABASE・DATABASE_URL が入り、同じプロジェクトの他のサービスから参照できます。DB は既定で非公開で、同じプロジェクトのサービスだけがプライベートネットワーク(postgres.railway.internal のような名前)でつなげます。外から接続したいときは、DB の Settings → Networking で Public Access を足すと TCP Proxy ができ、DATABASE_PUBLIC_URL が作られます。TCP Proxy 経由の通信は外向きの通信量として課金されます。
手元のPostgreSQL 16につないだ結果
上の server.mjs に、手元の PostgreSQL 16.15 の接続文字列を渡して /db を呼びました。
$ DATABASE_URL=postgresql://s324user:****@127.0.0.1:5432/s324db PORT=32407 node server.mjs
$ curl http://127.0.0.1:32407/db
{"db":"s324db","version":"PostgreSQL 16.15"}
つながらない3つの場合も試しました。
| 状況 | 実際に出たもの |
|---|---|
DATABASE_URL が無い |
DATABASE_URL is not set(500) |
| パスワードが違う | db error: 28P01 password authentication failed for user "s324user" → 503 |
xxx.railway.internal を外から使った |
Error: getaddrinfo ENOTFOUND postgres.railway.internal |
try/catch を書かない版では、パスワード違いや ENOTFOUND で Node.js のプロセスが終了コード 1 で止まりました。 Railway では、プロセスが 0 以外で終わると、そのデプロイは Crashed になり、再起動ポリシー(既定は On Failure・最大10回)に従って起動し直されます。DB に届かないときもプロセスを落とさず、503 を返して待つ形にしておくと、DB の再起動中にアプリまで落ちません。
railway run で手元のコマンドに変数を渡すとき、DATABASE_URL は *.railway.internal を指しています。 プライベートネットワークは Railway の中でしか引けないので、手元からは上の表の3行目と同じ ENOTFOUND になります。手元から DB に入るときは、DATABASE_PUBLIC_URL を使うか railway connect(psql を開く)を使います。
PostgreSQL を土台にした別の PaaS(認証・行単位の権限つき)は、関連記事「Supabaseとは|使い方・料金・RLSとFirebaseとの違いを実例で」で扱っています。
Railwayの環境変数と参照変数
この節では、変数の種類と、Railway が自動で入れる変数、参照の書き方が分かります。
変数はビルド中にも実行中にも読めます。 railway run <コマンド> と railway shell でも同じ値が手元のコマンドに渡ります(「Variables」)。
| 書き方 | 意味 | 例 |
|---|---|---|
${{ shared.名前 }} |
プロジェクトの共有変数(環境ごと) | API_KEY=${{shared.API_KEY}} |
${{ サービス名.名前 }} |
別のサービスの変数 | DATABASE_URL=${{Postgres.DATABASE_URL}} |
${{ 名前 }} |
同じサービスの別の変数 | https://${{ BASE_URL }}/${{ AUTH_PATH }} |
${{ backend.RAILWAY_PUBLIC_DOMAIN }} |
他のサービスの公開ドメイン | API_URL=https://${{ backend.RAILWAY_PUBLIC_DOMAIN }} |
画面の RAW Editor には .env か JSON の形でまとめて貼れます。GitHub 連携のリポジトリのルートにある .env.example などは、取り込み候補として表示されます。
Railwayが自動で入れる変数
| 変数 | 中身 |
|---|---|
PORT |
アプリが待ち受けるポート(ヘルスチェックもこの値) |
RAILWAY_PUBLIC_DOMAIN |
公開ドメイン(例 example.up.railway.app) |
RAILWAY_PRIVATE_DOMAIN |
プライベートネットワークでの名前 |
RAILWAY_ENVIRONMENT_NAME |
環境の名前(production など) |
RAILWAY_SERVICE_NAME |
サービスの名前 |
RAILWAY_DEPLOYMENT_ID・RAILWAY_REPLICA_ID |
デプロイとレプリカの ID |
RAILWAY_REPLICA_REGION |
動いているリージョン(例 us-west2) |
RAILWAY_VOLUME_MOUNT_PATH |
ボリュームのマウント先(例 /data) |
RAILWAY_GIT_COMMIT_SHA・RAILWAY_GIT_BRANCH |
GitHub からのデプロイのときだけ |
自分で設定して動きを変える変数もあります。
| 変数 | 効果 |
|---|---|
RAILWAY_DOCKERFILE_PATH |
Dockerfile の場所を指定(既定は Dockerfile) |
RAILWAY_HEALTHCHECK_TIMEOUT_SEC |
ヘルスチェックの待ち時間(既定 300秒) |
RAILWAY_DEPLOYMENT_DRAINING_SECONDS |
SIGTERM から SIGKILL までの猶予(既定 0) |
RAILWAY_DEPLOYMENT_OVERLAP_SECONDS |
前のデプロイを残して重ねる秒数(既定 0) |
RAILWAY_RUN_UID |
メインのプロセスを動かす UID。0 で root |
NO_CACHE |
1 でビルドのキャッシュを使わない |
秘密の値はSeal(封印)できる
変数の三点メニューの Seal を選ぶと、値はビルドとデプロイには渡りますが、画面にも API にも二度と表示されません。封印は取り消せず、railway variables と railway run の出力にも出ません。PR 環境や複製した環境にはコピーされないので、そちらでは別に設定します。
ドメインとポート:Generate Domain・独自ドメイン
この節では、公開 URL の付け方と、独自ドメインで DNS に書く値が分かります。
サービスを作っただけでは公開 URL は付きません。 Settings → Networking → Public Networking の Generate Domain で *.up.railway.app のドメインが付きます。アプリが1つのポートだけで待っていれば、そのポートが自動でターゲットポートになり、複数あれば一覧から選びます。CLI では railway domain で同じことができ、--port でターゲットポートを指定できます。
独自ドメインは、Railway が示す2つのレコードを DNS に足します。
| レコード | 値の例 | 役割 |
|---|---|---|
| CNAME | g05ns7.up.railway.app |
通信を Railway に向ける |
| TXT | Railway が示す値 | ドメインの持ち主の確認 |
TXT が無いと、CNAME が引けても 404 になります。 反映には最大72時間かかることがあり、証明書(Let's Encrypt)はふつう1時間以内に発行されます。ルートドメイン(example.com)には CNAME フラット化か ALIAS に対応した DNS(Cloudflare など)が必要で、ドキュメントは AWS Route 53・Azure DNS・GoDaddy は対応していないと書いています。Cloudflare のプロキシ(オレンジの雲)を使うときは、SSL/TLS を Full にします(Full (Strict) は想定どおりに動かないとの注意があります)。
公開の HTTP には次の上限があります(「Specs & Limits」)。
| 項目 | 上限 |
|---|---|
| 1リクエストの最長 | 15分(データが流れ続けている場合) |
| データが流れない状態 | 5分で切断 |
| ヘッダーの合計 | 32KB |
| 同時接続 | 1サービス 10,000 |
| WebSocket | 時間の上限なし |
ボリューム:再デプロイしてもデータを残す
この節では、ファイルを保存するアプリで必要なボリュームの決まりが分かります。
コンテナの中に書いたファイルは、再デプロイで消えます。 SQLite のファイルやアップロードされた画像を残すなら、ボリュームを付けます。キャンバスを右クリックするかコマンドメニューから作り、サービスとマウント先を選びます。
- 1マウント先はアプリから見た絶対パスにしたアプリは /app に置かれる。./data に書くなら /app/data にマウントする
- 2ビルド中や pre-deploy で書いていないボリュームは起動時にだけマウントされる。ビルド中に書いたものは残らない
- 3root 以外で動くイメージなら RAILWAY_RUN_UID=0 を足したボリュームは root の持ち物としてマウントされるため
- 4レプリカを増やしていないボリュームは1サービスに1つで、レプリカとは一緒に使えない
- 5再デプロイで短い停止がある前提にした同じボリュームに2つのデプロイを同時にマウントできないため、ヘルスチェックがあっても一瞬止まる
容量は Free とトライアルが 0.5GB、Hobby が 5GB、Pro が 50GB から(自分で 1TB まで増やせる)です(「Volumes Reference」)。容量の2〜3%はファイルシステムの管理情報に使われます。中のファイルは railway volume browse / や railway volume files download で取り出せます。
railway CLIの使い方(インストール・--version・--help)
この節では、CLI の入れ方と、手元で表示したバージョンとコマンド一覧が分かります。
ドキュメントにあるインストール方法です。
npm i -g @railway/cli # macOS・Linux・Windows(Node.js 16 以上)
brew install railway # macOS
scoop install railway # Windows
bash <(curl -fsSL railway.com/install.sh) # シェルのスクリプト
npm で入れて版を表示しました。npm のパッケージのインストール時に、OS に合った CLI 本体(約21MB の実行ファイル)が入りました。
$ railway --version
railway 5.71.0
railway --help の出力(主なコマンドを抜き出し)です。
Usage: railway [COMMAND]
Commands:
add Add a service to your project
config Manage Railway configuration and IaC ownership
connect Connect to a database's shell (psql for Postgres, mongosh for MongoDB, etc.)
deploy Provisions a template into your project
domain Add, list, inspect, update, or delete domains for a service
environment Create, delete or link an environment [aliases: env]
init Create a new project [aliases: new]
link Associate existing project with current directory, may specify projectId as an argument
login Sign in to Railway — also creates a new account if you don't have one
logs View build, deploy, HTTP, network flow, or DNS logs
run Run a local command using variables from the active environment [aliases: local]
service Manage services
shell Open a local subshell with Railway variables available
ssh Connect to a service via SSH or manage SSH keys
status Show information about a Railway project
up Upload and deploy project from the current directory
usage Show workspace usage and manage usage limits
variable Manage environment variables for a service [aliases: variables, vars, var]
volume Manage project volumes [aliases: volumes]
redeploy Redeploy the latest deployment of a service
restart Restart the latest deployment of a service (without rebuilding)
railway docs は、ブラウザーが無い環境ではドキュメントの URL を表示しました。
$ railway docs
https://docs.railway.com
https://docs.railway.com/llms.txt
https://docs.railway.com/llms-full.txt
よく使うコマンドの早見表
| やりたいこと | コマンド |
|---|---|
| ログイン(SSH 先など) | railway login(--browserless) |
| 既存のプロジェクトとつなぐ | railway link |
| 今のフォルダをデプロイ | railway up(待たないなら --detach) |
| ビルドのログを見る | railway logs --build |
| エラーだけ見る | railway logs --lines 10 --filter "@level:error" |
| 変数を一覧・設定 | railway variable list / railway variable set KEY=value |
| 変数を付けて手元で実行 | railway run -- npm run migrate |
| DB を足す | railway add --database postgres |
| DB のシェルを開く | railway connect |
| 公開ドメインを作る | railway domain(独自なら railway domain example.com) |
| 環境を作る | railway environment new staging |
| コンテナに入る | railway ssh |
railway up --help には、未ログインで実行するとブラウザー(SSH 先ではデバイスコード)でのログインに進むと書かれています。CI から使うときは、プロジェクトのトークンを RAILWAY_TOKEN に入れて railway up を実行します。アカウント全体の操作には RAILWAY_API_TOKEN を使います。
CLI に含まれるメッセージのうち、よく見る2つです。
Unauthorized. Please login with `railway login`
No linked project found. Run railway link to connect to a project
前者はログインかトークンの問題、後者はフォルダとプロジェクトが結びついていないことを示します。
ビルドの仕組み:RailpackとDockerfile
この節では、Railway がコードからイメージを作る2つの方法と、どちらが使われるかが分かります。
Railpack(既定)
言語とフレームワークを見分け、依存の導入・ビルド・起動コマンドを決める
BuildKit を土台にしたビルダー
設定は環境変数か railpack.json
Dockerfile
ルートに Dockerfile(D は大文字)があれば自動で使う
ログに Using detected Dockerfile! と出る
OS のパッケージや手順を細かく決めたいとき
RailpackがNode.jsを見分ける順番
railpack.com の Node.js のページによると、ルートに package.json があれば Node.js として扱い、次の順で決めます(上にあるほど優先)。
| 決めるもの | 見る順番 |
|---|---|
| Node.js の版 | RAILPACK_NODE_VERSION → package.json の engines.node → .nvmrc → .node-version → mise.toml → 無ければ LTS |
| パッケージマネージャー | packageManager → ロックファイル(pnpm-lock.yaml・bun.lock・yarn.lock) → 無ければ npm |
| 起動コマンド | scripts.start → main → ルートの index.js・index.ts |
| ビルド | 依存を入れたあと、scripts.build があれば実行 |
この記事のサンプルは engines.node が 22.x、scripts.start が node server.mjs なので、Node.js 22 で npm を使い、npm start で起動される形になります。起動コマンドが見つからないと No start command could be found で止まります(よくあるエラーの節)。
Dockerfileを使う場合
サンプルのアプリなら、次の形の Dockerfile で動かせます。アプリ自身が PORT を読むので、CMD に $PORT を書く必要がありません。
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
# npm を挟まず node を直接起動する(SIGTERM がアプリに届く)
CMD ["node", "server.mjs"]
ドキュメント「Dockerfiles」の決まりです。
- ビルド中に変数を使うときは
ARGで宣言します。 宣言した段(ステージ)でだけ読めます。
ARG RAILWAY_SERVICE_NAME
RUN echo $RAILWAY_SERVICE_NAME
- 起動コマンドに変数を入れるときは、シェルを通します(例
/bin/sh -c "exec python main.py --port $PORT")。["python", "main.py"]のような exec 形式では変数が展開されません。 - 別の名前の Dockerfile は
RAILWAY_DOCKERFILE_PATH=Dockerfile.originで指定します。 - キャッシュのマウントは
--mount=type=cache,id=s/<サービスID>-<パス>,target=<パス>の形で、ID に環境変数は使えません。
イメージを小さく・安全に作る書き方は、関連記事「Dockerfileの書き方|軽く・速く・安全なイメージを作るベストプラクティス」で扱っています。
設定をコードで管理:railway.jsonからrailway.tsへ
この節では、設定ファイルの書き方が2026年に変わった点と、新しい railway.ts を手元で評価した結果が分かります。
railway.json・railway.toml(Config as Code)は非推奨になり、既存のサービスでも2026年12月1日に読まれなくなります。 ドキュメントは「hard cutoff」と書いています。新しい方法は .railway/railway.ts に書く Infrastructure as Code(IaC)で、TypeScript は一般提供、Python と Go はベータです。
railway config plan で差分を見て、railway config apply で反映する
これまでのrailway.json(2026年12月1日まで)
キーの名前は railway.ts の中でも同じものが使われているので、読めると移行が楽です。
{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "RAILPACK",
"buildCommand": "npm run build"
},
"deploy": {
"startCommand": "node server.mjs",
"healthcheckPath": "/health",
"healthcheckTimeout": 120,
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 5
}
}
| キー | 意味 |
|---|---|
build.builder |
RAILPACK(既定)か DOCKERFILE |
build.watchPatterns |
このパターンに当たる変更のときだけデプロイ(例 ["src/**"]) |
deploy.preDeployCommand |
起動の前に実行(例 ["npm run db:migrate"]) |
deploy.cronSchedule |
cron の形で定期実行(例 */15 * * * *) |
environments.staging |
環境ごとの上書き。pr は PR 環境 |
新しいrailway.ts
npm の railway(TypeScript SDK)3.16.0 を入れ、web サービスと PostgreSQL を書きました。
npm install railway
// .railway/railway.ts
import { defineRailway, project, service, postgres, github } from "railway/iac";
export default defineRailway(() => {
const db = postgres("Postgres");
const web = service("web", {
source: github("your-account/railway-demo", { branch: "main" }),
start: "node server.mjs",
healthcheck: "/health",
healthcheckTimeout: 120,
env: {
NODE_ENV: "production",
DATABASE_URL: db.env.DATABASE_URL, // ${{Postgres.DATABASE_URL}} と同じ参照
},
});
return project("railway-demo", { resources: [db, web] });
});
このファイルを Node.js で評価し、できた定義を表示しました(createRailwayContext と project は SDK の関数)。
{
"name": "railway-demo",
"resources": [
{
"address": "database.Postgres",
"type": "database",
"engine": "postgres",
"image": "ghcr.io/railwayapp-templates/postgres-ssl:18",
"output": "DATABASE_URL",
"defaultMountPath": "/var/lib/postgresql/data"
},
{
"address": "service.web",
"type": "service",
"kind": "github",
"source": { "type": "github", "repo": "your-account/railway-demo", "branch": "main" },
"deploy": {
"startCommand": "node server.mjs",
"healthcheckPath": "/health",
"healthcheckTimeout": 120
},
"variables": {
"NODE_ENV": { "type": "literal", "value": "production" },
"DATABASE_URL": { "type": "reference", "resource": "database.Postgres", "output": "DATABASE_URL" }
}
}
]
}
読み取れることは3つです(一部のキーを省きました)。
start・healthcheckは、railway.json と同じstartCommand・healthcheckPathに置き換えられた。db.env.DATABASE_URLは文字列ではなく「Postgres の DATABASE_URL への参照」として記録された。postgres()が使うイメージは、SDK 3.16.0 ではpostgres-ssl:18(PostgreSQL 18)、データの場所は/var/lib/postgresql/dataだった。
TypeScript なので、参照の書き間違いを型検査で見つけられます。 わざと誤りを入れたファイルを tsc(7.0.2、strict)にかけると、次のエラーになりました。
bad/railway.ts(10,5): error TS2322: Type 'string' is not assignable to type 'number'.
bad/railway.ts(13,28): error TS2551: Property 'DATABSE_URL' does not exist on type 'ServiceVariableRef<PostgresVariable>'. Did you mean 'DATABASE_URL'?
1行目は healthcheckTimeout: "120"(文字列)、2行目は db.env.DATABSE_URL(綴りの誤り)です。正しい版は型検査を通りました。
移行のコマンド
| コマンド | すること |
|---|---|
railway config init |
.railway/railway.ts を作る(つないだプロジェクトから取り込むこともできる) |
railway config pull |
今の Railway の設定をファイルに取り込む |
railway config migrate |
railway.json・railway.toml を railway.ts に翻訳する(既定は試すだけ。--apply で書く) |
railway config migrate cutover |
サービスを Config as Code から外し、IaC で管理できるようにする |
railway config plan |
変更の差分を表示するだけ(Railway は変えない) |
railway config apply |
確認のあと反映する(--yes で確認を省く) |
1つのサービスを Config as Code と IaC の両方で管理することはできません。railway.json のあるサービスは、plan で管理する前に移行が必要です(「Infrastructure as Code」)。
環境・PR環境・ロールバック・再起動ポリシー
この節では、本番を壊さずに試す仕組みと、壊れたときに戻す方法が分かります。
| 機能 | どうなるか | 設定する場所 |
|---|---|---|
| 環境の追加 | Duplicate(サービスと変数を複製)か Empty(空) | 上部の環境メニューの + New Environment |
| PR 環境 | PR を開くと一時的な環境ができ、マージ・クローズで消える | Project Settings → Environments |
| Bot の PR 環境 | Dependabot・Renovate の PR にも作る | 同じ画面の Enable Bot PR Environments |
| 環境の同期 | 別の環境のサービスを取り込む | キャンバスの Sync |
デプロイを戻す・やり直す
- ロールバック:Deployments で戻したいデプロイの三点メニューから選びます。イメージと変数がその時点に戻ります。戻せるのはプランの保持期間(Free 24時間・Hobby 72時間・Pro 120時間)の中のデプロイだけです。
- Redeploy:同じコードと設定で新しいデプロイを作ります。最新のコミットを出すなら、コマンドパレットの Deploy Latest Commit です。
- Restart:
Crashedのデプロイに出るボタンで、元のビルドのイメージのまま起動し直します(railway restartも同じ)。
再起動ポリシー
| ポリシー | 動き |
|---|---|
| On Failure(既定) | 0 以外の終了コードのときだけ再起動。既定は最大10回 |
| Always | 理由を問わず再起動(Free・トライアルでは使えない) |
| Never | 自動では再起動しない |
10回の再起動のあとも落ちると状態が Crashed になり、メンバーにメールと Webhook で通知されます。終了コード 0 で終わった場合は Success のままです。
npm startではSIGTERMがアプリに届かない
ドキュメント「Node.js SIGTERM handling」は、npm・Yarn・pnpm で起動するとパッケージマネージャーがメインのプロセスになり、SIGTERM がアプリに届かないと書いています。手元で、npm start の npm のプロセスに SIGTERM を送って確かめました。
$ PORT=32406 npm start
> railway-demo@1.0.0 start
> node server.mjs
listening on 0.0.0.0:32406
(npm の PID に kill -TERM)
npm の終了コード: 143
PID PPID CMD
17362 1 node server.mjs ← アプリは親を失って残った
npm はすぐに終わり、アプリの SIGTERM received は出ませんでした。 アプリには SIGTERM が届いていません。コンテナではメインのプロセスが終わるとアプリも止められるので、処理中のリクエストや DB の接続を片付けられません。node server.mjs で直接起動したときは、前の節のとおり SIGTERM received → closed と終わりました。起動コマンド(Custom Start Command)は node server.mjs のように直接書きます。片付けに時間がかかるなら、RAILWAY_DEPLOYMENT_DRAINING_SECONDS で SIGKILL までの猶予を延ばします。
よくあるエラーと直し方(ポート・ヘルスチェック・ビルド失敗)
この節では、Railway で出やすい失敗を、出た文言から原因と直し方まで引けます。
まず、どこで失敗しているかを分けます。
flowchart TD
A[デプロイ失敗・502] --> B{ビルドで失敗}
B -->|はい| C[ビルドログの<br>最初のエラー]
B -->|いいえ| D{ヘルスチェック}
D -->|失敗| E[PORT と<br>待ち受け先]
D -->|通る| F[Crashed の<br>ログ]
Application failed to respond(502)
Railway の入口(Edge Proxy)がアプリに届かないと、502 とこの画面になります。ドキュメントの挙げる原因は「0.0.0.0 と PORT で待っていない」「ドメインのターゲットポートが違う」「負荷が高すぎる」の3つです。前の2つを手元で再現しました。
■ 127.0.0.1 で待つ(HOST=127.0.0.1)
listening on 127.0.0.1:32402
$ curl http://127.0.0.1:32402/health
ok
$ curl http://192.0.2.2:32402/health
curl: (7) Failed to connect to 192.0.2.2 port 32402 after 0 ms: Couldn't connect to server
同じマシンの中(127.0.0.1)からは開けるのに、別のアドレスからは接続を拒否されました。 Railway の入口は別のアドレスから来るので、127.0.0.1 や localhost で待つと 502 になります。手元では動くのに Railway で動かない原因の代表です。0.0.0.0 で待つように直すと、同じ呼び出しが 200 になりました。
ヘルスチェックで失敗する(Healthcheck failed)
ヘルスチェックは、新しいデプロイを公開する前に、設定したパスに 2xx が返るまで呼び続けます。既定の待ち時間は300秒で、返らなければデプロイは失敗し、前のデプロイが動き続けます。公開した後は呼びません(監視ではない)。ドキュメントの条件をまねたスクリプトです。
# healthcheck.py:Railway のヘルスチェックと同じ条件で /health を確かめる
# 使い方:python3 healthcheck.py <host> <port> <path> <timeout秒>
import sys, time, http.client
host, port, path, timeout = sys.argv[1], int(sys.argv[2]), sys.argv[3], float(sys.argv[4])
start = time.monotonic()
n = 0
while time.monotonic() - start < timeout:
n += 1
t = time.monotonic() - start
try:
c = http.client.HTTPConnection(host, port, timeout=2)
c.request("GET", path, headers={"Host": "healthcheck.railway.app"})
r = c.getresponse()
print(f"[{t:4.1f}s] attempt {n}: status {r.status}")
if 200 <= r.status < 300:
print("Healthcheck succeeded")
sys.exit(0)
except OSError as e:
print(f"[{t:4.1f}s] attempt {n}: {type(e).__name__}: {e}")
time.sleep(1)
print(f"Healthcheck failed: no 2xx within {timeout:g}s")
sys.exit(1)
失敗する形を4つ作って試しました。
■ A) 127.0.0.1 で待つアプリ
[ 0.0s] attempt 1: ConnectionRefusedError: [Errno 111] Connection refused
[ 1.0s] attempt 2: ConnectionRefusedError: [Errno 111] Connection refused
[ 2.0s] attempt 3: ConnectionRefusedError: [Errno 111] Connection refused
Healthcheck failed: no 2xx within 3s
■ C) アプリは 32402、ターゲットポートは 32403
[ 0.0s] attempt 1: ConnectionRefusedError: [Errno 111] Connection refused
(同じ行が続く)
Healthcheck failed: no 2xx within 3s
■ E) 許可するホストに healthcheck.railway.app が無い
[ 0.0s] attempt 1: status 400
[ 1.0s] attempt 2: status 400
Healthcheck failed: no 2xx within 2s
■ G) 起動に5秒かかるアプリ・待ち時間3秒
[ 0.0s] attempt 1: ConnectionRefusedError: [Errno 111] Connection refused
[ 1.0s] attempt 2: ConnectionRefusedError: [Errno 111] Connection refused
[ 2.0s] attempt 3: ConnectionRefusedError: [Errno 111] Connection refused
Healthcheck failed: no 2xx within 3s
E は、許可したホスト名以外を 400 で断るアプリ(Django の ALLOWED_HOSTS などと同じ考え方)です。
// strict.mjs:許可したホスト名以外を 400 で断るアプリ
import http from "node:http";
const allowed = (process.env.ALLOWED_HOSTS ?? "").split(",");
const delay = Number(process.env.STARTUP_DELAY_MS ?? 0); // 起動に時間がかかるアプリの再現
const server = http.createServer((req, res) => {
const host = (req.headers.host ?? "").split(":")[0];
if (!allowed.includes(host)) { res.writeHead(400); return res.end("Bad Request: invalid host"); }
res.writeHead(200); res.end("ok");
});
setTimeout(() => server.listen(Number(process.env.PORT), "0.0.0.0",
() => console.log(`listening on ${process.env.PORT} (allowed: ${allowed})`)), delay);
直した後の結果です。
■ F) ALLOWED_HOSTS に healthcheck.railway.app を足した
[ 0.0s] attempt 1: status 200
Healthcheck succeeded
■ H) 起動に5秒かかるアプリ・待ち時間10秒
[ 0.0s] attempt 1: ConnectionRefusedError: [Errno 111] Connection refused
(中略:5秒まで同じ)
listening on 32405 (allowed: healthcheck.railway.app)
[ 6.0s] attempt 7: status 200
Healthcheck succeeded
もう1つ、ヘルスチェックはアプリ側の待ち受けではなく PORT の値を使います。 ターゲットポートを使ってアプリを別のポートで待たせているときは、そのポート番号を PORT 変数に設定しないと「service unavailable」で失敗します(「Healthchecks」)。
エラーの早見表
| 出た文言・症状 | 原因 | 直し方 |
|---|---|---|
Application failed to respond(502) |
127.0.0.1 で待っている・PORT を読んでいない |
0.0.0.0 と process.env.PORT で待つ |
同上(PORT は正しい) |
ドメインのターゲットポートが違う | Settings → Networking で番号を直す |
Healthcheck failed(service unavailable) |
アプリが PORT と違う番号で待っている |
PORT 変数を待ち受けの番号にする |
Healthcheck failed(status 400) |
許可ホストに healthcheck.railway.app が無い | 許可するホストに足す |
| 起動が遅くてヘルスチェックが切れる | 待ち時間が足りない | RAILWAY_HEALTHCHECK_TIMEOUT_SEC を延ばす |
No start command could be found |
scripts.start・main・index.js が無い |
Start Command を指定する(例 node server.mjs) |
password authentication failed・ENOTFOUND xxx.railway.internal |
参照変数の誤り、手元から内部名を使った | ${{Postgres.DATABASE_URL}} を使う。手元は DATABASE_PUBLIC_URL |
デプロイが Crashed |
プロセスが 0 以外で終わった | デプロイのログの最後の例外を見る |
| 再デプロイで処理中の要求が切れる | npm start で SIGTERM が届かない |
起動コマンドを node server.mjs にする |
| Dockerfile が使われない | ファイル名が dockerfile など |
Dockerfile(D は大文字)か RAILWAY_DOCKERFILE_PATH |
| 独自ドメインが 404 | TXT レコードが無い | CNAME と TXT の両方を足す |
ERR_TOO_MANY_REDIRECTS |
Cloudflare の SSL/TLS が Flexible | Full にする |
Unauthorized. Please login with … |
CLI が未ログイン・トークンの誤り | railway login か RAILWAY_TOKEN を確かめる |
No linked project found |
フォルダとプロジェクトが未接続 | railway link |
ビルドのログは railway logs --build、デプロイのログは railway logs --lines 100 で手元に出せます。ビルドのキャッシュが怪しいときは NO_CACHE=1 を設定してビルドし直します。
Render・Fly.io・Heroku・Vercel・Netlifyとの違い
この節では、よく比べられるサービスとの事実の違いと、選び方の目安が分かります。
まず、サーバーやコンテナを常に動かせるサービスどうしの比較です(各社の公式ページ、2026年10月22日時点)。
| 項目 | Railway | Render | Fly.io | Heroku |
|---|---|---|---|---|
| 料金の形 | プラン月額+利用額(秒単価) | ワークスペースのプラン+インスタンスの月額 | 使った分だけ(秒単位) | dyno ごとの月額 |
| 無料で使える範囲 | トライアル5ドル(30日)→ 月1ドル | Free の Web(512MB、15分無通信で停止、月750時間) | トライアル(2時間の稼働か7日) | 料金ページに無料枠の記載なし |
| いちばん小さい有料の目安 | Hobby 5ドル(5ドル分含む) | 512MB のインスタンス 月7ドル | shared-cpu-1x 256MB 月2.19ドル | Eco 5ドル(30分無通信で停止) |
| 無料のDB | Free の範囲内で動かせる | Free の Postgres は30日で期限切れ | 料金ページに無料枠の記載なし | Essential-0 が月5ドル |
| 永続ディスク | ボリューム 1GB 月0.15ドル | Free の Web には無い | ボリューム 1GB 月0.15ドル | なし(ファイルは消える) |
フロントエンドや関数を中心にするサービスとの比較です。
| 項目 | Railway | Cloud Run | Vercel | Netlify |
|---|---|---|---|---|
| 得意なもの | 常駐サーバー・DB・ワーカー | コンテナ(リクエスト課金) | Next.js・フロントエンド | 静的サイト・フォーム |
| 無料の範囲 | 月1ドル分 | 月 18万 vCPU秒・36万 GiB秒・200万リクエスト | Hobby(個人・非商用) | 月300クレジット |
| 処理時間の上限 | 1リクエスト最長15分 | 既定5分・最長60分 | 関数は Hobby 300秒・Pro 800秒 | 関数は60秒 |
| DB を同じ画面で | PostgreSQL・MySQL・Redis・MongoDB | 別サービス(Cloud SQL など) | 別サービスと連携 | 別サービスと連携 |
Railway の比較ページ(Heroku との比較)は、Railway は自社が運用するハードウェアで動き、プライベートネットワークは追加料金なし、Heroku は AWS 上で動き、プライベートネットワークは Enterprise の有料機能、と書いています。Railway のリージョンは、米国西部(カリフォルニア)・米国東部(バージニア)・欧州西部(アムステルダム)・東南アジア(シンガポール)の4つで、日本のリージョンはありません。
迷ったときの判断表
| 状況 | 選ぶものの目安 | 理由 |
|---|---|---|
| API と DB をまとめて手軽に動かしたい | Railway | 同じキャンバスで DB を足し、参照変数でつなげる |
| まずは無料でしばらく動かしたい | Render の Free | 月750時間の無料枠(15分で停止) |
| 世界の複数の地域の近くで動かしたい | Fly.io か Railway の複数リージョン | どちらもリージョンを選んで置ける |
| Next.js のフロントエンドが中心 | Vercel | Next.js の開発元のサービス |
| 静的サイトとフォームだけ | Netlify | フォーム受信が標準で付く |
| アクセスが無い時間はほぼ0円にしたい | Cloud Run か Railway の Serverless | アイドル時の課金を止められる |
| 国内のデータ保管が条件・固定IPが必須 | 要件を満たすクラウドを個別に確かめる | Railway に日本のリージョンは無い |
Netlify の料金・デプロイ方法・エラーは、関連記事「Netlifyとは|使い方・料金・デプロイ方法とエラー対処を実例で」で扱っています。フロントは Netlify、API と DB は Railway、のように分けて置く使い方もできます。
よくある質問
Q. Railwayとは何ですか? A. GitHub のリポジトリやローカルのフォルダから、Web アプリ・API・DB・ワーカーをデプロイできる PaaS です。ビルドは Railpack(または Dockerfile)が受け持ち、公開 URL と HTTPS も付きます。
Q. Railwayの読み方は? A. 「レイルウェイ」と読みます。サービスの URL は railway.com です。
Q. Railwayは無料で使えますか? A. 最初の30日は5ドル分のトライアル、その後は Free プランで毎月1ドル分まで使えます(2026年10月22日時点)。常に動かす API は1か月で1ドルを超えやすく、料金の節の試算では小さな API でも約1.95ドルでした。
Q. Hobbyプランの5ドルで何ができますか? A. 月5ドルの中に5ドル分の利用が含まれます。試算では、平均 0.02 vCPU・150MB の小さな API なら5ドルに収まり、DB を足すと6.81ドルでした。
Q. 日本リージョンはありますか?
A. ありません。リージョンは米国西部・米国東部・アムステルダム・シンガポールの4つで、日本から近いのはシンガポール(asia-southeast1-eqsg3a)です。
Q. Application failed to respond と出ます。
A. アプリが 127.0.0.1 や固定のポートで待っていることが多い原因です。0.0.0.0 と環境変数 PORT で待つように直し、ドメインのターゲットポートも確かめます。手元で再現した結果は「よくあるエラー」の節にあります。
Q. railway.json(railway.toml)はいつまで使えますか?
A. 2026年12月1日に読まれなくなります。railway config migrate で .railway/railway.ts に翻訳し、railway config migrate cutover で切り替えます。
Q. データベースのデータは消えますか? A. DB とボリュームのデータは再デプロイでは消えません。プランをやめた場合は、トライアル・Free は失効から30日後、Hobby は60日後、Pro は90日後にボリュームが削除されます。
Q. Herokuからの乗り換えで変わる点は? A. Heroku は dyno ごとの月額、Railway は実際の使用量の課金です。Railway はボリュームでファイルを残せ、1つのプロジェクトに複数のサービスと共有変数をまとめられます。
Q. PHP・Python・Java・Go のアプリも動きますか? A. 動きます。Railpack は Node・Python・Go・PHP・Java・Ruby・Deno・Rust・Elixir・静的ファイル・シェルスクリプトに対応しています。Dockerfile を置けば、それ以外の構成も動かせます。
Q. Dockerイメージをそのままデプロイできますか?
A. できます。画面からイメージを選ぶか、railway add --image nginx:latest --service web のように指定します。起動コマンドは Dockerfile の ENTRYPOINT・CMD が使われます。
Q. 停止すれば課金は止まりますか? A. デプロイを Remove すると、そのデプロイの利用は止まります。ボリュームは使っている容量の分だけ課金が続きます。Serverless を有効にすると、外向きの通信が5分ない状態でサービスが眠ります。
まとめ
- Railway は、コードと「
PORTで待つ」ことだけを用意すれば、ビルド・起動・HTTPS・公開 URL を受け持つ PaaS。DB・ワーカー・cron も同じプロジェクトに置ける。 - 料金は2026年10月22日時点で、トライアル5ドル(30日)→ Free 月1ドル、Hobby 月5ドル、Pro 月20ドル。1 vCPU 月20ドル・1GB 月10ドルの使った分の課金で、ビルドは課金されない。
- 始め方は New Project → GitHub repo → Deploy Now → Generate Domain。CLI なら
railway init→railway up。 - DB は
${{Postgres.DATABASE_URL}}の参照変数で渡す。*.railway.internalは Railway の中でしか引けない。 - 502 とヘルスチェックの失敗は、
127.0.0.1で待つ・ポート違い・許可ホスト・起動の遅さで再現できた。npm startでは SIGTERM がアプリに届かなかった。 - railway.json・railway.toml は2026年12月1日に読まれなくなる。
.railway/railway.tsに移すと、参照の綴りの誤りを型検査で見つけられる。
参考・出典
確認日はいずれも 2026年10月22日です。
- Railway「Pricing」:https://railway.com/pricing
- Railway Docs「Pricing」:https://docs.railway.com/pricing
- Railway Docs「Plans」:https://docs.railway.com/pricing/plans
- Railway Docs「Free Trial」:https://docs.railway.com/pricing/free-trial
- Railway Docs「Quick Start」:https://docs.railway.com/quick-start
- Railway Docs「CLI」:https://docs.railway.com/cli
- Railway Docs「Variables」:https://docs.railway.com/variables
- Railway Docs「Variables Reference」:https://docs.railway.com/variables/reference
- Railway Docs「Volumes」:https://docs.railway.com/volumes
- Railway Docs「Volumes Reference」:https://docs.railway.com/volumes/reference
- Railway Docs「Public Networking」:https://docs.railway.com/networking/public-networking
- Railway Docs「Working with Domains」:https://docs.railway.com/networking/domains/working-with-domains
- Railway Docs「Specs & Limits」:https://docs.railway.com/networking/public-networking/specs-and-limits
- Railway Docs「Private Networking」:https://docs.railway.com/networking/private-networking
- Railway Docs「How Private Networking Works」:https://docs.railway.com/networking/private-networking/how-it-works
- Railway Docs「PostgreSQL」:https://docs.railway.com/databases/postgresql
- Railway Docs「Healthchecks」:https://docs.railway.com/deployments/healthchecks
- Railway Docs「Application Failed to Respond」:https://docs.railway.com/networking/troubleshooting/application-failed-to-respond
- Railway Docs「No Start Command Could Be Found」:https://docs.railway.com/deployments/troubleshooting/no-start-command-could-be-found
- Railway Docs「Node.js SIGTERM handling」:https://docs.railway.com/deployments/troubleshooting/nodejs-sigterm-handling
- Railway Docs「Railpack」:https://docs.railway.com/builds/railpack
- Railway Docs「Build Configuration」:https://docs.railway.com/builds/build-configuration
- Railway Docs「Build and Start Commands」:https://docs.railway.com/builds/build-and-start-commands
- Railway Docs「Dockerfiles」:https://docs.railway.com/builds/dockerfiles
- Railway Docs「Config as Code」:https://docs.railway.com/reference/config-as-code
- Railway Docs「Infrastructure as Code」:https://docs.railway.com/infrastructure-as-code
- Railway Docs「Environments」:https://docs.railway.com/environments
- Railway Docs「Deployment Actions」:https://docs.railway.com/deployments/deployment-actions
- Railway Docs「Restart Policy」:https://docs.railway.com/deployments/restart-policy
- Railway Docs「Serverless」:https://docs.railway.com/deployments/serverless
- Railway Docs「Regions」:https://docs.railway.com/deployments/regions
- Railway Docs「Railway vs. Heroku」:https://docs.railway.com/maturity/compare-to-heroku
- Railpack「Node」:https://railpack.com/languages/node
- Railpack「Config File」:https://railpack.com/config/file
- npm「@railway/cli」:https://www.npmjs.com/package/@railway/cli
- npm「railway」:https://www.npmjs.com/package/railway
- Render「Pricing」:https://render.com/pricing
- Render Docs「Deploy for Free」:https://render.com/docs/free
- Fly.io Docs「Fly.io Resource Pricing」:https://docs.fly.io/about/pricing
- Heroku「Pricing」:https://www.heroku.com/pricing/
- Google Cloud「Cloud Run pricing」:https://cloud.google.com/run/pricing
- Vercel「Pricing」:https://vercel.com/pricing
- Vercel Docs「Vercel Functions Limits」:https://vercel.com/docs/functions/limitations
- Netlify「Pricing」:https://www.netlify.com/pricing/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Railwayとは|使い方・料金・デプロイ手順とエラー対処を実例で」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。