如何在 Render 上配置 PHP/Node.js 文件上传 | Disk·环境变量·S3 集成
分类:Render·部署配置
本文目前仅提供日文版本。我们正在进行翻译工作。
Render 是一个作为 Heroku 替代品的流行云平台。与 Vercel 或 Netlify 不同,它使用持久进程(Web Service)模型而不是无服务器,这改变了文件上传的架构。本文介绍了 Render 的持久存储(Disk)配置、在 PHP 环境中修改 <code>upload_max_filesize</code> 的方法、使用环境变量的 S3 设置,以及基础设施即代码(IaC)中 <code>render.yaml</code>(Blueprint)的配置示例。
什么是 Render Disk(永久存储)?
Render 的 Web Service 默认是短暂的(重新部署时文件系统会重置)。要保持上传的文件,请添加 Disk。
| 存储类型 | 持久性 | 跨多个实例共享 | 费用 |
|---|---|---|---|
| 临时磁盘(默认) | 重新部署时重置 | 不可能 | 免费 |
| Render Disk(永久) | 永久(保留至手动删除) | 不可能(仅限单个实例) | $0.25/GB/月 |
| AWS S3(外部) | 永久 | 支持 | 按 S3 定价 |
Render Disk 不支持扩展(多个实例),因此生产环境中的文件上传建议使用 S3 集成。Disk 适用于开发、测试环境或单实例部署。
Render Dashboard 中的 Disk 配置
可以从 Render Dashboard 的 Web Service 设置中添加磁盘。
# render.yaml(Blueprint)での Disk 設定
services:
- type: web
name: my-app
runtime: node
buildCommand: npm install && npm run build
startCommand: npm start
disk:
name: uploads-disk
mountPath: /app/uploads # アプリ内でのマウントパス
sizeGB: 10 # 10GB のディスク
envVars:
- key: UPLOAD_DIR
value: /app/uploads
// Node.js での Disk へのファイル保存
const path = require('path');
const fs = require('fs');
const UPLOAD_DIR = process.env.UPLOAD_DIR || path.join(__dirname, 'uploads');
// アップロードディレクトリが存在しない場合は作成
if (!fs.existsSync(UPLOAD_DIR)) {
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}
// multer の設定例(Disk ストレージ)
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOAD_DIR);
},
filename: (req, file, cb) => {
const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;
const ext = path.extname(file.originalname);
cb(null, `upload-${uniqueSuffix}${ext}`);
},
});
const upload = multer({
storage,
limits: { fileSize: 50 * 1024 * 1024 }, // 50MB
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('許可されていないファイル形式です。'));
}
},
});
PHP环境中的upload_max_filesize配置
对于 Render 上的 PHP 应用(基于 Docker),您可以通过修改 <code>php.ini</code> 设置来调整上传大小。Render 支持任意 Docker 配置,比其他托管服务更灵活。
# Dockerfile(PHP アプリ)
FROM php:8.2-fpm
# 必要な拡張をインストール
RUN docker-php-ext-install pdo pdo_mysql
# php.ini の設定をオーバーライド
RUN echo "upload_max_filesize = 100M" > /usr/local/etc/php/conf.d/uploads.ini \
&& echo "post_max_size = 110M" >> /usr/local/etc/php/conf.d/uploads.ini \
&& echo "memory_limit = 256M" >> /usr/local/etc/php/conf.d/uploads.ini \
&& echo "max_execution_time = 120" >> /usr/local/etc/php/conf.d/uploads.ini \
&& echo "max_input_time = 120" >> /usr/local/etc/php/conf.d/uploads.ini
WORKDIR /var/www/html
COPY . .
EXPOSE 9000
CMD ["php-fpm"]
# php.ini(直接配置する場合)
; ファイルアップロードの有効化
file_uploads = On
; 1ファイルあたりの上限
upload_max_filesize = 100M
; POST データ全体の上限(upload_max_filesize より大きくする)
post_max_size = 110M
; PHP スクリプトのメモリ上限
memory_limit = 256M
; スクリプトの最大実行時間(秒)
max_execution_time = 120
; ファイル入力待ちの最大時間(秒)
max_input_time = 120
; 一時ファイルのディレクトリ(Render の場合は /tmp を使用)
upload_tmp_dir = /tmp
<?php
// .htaccess が使えない場合は ini_set() で実行時に変更(共有ホスティングでは制限あり)
// Render(Docker)では Dockerfile での設定が確実
// ini_set() による実行時オーバーライド(一部の設定のみ有効)
ini_set('memory_limit', '256M');
// upload_max_filesize と post_max_size は実行時変更不可(php.ini での設定が必要)
// 設定値の確認
echo ini_get('upload_max_filesize'); // "100M"
echo ini_get('post_max_size'); // "110M"
echo ini_get('memory_limit'); // "256M"
使用环境变量的S3配置
在 Render Dashboard 或 <code>render.yaml</code> 中设置环境变量,从您的应用访问 AWS S3。使用 Render 的秘密管理功能处理敏感信息,<code>render.yaml</code> 中仅包含密钥。
# render.yaml(Blueprint)— シークレットはキーのみ定義
services:
- type: web
name: my-php-app
runtime: docker
dockerfilePath: ./Dockerfile
envVars:
# 非シークレット(値を直接記載)
- key: AWS_REGION
value: ap-northeast-1
- key: AWS_S3_BUCKET
value: my-app-uploads
# シークレット(Render Dashboard で値を設定)
- key: AWS_ACCESS_KEY_ID
sync: false # sync: false でダッシュボードで手動入力
- key: AWS_SECRET_ACCESS_KEY
sync: false
# または Render の Environment Group を参照
- fromGroup: aws-credentials
disk:
name: tmp-uploads
mountPath: /tmp/uploads
sizeGB: 5
<?php
// PHP での AWS SDK を使った S3 アップロード
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
$s3 = new S3Client([
'version' => 'latest',
'region' => getenv('AWS_REGION'),
'credentials' => [
'key' => getenv('AWS_ACCESS_KEY_ID'),
'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
],
]);
function uploadToS3(array $file, string $bucket): array
{
global $s3;
$key = 'uploads/' . uniqid('file_', true) . '_' . basename($file['name']);
try {
$result = $s3->putObject([
'Bucket' => $bucket,
'Key' => $key,
'SourceFile' => $file['tmp_name'],
'ContentType' => mime_content_type($file['tmp_name']),
'ACL' => 'private',
]);
return [
'success' => true,
'key' => $key,
'url' => $result['ObjectURL'],
];
} catch (AwsException $e) {
return ['success' => false, 'error' => $e->getMessage()];
}
}
// アップロード処理
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
// バリデーション
$maxSize = 50 * 1024 * 1024; // 50MB
if ($file['size'] > $maxSize) {
http_response_code(413);
echo json_encode(['error' => 'ファイルが大きすぎます(上限50MB)。']);
exit;
}
$allowedMimes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
$detectedMime = mime_content_type($file['tmp_name']); // サーバー側でMIMEを検出
if (!in_array($detectedMime, $allowedMimes)) {
http_response_code(415);
echo json_encode(['error' => '許可されていないファイル形式です。']);
exit;
}
$result = uploadToS3($file, getenv('AWS_S3_BUCKET'));
echo json_encode($result);
}
render.yaml(Blueprint)中的完整配置示例
使用 Blueprint,你可以将 Render 基础设施作为代码进行管理。你可以一起定义 Web Service、数据库、Redis、Disk 和环境变量。
# render.yaml
version: "1"
services:
# Web アプリケーション
- type: web
name: file-upload-app
runtime: node
plan: starter # free / starter / standard / pro
region: singapore # oregon / frankfurt / singapore / ohio
buildCommand: npm ci && npm run build
startCommand: node server.js
healthCheckPath: /health
autoDeploy: true # Git push で自動デプロイ
# 永続ストレージ(スケールアウト不可)
disk:
name: user-uploads
mountPath: /app/data/uploads
sizeGB: 20
# 環境変数
envVars:
- key: NODE_ENV
value: production
- key: PORT
value: 3000
- key: UPLOAD_DIR
value: /app/data/uploads
- key: AWS_REGION
value: ap-northeast-1
- key: AWS_S3_BUCKET
value: my-production-bucket
# シークレット(ダッシュボードで値を設定)
- key: AWS_ACCESS_KEY_ID
sync: false
- key: AWS_SECRET_ACCESS_KEY
sync: false
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
# PostgreSQL データベース
- type: pserv
name: app-db
runtime: postgres
plan: starter
region: singapore
databaseName: app_production
本文中可用的测试文件(免费)
- → <a href="/ja/files/images/png/1mb/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG 测试图像(1MB)</a> — 用于验证到 Render Disk·S3 的上传行为
- → <a href="/ja/files/pdf/1mb/" class="text-primary-600 dark:text-primary-400 hover:underline">PDF 测试文件(1MB)</a> — 用于验证 PHP 的 <code>upload_max_filesize</code> 配置
- → <a href="/ja/files/zip/1mb/" class="text-primary-600 dark:text-primary-400 hover:underline">ZIP 测试文件(1MB)</a> — 用于边界值测试和 S3 直接上传验证
相关文章
- → <a href="/ja/blog/vercel-upload-config/" class="text-primary-600 dark:text-primary-400 hover:underline">Vercel 文件上传配置和限制 | Vercel Blob・API 限制・解决方案</a>
- → <a href="/ja/blog/netlify-upload-config/" class="text-primary-600 dark:text-primary-400 hover:underline">使用 Netlify Functions 上传文件的方法|限制、Large Media 和解决方案</a>
- → <a href="/ja/blog/laravel-file-upload/" class="text-primary-600 dark:text-primary-400 hover:underline">Laravel 文件上传实现指南|验证、Storage 和 S3 支持</a>