<CodeLearn/>
インフラ レッスン5

インフラ総合演習

本番環境を構築しよう - Linux、Nginx、Docker、監視の実践

演習の概要

この演習では、これまでに学んだ知識を総合して、本番環境に近いインフラ構成を構築します。 Linuxサーバーの初期設定からNginxリバースプロキシ、Docker Composeでのアプリケーション運用、 基本的なモニタリングまでを段階的に実装します。

構築する環境

  • Ubuntu Linux サーバー
  • Nginx リバースプロキシ(SSL対応)
  • Docker Compose でアプリ+DB
  • 基本的なログ監視とヘルスチェック

学習のゴール

  • サーバーのセキュリティ初期設定ができる
  • NginxでHTTPS通信を構成できる
  • Docker Composeで複数サービスを管理できる
  • ログ監視と自動再起動を設定できる

ステップ1: Linuxサーバーの初期設定

新しいサーバーを立てたら、まずセキュリティとユーザーの初期設定を行います。 rootユーザーでの直接ログインを禁止し、SSH鍵認証のみ許可します。

# 1. システムを最新に更新
$ sudo apt update && sudo apt upgrade -y

# 2. 作業用ユーザーを作成
$ sudo adduser deploy
$ sudo usermod -aG sudo deploy

# 3. SSH鍵を設定(ローカルマシンで実行)
$ ssh-keygen -t ed25519 -C "deploy@myserver"
$ ssh-copy-id deploy@your-server-ip

# 4. SSH設定を強化 (/etc/ssh/sshd_config)
$ sudo vi /etc/ssh/sshd_config
# /etc/ssh/sshd_config の変更箇所

# rootでのSSHログインを禁止
PermitRootLogin no

# パスワード認証を無効化(鍵認証のみ)
PasswordAuthentication no

# SSHポートを変更(オプション)
Port 2222
# 5. ファイアウォール設定(UFW)
$ sudo ufw allow 2222/tcp    # SSH(ポート変更した場合)
$ sudo ufw allow 80/tcp      # HTTP
$ sudo ufw allow 443/tcp     # HTTPS
$ sudo ufw enable
$ sudo ufw status

Status: active

To                         Action      From
--                         ------      ----
2222/tcp                   ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere

# 6. SSHサービスを再起動
$ sudo systemctl restart sshd

ステップ2: Nginxリバースプロキシの構成

Nginxをリバースプロキシとして設定し、バックエンドのDockerコンテナにリクエストを転送します。 SSL証明書も設定してHTTPS化します。

# Nginxのインストール
$ sudo apt install nginx -y
$ sudo systemctl enable nginx

# SSL証明書の取得
$ sudo apt install certbot python3-certbot-nginx -y
$ sudo certbot --nginx -d myapp.example.com
# /etc/nginx/sites-available/myapp.conf

# HTTPはHTTPSにリダイレクト
server {
    listen 80;
    server_name myapp.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.example.com;

    # SSL証明書(Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/myapp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.example.com/privkey.pem;

    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # アクセスログ・エラーログ
    access_log /var/log/nginx/myapp.access.log;
    error_log /var/log/nginx/myapp.error.log;

    # アプリケーション(Docker コンテナ)へリバースプロキシ
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 静的ファイルは直接Nginxから配信
    location /_next/static/ {
        alias /var/www/myapp/.next/static/;
        expires 365d;
        add_header Cache-Control "public, immutable";
    }

    # ヘルスチェックエンドポイント
    location /health {
        proxy_pass http://127.0.0.1:3000/api/health;
        access_log off;
    }
}

# 設定を有効化
$ sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
$ sudo nginx -t && sudo systemctl reload nginx

ステップ3: Docker Composeでアプリケーション運用

Docker Composeを使って、アプリケーションとデータベースを一括管理します。 環境変数の管理、ボリュームの永続化、ネットワーク分離を行います。

# docker-compose.yml

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: myapp
    restart: always
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://appuser:secretpass@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:16-alpine
    container_name: myapp-db
    restart: always
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: secretpass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "127.0.0.1:5432:5432"    # ローカルからのみアクセス
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

networks:
  app-network:
    driver: bridge
# Dockerfile(Next.jsアプリの例)

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]

# デプロイコマンド
$ docker compose build
$ docker compose up -d
$ docker compose ps
$ docker compose logs -f app

ステップ4: 基本的なモニタリング

本番環境では、アプリケーションの稼働状況を監視し、問題があれば素早く検知する仕組みが必要です。 ログ監視、ヘルスチェック、ディスク使用量チェックの基本を設定します。

# ヘルスチェックスクリプト
# /opt/scripts/health-check.sh

#!/bin/bash
HEALTH_URL="http://localhost:3000/api/health"
LOG_FILE="/var/log/health-check.log"

response=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)

if [ "$response" != "200" ]; then
    echo "$(date): ALERT - Health check failed (HTTP $response)" >> $LOG_FILE
    # Docker Compose で再起動
    cd /opt/myapp && docker compose restart app
    echo "$(date): App restarted" >> $LOG_FILE
else
    echo "$(date): OK" >> $LOG_FILE
fi
# crontabでヘルスチェックを定期実行
$ crontab -e

# 5分おきにヘルスチェック
*/5 * * * * /opt/scripts/health-check.sh

# 毎日ログをローテーション
0 0 * * * find /var/log -name "*.log" -mtime +30 -delete

# SSL証明書の自動更新(月2回)
0 3 1,15 * * certbot renew --quiet --post-hook "systemctl reload nginx"
# ディスク使用量チェックスクリプト
# /opt/scripts/disk-check.sh

#!/bin/bash
THRESHOLD=80
USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')

if [ "$USAGE" -gt "$THRESHOLD" ]; then
    echo "$(date): WARNING - Disk usage is $USAGE%"
    # Docker の不要イメージを削除
    docker system prune -f
fi

# リソース確認コマンド
$ df -h                     # ディスク使用量
$ free -h                   # メモリ使用量
$ docker stats              # コンテナのリソース使用量
$ docker system df          # Dockerのディスク使用量
$ journalctl -u nginx -f    # Nginxのsystemdログ

本番運用チェックリスト

本番環境を運用する前に、以下の項目を確認しましょう。

セキュリティ

  • SSH鍵認証のみ、パスワード認証は無効
  • ファイアウォール(UFW)で必要なポートのみ開放
  • HTTPS(SSL/TLS)を有効化
  • セキュリティヘッダーを設定
  • 定期的なOSアップデート

可用性

  • Docker restart: always で自動再起動
  • ヘルスチェックの定期実行
  • ログローテーションでディスク枯渇を防止
  • データベースのバックアップ設定

運用

  • デプロイ手順のドキュメント化
  • ロールバック手順の確認
  • 監視アラートの通知先設定
  • 障害時の対応フローを決めておく

まとめ

  • サーバーの初期設定ではSSH鍵認証とファイアウォールが最重要
  • NginxリバースプロキシでHTTPS化し、セキュリティヘッダーを設定する
  • Docker Composeでアプリケーションとデータベースを一括管理する
  • ヘルスチェックとcronで基本的な監視と自動復旧を実現する
  • 本番運用前にセキュリティ・可用性・運用のチェックリストを確認する
  • インフラの知識はアプリ開発者にとっても不可欠なスキル