GCEでブログを構築した話


ブログを作るにあたって、せっかくなのでインフラもコードで管理したいと思い、TerraformとGCEを使って構築しました。この記事ではどんな構成にしたか、実際のコードを交えて紹介します。

構成概要

項目内容
インフラ管理Terraform
クラウドGoogle Cloud Platform
サーバーGCE(e2-micro)
OSDebian 12
リージョンasia-northeast1(東京)
WebサーバーNginx
フロントエンドAstro v6(静的サイト生成)
パッケージマネージャpnpm

GCEのe2-microは無料枠の対象なので、コストをほぼゼロに抑えられます。

Terraformの構成

Terraformのファイル構成はシンプルにしています。

terraform/
├── main.tf       # リソース定義
├── variables.tf  # 変数定義
└── outputs.tf    # 出力値

ネットワーク

専用VPCとサブネットを作成しています。デフォルトVPCは使わない方針です。

resource "google_compute_network" "blog_vpc" {
  name                    = "blog-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "blog_subnet" {
  name          = "blog-subnet"
  ip_cidr_range = "10.0.1.0/24"
  region        = var.region
  network       = google_compute_network.blog_vpc.id
}

ファイアウォール

SSHはIAP(Identity-Aware Proxy)経由のみ許可しています。外部から22番ポートを直接開けないので、セキュリティ的に安心です。

# SSHはIAPのIPレンジのみ許可
resource "google_compute_firewall" "allow_ssh" {
  name    = "blog-allow-ssh"
  network = google_compute_network.blog_vpc.name

  allow {
    protocol = "tcp"
    ports    = ["22"]
  }

  source_ranges = ["35.235.240.0/20"]
  target_tags   = ["blog-server"]
}

# HTTP/HTTPSは全公開
resource "google_compute_firewall" "allow_http" {
  name    = "blog-allow-http"
  network = google_compute_network.blog_vpc.name

  allow {
    protocol = "tcp"
    ports    = ["80", "443"]
  }

  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["blog-server"]
}

GCEインスタンス

インスタンスのOSはDebian 12を選択しました。スタートアップスクリプトでNginxのインストールと設定、Let’s Encryptの証明書取得まで自動で行います。

resource "google_compute_instance" "blog" {
  name         = "blog-server"
  machine_type = "e2-micro"
  zone         = var.zone
  tags         = ["blog-server"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
      size  = 20
    }
  }

  network_interface {
    network    = google_compute_network.blog_vpc.name
    subnetwork = google_compute_subnetwork.blog_subnet.name
    access_config {
      nat_ip = google_compute_address.blog_ip.address
    }
  }

  metadata = {
    enable-oslogin = "TRUE"
  }
}

enable-oslogin = "TRUE" を設定することで、OS Loginが有効になります。SSHの公開鍵管理をGCPのIAMに任せられるので、鍵ファイルを手で管理しなくて済みます。

スタートアップスクリプト

metadata_startup_script に起動時の初期設定を書いています。Nginxのインストール、設定ファイルの配置、certbotによるHTTPS化まで一気に終わります。

apt-get update
apt-get install -y nginx certbot python3-certbot-nginx

mkdir -p /var/www/blog
chown -R www-data:www-data /var/www/blog

# Nginx設定を配置
cat > /etc/nginx/sites-available/blog <<'NGINX'
server {
    listen 80;
    server_name nagiho.xyz;

    root /var/www/blog;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静的ファイルのキャッシュ設定
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    gzip on;
    gzip_types text/plain text/css application/javascript application/json image/svg+xml;
}
NGINX

ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/blog
rm -f /etc/nginx/sites-enabled/default
systemctl enable nginx && systemctl restart nginx

# Let's Encryptで証明書取得+HTTPSリダイレクト設定
certbot --nginx -d nagiho.xyz --non-interactive --agree-tos \
  --email your@email.com --redirect

terraform apply 一発でサーバーが立ち上がり、NginxとHTTPS設定まで完了します。

フロントエンド(Astro)

ブログ本体はAstroで作っています。pnpm build でHTMLを静的生成し、生成したファイルをGCEに転送するだけで公開できます。

# ビルド
pnpm build

# GCEに転送(IAP経由)
gcloud compute scp --recurse dist/* blog-server:/var/www/blog/ \
  --zone=asia-northeast1-a \
  --project=YOUR_PROJECT_ID \
  --tunnel-through-iap

静的ファイルをNginxで配信するだけなので、構成がシンプルで把握しやすいです。

まとめ

TerraformとGCEを使うことで、インフラの構成をコードとして管理できるようになりました。terraform apply で再現可能な状態にしておくと、万が一サーバーが壊れてもすぐに作り直せるので安心感があります。

Astroによる静的サイト生成と組み合わせることで、シンプルかつ低コストなブログ環境ができました。