画像を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;
    }
}

Next.jsのApp routerの同じファイル名だらけでタブの視認性が悪い問題解決!

globパターンが分かってなくてちょっと戸惑いました

VScodeのsetteing.jsonに下記

setting.json
  // タブ名カスタム
  "workbench.editor.customLabels.enabled": true,
  "workbench.editor.customLabels.patterns": {
    "**/admin/*/*/page.tsx": "${dirname(1)}${dirname(0)} - Page",
    "**/admin/*/page.tsx": "${dirname} - Page",
    "**/api/*/*/route.ts": "${dirname(1)}${dirname(0)} - API",
    "**/api/*/route.ts": "${dirname} - API",
    "**/layout.tsx": "${dirname} - Layout",
    "**/page.tsx": "${dirname} - Page",
    "**/route.ts": "${dirname} - API"
  }

admin/*/*/page.tsxなどにすることで階層を指定できるようです。

admin/upload.tsxは「upload – Page」、admin/edit/[id]/page.tsxは「edit[id] – Page」と[slug]が分かるようにしたかったので

SNSに上げていた進捗をまとめてみました。NSFW(背後注意)な絵もあるのでご注意

お空のデート

続きを読む

メギド72、ついに完結しオフライン版となりました。

他のゲームとかだとなかなか触れない部分を埋めてくれたり、家族愛や同性間の恋愛など、様々な愛について人外視点で解体して再構築するシナリオと、奥深いゲーム性、ミルトンの失楽園や黙示録はじめループ重力量子論などの量子力学・物理学にも通じたライターのSF作家としての力量、本当に大好きです…

弊アジトには実装された272体が全員揃い、衣装もすべて購入済み、全員Lv70(ブフ様&サタン様はLv80)&専用霊宝も全作成済み、全金冠にミッションもソロモンLv以外はスタイル縛りミッションも全て埋めたり、本当にやりこんだゲームでした。

自作したメギド所持率チェッカーも自鯖がダメになるまではずっと置き続ける予定です。是非攻略の際の手持ち共有などにもご利用ください。

メギド72を永遠にしたい

そういうわけでオフライン版となったメギド72ですが、オフライン化後は通信が一切行われず、運営のサーバーも閉じ、端末が壊れるまではずっと遊べる仕様となりました。

いやだーーーーーー!!!!!壊れないで!!!!!!!!!

そういうわけで私は目論見ました。

Androidであればエミュレータもあるし、バックアップがうまくいけばメギドを永遠にできるのでは?

私はずっとiPhoneでメギドをやっていたのですが、このためだけにGoogle Pixel8aを買い、データ移行をしておきました。

ちなみにpixelにしたのはroot化がXperiaよりしやすそうとかなだったのですが結局仕事とかがバタついていてその辺やらずにオフライン化突入

iOSはシステムやアプリデータなどユーザーが触れないように割とガチガチなので、root化なしにアプリデータのバックアップできる可能性が割と低かったため

結論から言うと、いけました。

PCへバックアップを取ってそのデータでプレイできる感じになります。

現状rootを取らなくてもできるので良かったです😉

続きを読む

Nox playerを入れたかったのですが何やってもハイパーバイザー&仮想化ベースのセキュリティが無効化できず困った備忘録です。

Intel 14700KF+MSI Z790 TOMAHAWK WIFIでWindows11Proを使用しています。

VT-xの有効化の確認にはLeoMoon CPU-Vなどが簡単です。

こんな風になっちゃう…

またMicrosoftのcoreinfoでもチェックできます。コマンドプロンプトからソフトのあるフォルダに移動してcoreinfo64 -vで実行します。

続きを読む

最近のお絵描き関連のツールのメモをまとめてみました。

画像にはNSFWありますので注意

続きを読む

m.estampie.work, blog.estampie.work… と個別に証明書を取っていたのですが面倒になってきたのでワイルドカード証明書を取ることにしました。またHTTP-01チャレンジで行っていたのでDNS-01チャレンジで取得してみます。

DNS-01チャレンジで証明書取得

サンプルはexample.comです。

既にcerbotはインストール済みのため、追加で必要なパッケージを取得します。

sudo apt-get update
sudo apt-get install python3-certbot-dns-cloudflare

CloudflareのダッシュボードでAPIトークンを取得しておきます。テンプレートから「ゾーン DNS を編集する」を選び、対象ドメインを指定します。

取得したら/etc/letsencrypt/cloudflare.iniファイルを作成してAPIトークンを記述します。

sudo vi /etc/letsencrypt/cloudflare.ini
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
/etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = APIトークン

元々example.comで証明書を取得していたのでワイルドカード証明書もcert-nameを同名で取得します。

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "*.example.com" \
  -d "example.com" \
  --cert-name example.com

完了したら下記コマンドで証明書を確認します。

sudo certbot certificates

ワイルドカード証明書でカバーできる不要な証明書は下記で削除します。

sudo certbot delete --cert-name blog.example.com

Nginxに記述してある証明書ファイルの場所ssl_certificate, ssl_certificate_keyを統一したcert-name example.comのものに置き換えます。

default
server {
    listen 443 ssl;
    server_name blog.example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_verify_client off;
    ...
}

またHTTP-01チャレンジの際に必要だった/.well-known/へのアクセスの切り分けも不要になります。

書き換えたらNginxを再起動します。

sudo nginx -t
sudo systemctl reload nginx

以上で完了です。

IMAPメールの受信ボックスの未読メールから特定の件名&送信元のメールを取得→LINE通知→既読にするPythonスクリプトです。

前回書いたものはGASを使ってGmailのみ対応でしたが、こちらはIMAPメールなら何でも大丈夫です。

サンプルではBoothの購入とskebリクエストが入ったら通知します。

自鯖があればLinuxならCronで定期実行してあげます。

24時間動いているPCがないといけないので、AWSのLambdaを使って無料枠で実行したりも良いかもです。(無料枠だと実行間隔に注意かも)

続きを読む

ちょっとアプリだと色々不便なことが増えてしまったので、スマホでブラウザ版Twitterを使用し、不要なものをUserCSSで消していきます。

続きを読む

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

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

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

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

続きを読む