Skip to main content

アプリデプロイメント

優れた Shopify アプリの構築は戦いの半分に過ぎません -- 本番環境で確実にデプロイし運用することがもう半分です。このモジュールでは、ホスティングプラットフォームの選択、環境変数管理、GitHub Actions による CI/CD パイプラインのセットアップ、モニタリング、ロギング、エラートラッキングをカバーします。終了時には、すべてのリリースに自信を持てる本番グレードのデプロイメントパイプラインが得られます。

ホスティングオプション

Shopify アプリは HTTPS 経由で公開アクセス可能でなければならない Web アプリケーションです。最適なホスティングプラットフォームは、アプリのアーキテクチャ、トラフィックパターン、予算によって異なります。

プラットフォーム比較

プラットフォーム最適な用途開始コストコールドスタートデータベース
VercelRemix/Next.js apps, serverlessFree tierYes (serverless)External required
RailwayFull-stack apps, easy setup$5/monthNoBuilt-in PostgreSQL
RenderContainers, background workersFree tierYes (free tier)Built-in PostgreSQL
Fly.ioLow-latency global appsPay-as-you-goNoBuilt-in PostgreSQL
AWSEnterprise, full controlVariesDepends on serviceRDS, DynamoDB

Railway へのデプロイ

Railway は Shopify アプリに最適な選択肢です。長時間実行プロセス(Webhook やバックグラウンドジョブに必要)をサポートし、組み込みの PostgreSQL を備えています:

# Install Railway CLI
npm install -g @railway/cli

# Login and initialize
railway login
railway init

# Add PostgreSQL
railway add --plugin postgresql

# Deploy
railway up

Railway 用の Procfile を設定します:

web: npm run start
worker: npm run worker

Fly.io へのデプロイ

Fly.io は低レイテンシのグローバル分散デプロイが必要な場合に最適です:

# fly.toml
app = "your-shopify-app"
primary_region = "iad"

[build]
builder = "heroku/buildpacks:20"

[env]
NODE_ENV = "production"
PORT = "8080"

[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 1

[[services]]
protocol = "tcp"
internal_port = 8080

[[services.ports]]
port = 80
handlers = ["http"]

[[services.ports]]
port = 443
handlers = ["tls", "http"]

[services.concurrency]
type = "connections"
hard_limit = 250
soft_limit = 200

[[services.http_checks]]
interval = 10000
grace_period = "5s"
method = "get"
path = "/health"
protocol = "http"
timeout = 2000
# Deploy to Fly.io
fly launch
fly deploy

# Scale to multiple regions
fly regions add lhr sin
fly scale count 2

Vercel へのデプロイ

Remix ベースの Shopify アプリの場合、Vercel はゼロコンフィグのデプロイを提供します:

// vercel.json
{
"framework": "remix",
"buildCommand": "npm run build",
"installCommand": "npm install",
"regions": ["iad1", "lhr1"],
"functions": {
"api/**/*.js": {
"maxDuration": 30
}
},
"headers": [
{
"source": "/webhooks/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "no-store" }
]
}
]
}
warning

Vercel のサーバーレス関数には最大実行時間があります(Pro で 30 秒、Enterprise で 300 秒)。アプリが長時間実行の Webhook やバルクオペレーションを処理する場合は、Railway や Fly.io のような永続プロセスをサポートするプラットフォームを使用するか、重い処理を別のワーカーサービスにオフロードしてください。

環境変数

必須環境変数

すべての Shopify アプリは本番環境でこれらの環境変数を設定する必要があります:

# .env.example (never commit actual .env files)

# Shopify App Credentials
SHOPIFY_API_KEY=your_api_key
SHOPIFY_API_SECRET=your_api_secret
SCOPES=read_products,write_products,read_orders

# App Configuration
HOST=https://your-app.fly.dev
PORT=8080
NODE_ENV=production

# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname

# Session Storage
REDIS_URL=redis://default:pass@host:6379

# Encryption (for access token storage)
ENCRYPTION_KEY=generate-a-32-byte-hex-string

# Error Tracking
SENTRY_DSN=https://key@sentry.io/project-id

# Logging
LOG_LEVEL=info
danger

.env ファイルをバージョン管理にコミットしないでください。.env*.gitignore に追加してください。ホスティングプラットフォームのシークレット管理(Railway variables、Fly.io secrets、Vercel environment variables)を使用して、ランタイム時にこれらを注入してください。

安全な暗号化キーの生成

# Generate a 32-byte encryption key for AES-256
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

プラットフォーム固有のシークレット管理

# Fly.io
fly secrets set SHOPIFY_API_KEY=xxx SHOPIFY_API_SECRET=yyy

# Railway (via dashboard or CLI)
railway variables set SHOPIFY_API_KEY=xxx

# Vercel
vercel env add SHOPIFY_API_KEY production

GitHub Actions による CI/CD

適切な CI/CD パイプラインにより、すべてのデプロイがテスト、ビルド、一貫してデプロイされることが保証されます。

完全な GitHub Actions ワークフロー

# .github/workflows/deploy.yml
name: Test, Build, and Deploy

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
NODE_VERSION: '20'

jobs:
lint-and-typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run typecheck

unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run test -- --coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info

integration-tests:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: shopify_app_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- name: Run migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://test:test@localhost:5432/shopify_app_test
- name: Run integration tests
run: npm run test:integration
env:
DATABASE_URL: postgresql://test:test@localhost:5432/shopify_app_test
SHOPIFY_API_KEY: ${{ secrets.TEST_SHOPIFY_API_KEY }}
SHOPIFY_API_SECRET: ${{ secrets.TEST_SHOPIFY_API_SECRET }}

security-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm audit --audit-level=high
- name: Check for secrets in code
uses: trufflesecurity/trufflehog@main
with:
extra_args: --only-verified

deploy-staging:
needs: [lint-and-typecheck, unit-tests, security-audit]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --app your-app-staging
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
- name: Run smoke tests against staging
run: |
npm run test:smoke -- --base-url=https://your-app-staging.fly.dev

deploy-production:
needs: [deploy-staging]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://your-app.fly.dev
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --app your-app-production --strategy canary
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
- name: Verify deployment health
run: |
for i in 1 2 3 4 5; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://your-app.fly.dev/health)
if [ "$STATUS" = "200" ]; then
echo "Health check passed"
exit 0
fi
sleep 10
done
echo "Health check failed"
exit 1

Shopify CLI エクステンションデプロイ

アプリにエクステンション(Theme App Extension、Checkout UI Extension など)が含まれている場合は、別のデプロイステップを追加します:

  deploy-extensions:
needs: [deploy-production]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- name: Deploy Shopify extensions
run: npx shopify app deploy --force
env:
SHOPIFY_API_KEY: ${{ secrets.SHOPIFY_API_KEY }}
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
tip

本番デプロイには、必須レビュアー付きの GitHub Actions environments を使用してください。これにより、コードが本番に到達する前に手動承認ゲートが追加され、チームがステージングテスト結果をレビューする機会が得られます。

モニタリングとログ

ヘルスチェックエンドポイント

すべての本番アプリにはヘルスチェックエンドポイントが必要です:

// routes/health.js
export async function loader() {
const checks = {};

// Database connectivity
try {
await prisma.$queryRaw`SELECT 1`;
checks.database = 'healthy';
} catch (error) {
checks.database = 'unhealthy';
}

// Redis connectivity
try {
await redis.ping();
checks.redis = 'healthy';
} catch (error) {
checks.redis = 'unhealthy';
}

const allHealthy = Object.values(checks).every((v) => v === 'healthy');

return new Response(JSON.stringify({
status: allHealthy ? 'healthy' : 'degraded',
checks,
timestamp: new Date().toISOString(),
version: process.env.COMMIT_SHA || 'unknown',
}), {
status: allHealthy ? 200 : 503,
headers: { 'Content-Type': 'application/json' },
});
}

構造化ログ

// utils/logger.js
import pino from 'pino';

export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
transport:
process.env.NODE_ENV === 'development'
? { target: 'pino-pretty' }
: undefined,
base: {
app: 'shopify-app',
env: process.env.NODE_ENV,
version: process.env.COMMIT_SHA,
},
});

// Usage
logger.info({ shop: 'example.myshopify.com', event: 'install' }, 'App installed');
logger.error({ err, shop, webhookTopic }, 'Webhook processing failed');

エラートラッキング

Sentry 統合

// utils/sentry.js
import * as Sentry from '@sentry/node';

Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
release: process.env.COMMIT_SHA,
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.2 : 1.0,
integrations: [
Sentry.prismaIntegration(),
Sentry.httpIntegration(),
],
beforeSend(event) {
// Scrub sensitive data
if (event.request?.headers) {
delete event.request.headers['x-shopify-access-token'];
delete event.request.headers['authorization'];
}
return event;
},
});

export { Sentry };

セッションリプレイ用 LogRocket

アプリの管理 UI でマーチャントから報告された問題をデバッグするには:

// app/entry.client.jsx
import LogRocket from 'logrocket';

if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {
LogRocket.init('your-org/your-app');

// Identify the merchant
const shop = new URLSearchParams(window.location.search).get('shop');
if (shop) {
LogRocket.identify(shop, { shop });
}
}
info

LogRocket はユーザーセッションを記録するため、マーチャントがバグを報告した際に体験した内容を正確にリプレイできます。再現が難しい問題のデバッグに非常に有用です。プライバシーに注意し、決済情報や顧客 PII などの機密フィールドを編集するように LogRocket を設定してください。

デプロイチェックリスト

項目ステータスメモ
HTTPS の強制必須上記のすべてのプラットフォームがこれを強制します
ヘルスチェックエンドポイント必須ホスティングプラットフォームと稼働時間監視で使用
環境変数の保護必須コードには入れず、常にプラットフォームのシークレットに保存
データベースマイグレーションの自動化必須デプロイ前に CI で実行
エラートラッキングの設定強く推奨Sentry、Bugsnag、または同等のツール
構造化ログ強く推奨検索性のために JSON 形式
CI/CD パイプライン強く推奨テストとデプロイの自動化
ステージング環境推奨本番前にテスト
カナリアデプロイ推奨リスク軽減のための段階的ロールアウト
稼働時間監視推奨外部監視(Uptime Robot、Better Stack)

堅実なデプロイメントパイプラインは信頼性の高い Shopify アプリの基盤です。初日から適切にセットアップする時間を投資すれば、本番環境の問題と戦う時間が大幅に減り、マーチャントが喜ぶ機能を構築する時間が大幅に増えます。