0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GhostをConohaVPSを利用して、サーバーを立ててみた話だったが挫折してGhostPROに課金した話

Last updated at Posted at 2025-07-28

結論

GhostPROに課金したほうがはるかに便利でした。
なぜなら、

  • メンテナンスが楽
  • バックアップが楽
  • DBがばぐらない(=つまり不具合が起きにくい)
  • でバックアップ用のVPS環境やバックアップのテーマを取るための容量選択のコストも減る
  • 月額35ドルのコスパ

ということで、実装はできたにせよ、現実的ではなかったので、VPSはやめましたが。
それでもHTTPS化して実装?はできたのでまずはご報告いたします。

テーマは自作です。カスタムページネーションなど工夫したので後日、共有します。

Naomina121 |メンタルヘルスと情報リテラシー

スペックは下記の通り

VPSのスペック

  • メモリ4Gb
  • コア4コア
  • SSD 100GB

Ghostは文章のみのほうが多いので、このぐらいのスペックでも行けると思いました。
何なら他のサービスで、画像はどうにかなりそうです。

  • Amazon S3
  • Imgur
  • Dropbox API
  • Google Cloud Storage
  • Firebase Storage
  • Microsoft Azure Blob Storage
  • ImageKit

ドメイン設定は、CONOHAのマニュアルを見ましょう。
公開鍵もありますが、最初に、作っておいてから、VPS契約するとスムーズです。
公式のドキュメントを参考にしましょう。

さて、実際の手順ですが、そのまま載せます。

自分はこれで動きましたが、動くことは動きますが、メンテナンスの面が大変だと思うのであまり推奨はしません。

Ghostの業者ではありませんが。

VPSで設定する方法

1. VPSの初期セットアップ

まず、ディレクリー構成は最終的にこうなります。

── ghost-blog/
    ├── ghost
    ├── mysql/
    │   └── my.cnf
    ├── nginx/
    │   └── nginx.conf
    ├── .env
    ├── docker-compose.yml
    ├── monitor.sh
    └── backup.sh

1.1 基本的なセキュリティ設定

# システムアップデート
sudo apt update && sudo apt upgrade -y

# 必要なパッケージのインストール
sudo apt install -y ufw fail2ban unattended-upgrades

# 新しいユーザーの作成(rootの直接使用を避ける)
sudo adduser deploy
sudo usermod -aG sudo deploy

# SSH鍵認証の設定
mkdir -p ~/.ssh
# 公開鍵をauthorized_keysに追加
echo "your-public-key" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh

1.2 SSH設定の強化

# SSH設定を編集
sudo nano /etc/ssh/sshd_config

# 以下の設定を追加/変更
Port 2222  # デフォルトポートを変更
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 600
ClientAliveCountMax 0

# SSH再起動
sudo systemctl restart ssh

1.3 ファイアウォール設定

# UFW基本設定
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 必要なポートのみ開放
sudo ufw allow 2222/tcp  # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS

# ファイアウォール有効化
sudo ufw enable

2. Docker環境のセットアップ

2.1 Dockerのインストール

# 古いDockerの削除
sudo apt remove docker docker-engine docker.io containerd runc

# 公式リポジトリの追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Dockerインストール
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# ユーザーをdockerグループに追加
sudo usermod -aG docker $USER

2.2 Docker Composeのインストール

# Docker Compose v2の確認
docker compose version

# 必要に応じて手動インストール
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

3. Ghost環境の構築

3.1 プロジェクトディレクトリの作成

# プロジェクトディレクトリ作成
mkdir -p ~/ghost-blog
cd ~/ghost-blog

# 必要なディレクトリ構造
mkdir -p {nginx,ssl,mysql,ghost/content}

3.2 環境変数ファイルの作成

# .env ファイル作成
cat > .env << 'EOF'
# Ghost設定
GHOST_URL=http://yourdomain.com
GHOST_DB_PASSWORD=your_db_password_here

# MySQL設定
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=ghostdb
MYSQL_USER=ghost

# 環境設定
NODE_ENV=production
TZ=Asia/Tokyo

# 追加の最適化設定
NODE_OPTIONS=--max-old-space-size=512
DB_POOL_MIN=2
DB_POOL_MAX=10

# パフォーマンス最適化
database__pool__min=1
database__pool__max=5
database__connection__acquireConnectionTimeout=60000
database__connection__timeout=60000
database__connection__debug=false
EOF

# 環境変数ファイルのパーミッション設定
chmod 600 .env

3.3 docker-compose.yml

# .env ファイル作成
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  ghost:
    image: ghost:5-alpine
    container_name: ghost-app

    depends_on:
      mysql:
        condition: service_started
    restart: unless-stopped
    environment:
      url: ${GHOST_URL}
      database__client: mysql
      database__connection__host: mysql
      database__connection__user: ${MYSQL_USER}
      database__connection__password: ${GHOST_DB_PASSWORD}
      database__connection__database: ${MYSQL_DATABASE}
      database__pool__min: 1
      database__pool__max: 5
    volumes:
      - ghost_content:/var/lib/ghost/content
    networks:
      - ghost-network
    # Ghostのリソース制限
    deploy:
      resources:
        limits:
          memory: 1G
          cpus: '1.5'
        reservations:
          memory: 256M
          cpus: '0.5'

  mysql:
    image: mysql:8.0
    container_name: ghost-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${GHOST_DB_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    networks:
      - ghost-network
    # MySQLのリソース制限
    deploy:
      resources:
        limits:
          memory: 800M
          cpus: '1.0'
        reservations:
          memory: 256M
          cpus: '0.5'
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 60s
      timeout: 30s
      retries: 5
      start_period: 120s
    command: >
      --default-authentication-plugin=mysql_native_password
      --innodb-buffer-pool-size=256M
      --max-connections=20
      --innodb-log-file-size=64M
      --performance-schema=OFF

  nginx:
    image: nginx:alpine
    container_name: ghost-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
      - ./nginx/logs:/var/log/nginx
    depends_on:
      - ghost
    networks:
      - ghost-network
    # Nginxのリソース制限
    deploy:
      resources:
        limits:
          memory: 128M
          cpus: '0.5'

volumes:
  ghost_content:
  mysql_data:

networks:
  ghost-network:
    driver: bridge
EOF

3.4 MySQL設定ファイル

# MySQL設定ファイル作成
cat > mysql/my.cnf << 'EOF'
# mysql/my.cnf - 4GB RAM環境向け最適化設定

[mysqld]
# === 基本設定 ===
bind-address = 0.0.0.0
skip-name-resolve
default-authentication-plugin = mysql_native_password

# === メモリ最適化 (4GB RAM環境向け) ===
# InnoDB バッファプール (RAM の約25-30%)
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 4

# クエリキャッシュ (MySQL 8.0では廃止されたが設定例として)
# query_cache_type = 1
# query_cache_size = 128M

# テーブルキャッシュ
table_open_cache = 2000
table_definition_cache = 1400

# === 接続設定 ===
max_connections = 50
max_connect_errors = 1000
wait_timeout = 300
interactive_timeout = 300

# === InnoDB 最適化 ===
innodb_log_file_size = 256M
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_read_io_threads = 4
innodb_write_io_threads = 4

# === MyISAM 設定 (念のため) ===
key_buffer_size = 32M
myisam_sort_buffer_size = 8M

# === スレッド設定 ===
thread_cache_size = 16
thread_stack = 256K

# === ソート・結合バッファ ===
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 2M

# === 一時テーブル ===
tmp_table_size = 64M
max_heap_table_size = 64M

# === ログ設定 ===
# スロークエリログ
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 0

# エラーログ
log_error = /var/log/mysql/error.log

# === セキュリティ設定 ===
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO

# === その他の最適化 ===
# バイナリログ (レプリケーションしない場合は無効化)
skip-log-bin

# パフォーマンススキーマ (必要に応じて無効化)
# performance_schema = OFF

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4
EOF

3.5 Nginx設定

# Nginx設定ファイル作成
cat > nginx/nginx.conf << 'EOF'
events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # ログ設定
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # レート制限(緩和)
    limit_req_zone $binary_remote_addr zone=ghostadmin:10m rate=30r/m;
    limit_req_zone $binary_remote_addr zone=ghost:10m rate=60r/m;

    # キャッシュ設定
    proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=ghost_cache:10m max_size=100m inactive=60m;
    proxy_temp_path /tmp/nginx_temp;

    # Gzip圧縮
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/javascript;
    gzip_min_length 1000;

    # HTTPS設定
    server {
        listen 443 ssl http2;
        server_name yourdomain.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;

        # 静的ファイルのキャッシュ
        location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
            proxy_pass http://ghost:2368;
            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;

            # 静的ファイルの長期キャッシュ
            expires 1M;
            add_header Cache-Control "public, immutable";

            # プロキシキャッシュ
            proxy_cache ghost_cache;
            proxy_cache_valid 200 1h;
            proxy_cache_use_stale error timeout invalid_header updating;
        }

        # Ghost管理画面(キャッシュなし)
        location /ghost/ {
            limit_req zone=ghostadmin burst=15 nodelay;
            proxy_pass http://ghost:2368;
            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;
            proxy_read_timeout 300;
            proxy_connect_timeout 300;
            proxy_send_timeout 300;

            # 管理画面はキャッシュしない
            proxy_cache off;
        }

        # 一般的なページ(軽いキャッシュ)
        location / {
            limit_req zone=ghost burst=30 nodelay;
            proxy_pass http://ghost:2368;
            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;

            # 軽いキャッシュ
            proxy_cache ghost_cache;
            proxy_cache_valid 200 5m;
            proxy_cache_use_stale error timeout invalid_header updating;

            # キャッシュバイパス(管理者用)
            proxy_cache_bypass $cookie_ghost_admin_api_session;
        }
    }

    # Client
    client_max_body_size 100M;
    # HTTP to HTTPS redirect
    server {
        listen 80;
        server_name yourdomain.com;
        return 301 https://$server_name$request_uri;
    }
}
EOF

4. SSL証明書の設定

4.1 Let's Encryptの使用

# Certbotのインストール
sudo apt install certbot python3-certbot-nginx

# SSL証明書の取得
sudo certbot certonly --webroot -w /var/www/html -d yourdomain.com

# 証明書のコピー
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem ssl/cert.pem
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem ssl/key.pem

# 証明書の自動更新
sudo crontab -e
# 以下を追加
0 12 * * * /usr/bin/certbot renew --quiet

5. 監視とログ設定

5.1 ログ管理

# ログローテーション設定
sudo nano /etc/logrotate.d/ghost

# 以下を追加
/home/deploy/ghost-blog/nginx/logs/*.log {
    daily
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    create 644 root root
    postrotate
        docker kill -s USR1 ghost-nginx
    endscript
}

5.2 監視スクリプト

# 監視スクリプト作成
cat > monitor.sh << 'EOF'
#!/bin/bash

# コンテナの状態チェック
docker ps --format "table {{.Names}}\t{{.Status}}" | grep -E "(ghost|mysql|nginx)"

# ディスク使用量チェック
df -h | grep -E "(/$|/var)"

# メモリ使用量チェック
free -h

# ログの異常チェック
tail -n 50 nginx/logs/error.log | grep -E "(error|warning)"
EOF

chmod +x monitor.sh

6. バックアップ設定

# バックアップスクリプト作成
cat > backup.sh << 'EOF'
#!/bin/bash

BACKUP_DIR="/home/deploy/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# バックアップディレクトリ作成
mkdir -p $BACKUP_DIR

# MySQLバックアップ
docker exec ghost-mysql mysqldump -u root -p$MYSQL_ROOT_PASSWORD ghostdb > $BACKUP_DIR/ghost_db_$DATE.sql

# Ghostコンテンツバックアップ
docker run --rm -v ghost_content:/source -v $BACKUP_DIR:/backup alpine tar czf /backup/ghost_content_$DATE.tar.gz -C /source .

# 古いバックアップを削除(7日以上前)
find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
EOF

chmod +x backup.sh

# 定期実行設定
crontab -e
# 以下を追加
0 2 * * * /home/deploy/ghost-blog/backup.sh

7. 起動とテスト

# 環境の起動
docker compose up -d

# ログの確認
docker compose logs -f

# 状態確認
docker compose ps

8. セキュリティチェックリスト

  • SSH鍵認証の設定完了
  • ファイアウォール設定完了
  • パスワードを環境変数に設定
  • SSL証明書の設定完了
  • レート制限の設定完了
  • セキュリティヘッダーの設定完了
  • ログ監視の設定完了
  • バックアップ設定の完了
  • 定期更新の設定完了

公開できたなら

ここまでいけば、とお思いでしょう。

でも本格的にやるなら、テーマのバックアップと、Github連携による自動デプロイ設定から、ステージング環境間で用意したほうが良いと思うのでやはり現実的では・・・(ごほごほっ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?