Railway.appでアプリを簡単デプロイ - モダンなPaaS完全ガイド
Railway.appでアプリを簡単デプロイ
Railway.appは、開発者にとって最もシンプルで強力なPlatform as a Service(PaaS)の一つです。GitHubリポジトリと連携するだけで、Node.js、Python、Go、Rustなど様々な言語のアプリケーションを数分でデプロイできます。
この記事では、Railwayの基本的な使い方から、データベース設定、環境変数管理、本番運用まで、実践的なデプロイ方法を詳しく解説します。
Railwayの特徴
1. ゼロコンフィグデプロイ
Dockerfileやビルド設定なしで、自動的にアプリケーションを検出してデプロイします。
2. GitHubとの統合
プッシュするだけで自動デプロイ。プルリクエストごとにプレビュー環境も作成されます。
3. 豊富なデータベーステンプレート
PostgreSQL、MySQL、MongoDB、Redisなどを数クリックで追加できます。
4. 開発者フレンドリーな料金
毎月$5分の無料枠があり、個人プロジェクトなら十分です。
アカウント作成とプロジェクトセットアップ
1. Railwayにサインアップ
# Railway CLIをインストール(オプション)
npm install -g @railway/cli
# または
brew install railway
- Railway.appにアクセス
- “Start a New Project”をクリック
- GitHubアカウントで認証
2. プロジェクト作成
Railway上で新規プロジェクトを作成する方法は3つあります:
- GitHubリポジトリから(推奨)
- テンプレートから
- 空のプロジェクトから
Next.jsアプリのデプロイ
プロジェクトの準備
# Next.jsプロジェクト作成
npx create-next-app@latest my-railway-app
cd my-railway-app
# GitHubリポジトリにプッシュ
git init
git add .
git commit -m "Initial commit"
gh repo create my-railway-app --public --source=. --remote=origin
git push -u origin main
package.jsonの設定
{
"name": "my-railway-app",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"engines": {
"node": ">=18.0.0"
}
}
Railwayでのデプロイ
- Railway ダッシュボードで “New Project”
- “Deploy from GitHub repo”を選択
- リポジトリを選択
- 自動的にビルドとデプロイが開始される
環境変数の設定
# Railway CLIから設定
railway variables set NODE_ENV=production
railway variables set DATABASE_URL=postgresql://...
# または、ダッシュボードから設定
# Project → Variables
Express.js APIのデプロイ
プロジェクト構成
// src/index.js
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.json({ message: 'Hello from Railway!' });
});
app.get('/api/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
});
});
app.listen(port, '0.0.0.0', () => {
console.log(`Server running on port ${port}`);
});
package.json
{
"name": "express-railway-api",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1"
},
"devDependencies": {
"nodemon": "^3.0.1"
},
"engines": {
"node": ">=18.0.0"
}
}
Procfileの作成(オプション)
web: node src/index.js
データベースの追加
PostgreSQLの追加
- Railwayダッシュボードで “New”
- “Database” → “Add PostgreSQL”
- 自動的に環境変数が設定される
データベース接続
// src/db.js
import pg from 'pg';
const { Pool } = pg;
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? {
rejectUnauthorized: false
} : false,
});
export async function query(text, params) {
const start = Date.now();
const res = await pool.query(text, params);
const duration = Date.now() - start;
console.log('Executed query', { text, duration, rows: res.rowCount });
return res;
}
export default pool;
マイグレーションの実行
// scripts/migrate.js
import pool from '../src/db.js';
async function migrate() {
try {
await pool.query(`
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS posts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
title VARCHAR(255) NOT NULL,
content TEXT,
published BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`);
console.log('Migration completed successfully');
} catch (error) {
console.error('Migration failed:', error);
throw error;
} finally {
await pool.end();
}
}
migrate();
package.jsonにスクリプト追加:
{
"scripts": {
"migrate": "node scripts/migrate.js",
"build": "npm run migrate"
}
}
Prismaの使用
npm install @prisma/client
npm install -D prisma
npx prisma init
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
posts Post[]
createdAt DateTime @default(now()) @map("created_at")
@@map("users")
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
@@map("posts")
}
{
"scripts": {
"build": "prisma generate && prisma migrate deploy"
}
}
Redisの追加
Redis接続設定
// src/cache.js
import { createClient } from 'redis';
const client = createClient({
url: process.env.REDIS_URL,
});
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
export async function get(key) {
return await client.get(key);
}
export async function set(key, value, expireSeconds = 3600) {
return await client.setEx(key, expireSeconds, value);
}
export async function del(key) {
return await client.del(key);
}
export default client;
キャッシュの使用例
import express from 'express';
import { get, set } from './cache.js';
import pool from './db.js';
const app = express();
app.get('/api/users/:id', async (req, res) => {
const { id } = req.params;
const cacheKey = `user:${id}`;
// キャッシュチェック
const cached = await get(cacheKey);
if (cached) {
return res.json(JSON.parse(cached));
}
// データベースから取得
const result = await pool.query(
'SELECT * FROM users WHERE id = $1',
[id]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'User not found' });
}
const user = result.rows[0];
// キャッシュに保存(1時間)
await set(cacheKey, JSON.stringify(user), 3600);
res.json(user);
});
環境変数の管理
環境別の設定
// config/index.js
export const config = {
port: process.env.PORT || 3000,
nodeEnv: process.env.NODE_ENV || 'development',
database: {
url: process.env.DATABASE_URL,
},
redis: {
url: process.env.REDIS_URL,
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: '7d',
},
cors: {
origin: process.env.CORS_ORIGIN || '*',
},
};
.env.exampleの作成
# .env.example
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key
CORS_ORIGIN=http://localhost:3000
Railwayでの環境変数設定
# Railway CLIで一括設定
railway variables set NODE_ENV=production
railway variables set JWT_SECRET=$(openssl rand -hex 32)
railway variables set CORS_ORIGIN=https://yourdomain.com
# または .env ファイルから読み込み
railway variables set < .env.production
カスタムドメインの設定
ドメインの追加
- Railway ダッシュボードで Settings
- “Domains” セクション
- “Custom Domain” を追加
DNS設定
# Aレコード
@ A 76.76.21.21
# CNAMEレコード
www CNAME your-app.up.railway.app
SSL証明書
Railwayは自動的にLet’s EncryptのSSL証明書を発行します。設定不要です。
モニタリングとログ
ログの確認
# Railway CLIでログ表示
railway logs
# リアルタイムログ
railway logs --follow
メトリクスの監視
ダッシュボードで以下を確認できます:
- CPU使用率
- メモリ使用率
- ネットワーク転送量
- リクエスト数
ヘルスチェックエンドポイント
app.get('/health', async (req, res) => {
try {
// データベース接続確認
await pool.query('SELECT 1');
// Redis接続確認
await client.ping();
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
});
} catch (error) {
res.status(503).json({
status: 'unhealthy',
error: error.message,
});
}
});
CI/CDの設定
GitHub Actionsとの連携
# .github/workflows/test.yml
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
自動デプロイ
Railwayは自動的にmainブランチへのプッシュをデプロイします。プルリクエストごとにプレビュー環境も作成されます。
パフォーマンス最適化
ビルド最適化
{
"scripts": {
"build": "npm run migrate && npm prune --production"
}
}
Node.jsの最適化
// 本番環境での最適化
if (process.env.NODE_ENV === 'production') {
app.enable('trust proxy');
app.use(compression());
// セキュリティヘッダー
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
next();
});
}
データベース接続プール
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // 最大接続数
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
トラブルシューティング
よくある問題
1. ポートバインディングエラー
// ❌ 間違い
app.listen(3000);
// ✅ 正しい
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0');
2. データベース接続エラー
// SSL設定が必要
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
});
3. ビルド失敗
{
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
}
}
料金とスケーリング
無料枠
- 月$5分の無料使用量
- 500時間の実行時間
- 無料のPostgreSQL/MySQL/Redis
有料プラン
- Hobby: $5/月から
- Pro: $20/月から
- 自動スケーリング
- 優先サポート
まとめ
Railway.appは、モダンなWebアプリケーションを簡単にデプロイできる強力なPaaSプラットフォームです。
主な利点:
- ゼロコンフィグデプロイ
- GitHubとのシームレスな統合
- 豊富なデータベーステンプレート
- 自動SSL証明書
- 開発者フレンドリーな料金
適用シーン:
- 個人プロジェクト
- スタートアップのMVP
- API開発
- マイクロサービス
- サイドプロジェクト
Railwayを使えば、インフラ管理に時間を取られることなく、アプリケーション開発に集中できます。