画像をMiniOサーバにアップロードするアプリを作成してビルド後自鯖にデプロイしてみたところ、Server Actionsの1MB制限に引っかかってしまいアップロードできない事態に見舞われました。開発環境だと問題なく上げられたのでちょっと困りました。

Next.js13以下ではnext.config.tsに下記を追加することで回避できたようですが、Next.js15 App Routerでは使用できません。

next.config.ts
// Next.js13以前の設定
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // これを追記
  experimental: {
    serverActions: {
      bodySizeLimit: '500mb',
    },
  },
};

export default nextConfig;

Next.js15ではスタンドアロンモード(最小限の構成でビルド)でデプロイすることでExpressのserver.js側でアップロード上限を設定できるようなのでやってみました。next.config.tsに下記を追記します。

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // スタンドアロンモードで出力
  output: "standalone",
};

export default nextConfig;

設定系は/myapp/.env.productionに書いています。

ディレクトリ構成が下記になっているので適宜変更してください。

/
├─ myapp/ (Next.jsアプリ)
│  ├─ app/
│  │  └─ page.tsx
│  ├─ .env.production
│  ├─ next.config.ts
│  ├─ package.json
│  ├─ package.lock.json
│  ├─ server.js
│  └─ tsconfig.json
└─ docker-compose.yml

自前でserver.jsを用意します

server.js
/* eslint-disable @typescript-eslint/no-require-imports */

// server.js
const express = require("express");
const next = require("next");
const path = require("path");

const port = parseInt(process.env.PORT || "3000", 10);
const dev = process.env.NODE_ENV !== "production";

const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();

  // 最大アップロードサイズを設定
  server.use(express.json({ limit: "500mb" }));
  server.use(express.urlencoded({ extended: true, limit: "500mb" }));
  
  server.use(
    "/_next/static",
    express.static(path.join(__dirname, ".next/static"))
  );

  server.all("*", (req, res) => {
    return handle(req, res);
  });

  server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`);
  });
});
Dockerfile
# Dockerfile

FROM node:20-alpine AS base
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=base /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 本番用
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /server.js ./server.js

# Next standalone実行に必要
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

EXPOSE 3000
CMD ["node", "server.js"]
docker-compose.yml
services:
  app:
    build:
      context: ./myapp
      dockerfile: Dockerfile
    container_name: myapp-app
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    env_file:
      - ./myapp/.env.production
    depends_on:
      - db

volumes:
  postgres_data:

あとはNginx側でもclient_max_body_sizeを設定してあげます。

Nginx
server {
    listen 32222 ssl;
    ssl_certificate /home/owner/system/pem/server_cert.pem;
    ssl_certificate_key /home/owner/system/pem/server_key.pem;
    client_max_body_size 500m; # ここで上限設定
    
    location / {
        proxy_pass http://localhost: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;
    }
}

独自ドメインにメールも統合しようと思ったのでdocker-mailserverを使用してVPSにメールサーバーを構築しました。

docker-mailserverを使うとPostfixとDovecotでサクッとメールサーバーが構築できます。

送信にはリレーサーバーを使用、また受信ガイドラインの厳しくなったGmailでも受信できるようにdocker-mailserver+CloudflareでDKIM,DMARC,SPFの設定を行います。

元々example.comドメインを使用している前提で[email protected]のメアドを作る感じで説明を入れていきます。

続きを読む

Blueskyも登録してみました。

フィードが便利なのですが、フィードの作れるskyfeedは7日保存だったりたまに重くなるので自鯖に立ててみました。Bluesky公式のfeed-generatorとDockerを使用します。

参考サイト:

Github – ATProto Feed Generator

feed-generatorを使ってBlueskyのCustomFeedを作る

カスタムフィードを作ってみる?

feed-generatorはリアルタイムで全ての投稿が流れてくる中から自鯖のDBにデータを選んで保存し、そのDBからフィードを作成してフィードのjsonを返します。

AT protocolの思想にcraving indexerがBluesky鯖の外部に作成されて分散型でも鯖を跨いでデータを収集し検索や統計に使用されるという要素が有り、フィード作成はその思想の一端を担っている印象です。(現時点まだ鯖間の連合はできないですが…)

続きを読む

やってみたかったので

オブジェクトストレージ

Misskeyのドライブにアップロードした画像などのデータは./files/フォルダの中でこんな感じになっています

なんとなくthumbnailはわかりますけどよくわかんないですね…。

オブジェクトストレージといって、ファイルを階層化させず、オブジェクト単位で保存し扱いやすくさせる形式で保存されています。

オブジェクトストレージはサービスによっては保存したファイルの冗長性を高めたり、負荷を分散させたりできます。Amazonのs3だったり、Google Cloud Storageだったり、CDNサービスのCloudflareも最近サービスを始めました。保存の料金だったりデータの転送などに料金がかかったりします(内容によって無料も有り)。料金の見直しなどで別なオブジェクトストレージサーバーに移ることもあるため、現在大抵のオブジェクトストレージはAmazon s3と互換性のある形式で作成されています。

Misskeyでは外部のオブジェクトストレージが使えるので、フリーのs3互換オブジェクトストレージMiniOをインストールして使ってみました。

注意:後からオブジェクトストレージを設定すると今までMisskeyサーバー上に上げていた./files/内のファイルにはアクセス出来なくなります。

続きを読む

2023/09/26更新 Ubuntu Server 22.04 LTS / PostgreSQL 15

動機

pg_rmanでオンラインバックアップを取りたいのにweb上で見かけたライブラリをインストールしてもPostgreSQL15だと上手く動かなかったので、その辺成功したメモ

Dockerfileの作成

Miskkeyで使うDBのDockerfile(イメージにはpostgres:15-bookwormを使用)に以下を追加

実際には前回のPGroonga導入で作成したDockerfileに追記しています

スクリプトはDockerfileと同じフォルダに作成

Dockerfile

Tiniを入れてPostgreSQLのDocker内のPIDが1にならないようにします。リストアするときにPostgreSQLを停止しないと行けないのですが、PIDが1になっているとPostgrSQLの停止=Dockerコンテナ自体が停止してしまうためです。

Dockerfile
# Add Tini
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
# pg_rman install
RUN apt update
RUN apt install -y build-essential libpq-dev git zlib1g-dev
RUN apt-get update
RUN apt-get -y install postgresql-client-15 postgresql-15 postgresql-server-dev-15 libpq-dev
RUN apt-get -y install libpq-dev libselinux1-dev liblz4-dev libpam0g-dev libkrb5-dev libreadline-dev libzstd-dev
RUN git clone https://github.com/ossc-db/pg_rman.git /tmp/pg_rman && \
    cd /tmp/pg_rman && \
    make && make install && \
    rm -rf /tmp/pg_rman
CMD ["docker-entrypoint.sh", "postgres"]

backup_script.sh

backup_script.sh
#!/bin/bash
BACKUP_DIR="/var/lib/postgresql/backup"
DB_DIR="/var/lib/postgresql/data"
ARCHIVE_DIR="/var/lib/postgresql/archive"
MODE="$1"
/usr/pgsql-15/bin/pg_rman backup --backup-mode=$MODE -b $BACKUP_DIR -D $DB_DIR -A $ARCHIVE_DIR

cronでバックアップを定時実行しています

Ubuntu 22.04 LTS

独自ドメインにwordpressを移行しました。プラグイン等は使っていません。

DockerでWordpress+MariaDBをインストール、ホストOS側のNginxでリバースプロキシを設定しています。

プラグインを使用して移行しようと思ったら上手く行かなかったので自力移行です。(;o;)オヨー

続きを読む