You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Heroku部署Django 2.0时遇OSError: [Errno 30]只读文件系统问题

解决Heroku上Django应用写入媒体目录的只读文件系统错误

首先,这个问题的核心原因是Heroku的文件系统特性:Heroku的dyno文件系统是临时(ephemeral)且大部分目录只读的,只有/tmp目录是允许写入的,而你当前配置的MEDIA_ROOT指向的是BASE_DIR外的static_cdn/media_root,这个路径不在Heroku允许的可写范围内,所以触发了OSError: [Errno 30] Read-only file system错误。

下面分两种场景给出解决方案:

场景1:临时测试(不要求文件持久化)

如果只是测试功能,不需要生成的音频文件长期保存,可以直接把MEDIA_ROOT指向Heroku的临时目录/tmp:

修改你的App/settings/production.py:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
MEDIA_URL = '/media/'
# 替换为Heroku允许写入的临时目录
MEDIA_ROOT = os.path.join('/tmp', 'static_cdn', 'media_root')

同时,在生成音频文件的代码里,确保目标目录存在(避免路径不存在的错误):

import os
import time
from django.conf import settings
from gtts import gTTS

tts_file_name = f"{int(time.time())}.mp3"
# 确保tts子目录存在,exist_ok=True避免重复创建报错
tts_dir = os.path.join(settings.MEDIA_ROOT, 'tts')
os.makedirs(tts_dir, exist_ok=True)
joined_path = os.path.join(tts_dir, tts_file_name)

# 生成并保存语音文件
tts = gTTS(text="你的文本内容", lang='zh-cn')
tts.save(joined_path)

⚠️ 注意:/tmp目录的文件会在dyno重启(比如部署新代码、dyno休眠唤醒)时被清空,所以不适合生产环境长期存储文件。

场景2:生产环境(需要文件持久化)

生产环境下,必须使用云存储服务来保存媒体文件,Heroku官方推荐使用AWS S3、Cloudinary等服务。这里以AWS S3为例:

步骤1:安装依赖

在你的requirements.txt中添加:

django-storages>=1.13.2
boto3>=1.28.0

然后重新部署到Heroku,或本地执行pip install -r requirements.txt。

步骤2:配置S3存储

修改App/settings/production.py,添加S3相关配置:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
MEDIA_URL = '/media/'

# 引入环境变量(敏感信息不要硬编码)
import os
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = 'us-east-1'  # 替换为你的S3存储桶所在区域
AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"

# 设置媒体文件存储到S3
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/media/"

# 可选:设置缓存控制,提升访问速度
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

步骤3:在Heroku设置环境变量

通过Heroku CLI设置敏感信息(避免硬编码到代码中):

heroku config:set AWS_ACCESS_KEY_ID="你的AWS访问密钥ID"
heroku config:set AWS_SECRET_ACCESS_KEY="你的AWS秘密访问密钥"
heroku config:set AWS_STORAGE_BUCKET_NAME="你的S3存储桶名称"
heroku config:set AWS_S3_REGION_NAME="你的存储桶区域"

步骤4:调整文件保存代码

不需要修改保存路径的代码,因为django-storages会自动将settings.MEDIA_ROOT的写入请求转发到S3,原有的os.path.join(settings.MEDIA_ROOT, 'tts', tts_file_name)会自动映射到S3的对应路径。

这样修改后,生成的音频文件会直接保存到S3,既解决了Heroku文件系统只读的问题,又能持久化存储媒体文件。

内容的提问来源于stack exchange,提问作者Anuj TBE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 07:04:26