django-storages FTP存储在生产环境无法连接的问题求助
问题:DRF部署在PythonAnywhere时,django-storages FTP连接被拒绝(500错误)
前端基于Angular部署在云主机,后端基于DRF部署在PythonAnywhere,配置django-storages通过FTP将用户上传的文件发送到前端所在服务器。本地开发环境功能正常,但生产环境出现Server Error (500)错误,控制台错误信息如下:
2023-04-04 19:32:00,158: Internal Server Error: /admin/portfolio/developer/add/ Traceback (most recent call last): File "/home/ferreromanuel/.virtualenvs/portfolio-virtualenv/lib/python3.10/site-packages/storages/backends/ftp.py", line 91, in _start_connection ftp.connect(self._config['host'], self._config['port']) File "/usr/local/lib/python3.10/ftplib.py", line 158, in connect self.sock = socket.create_connection((self.host, self.port), self.timeout, File "/usr/local/lib/python3.10/socket.py", line 845, in create_connection raise err File "/usr/local/lib/python3.10/socket.py", line 833, in create_connection sock.connect(sa) ConnectionRefusedError: [Errno 111] Connection refused **NO MATCH** During handling of the above exception, another exception occurred: **NO MATCH** Traceback (most recent call last): ... raise FTPStorageException( storages.backends.ftp.FTPStorageException: Connection or login error using data {'active': False, 'path': '/htdocs/assets/media/', 'host': 'ftp.manuelferrero.com.ar', 'user': 'webmaster.manuelferrero.com.ar', 'passwd': '*********', 'port': 21}
settings.py配置如下:
import os import environ from pathlib import Path env = environ.Env() environ.Env.read_env() SITE_NAME = 'Manuel Ferrero' BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = os.environ.get("SECRET_KEY") DEBUG = os.environ.get("DEBUG") == "True" ALLOWED_HOSTS = [] INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "rest_framework", "corsheaders", "portfolio", "contact", ] CSRF_TRUSTED_ORIGINS = ['http://localhost:4200','https://*.127.0.0.1'] MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] ROOT_URLCONF = "core.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [os.path.join(BASE_DIR, 'templates')], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] WSGI_APPLICATION = "core.wsgi.application" DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", } } AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",}, ] LANGUAGE_CODE = "es-AR" TIME_ZONE = "America/Argentina/Buenos_Aires" USE_I18N = True USE_TZ = True STATIC_URL = "static/" STATIC_ROOT = os.path.join(BASE_DIR, 'static') DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # Media files settings PUBLIC_MEDIA_LOCATION = 'assets/media' MEDIA_URL = f'https://www.manuelferrero.com.ar/{PUBLIC_MEDIA_LOCATION}/' # Django-Storages settings DEFAULT_FILE_STORAGE = 'storages.backends.ftp.FTPStorage' FTP_STORAGE_LOCATION = os.environ.get('FTP_STORAGE_LOCATION') # CORS settings CORS_ALLOW_ALL_ORIGINS = True # Email settings EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' DEFAULT_FROM_EMAIL = 'no-responder@manuelferrero.com.ar' DEFAULT_CONTACT_EMAIL = 'contacto@manuelferrero.com.ar' #! =============================== PRODUCTION SETTINGS =============================== if not DEBUG: ALLOWED_HOSTS = [ 'http://www.manuelferrero.com.ar', 'https://www.manuelferrero.com.ar', 'http://ferreromanuel.pythonanywhere.com', 'https://ferreromanuel.pythonanywhere.com', 'ferreromanuel.pythonanywhere.com' ] CSRF_TRUSTED_ORIGINS = [ 'http://www.manuelferrero.com.ar', 'https://www.manuelferrero.com.ar', 'http://ferreromanuel.pythonanywhere.com', 'https://ferreromanuel.pythonanywhere.com', ] # Email settings EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.manuelferrero.com.ar' EMAIL_HOST_USER = 'no-responder@manuelferrero.com.ar' EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD") EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_TIMEOUT = 300 # Sec DEFAULT_FROM_EMAIL = 'No responder | MF! <no-responder@manuelferrero.com.ar>' DEFAULT_CONTACT_EMAIL = 'Contacto | MF! <contacto@manuelferrero.com.ar>' # CORS Policy CORS_ALLOW_ALL_ORIGINS = False CORS_ALLOWED_ORIGINS = [] # Session & CSRF cookies SESSION_COOKIE_SECURE = True SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_SECONDS = 31536000 SECURE_REDIRECT_EXEMPT = [] SECURE_SSL_REDIRECT = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
解决思路
- 检查PythonAnywhere出站限制:PythonAnywhere默认禁止出站连接到标准FTP端口21(仅允许连接自身FTP服务),这是最可能的原因。可改用SFTP(端口22),或确认前端主机支持非标准FTP端口,同时查看PythonAnywhere后台的出站规则。
- 手动测试FTP连接:在PythonAnywhere控制台执行
ftp ftp.manuelferrero.com.ar命令,验证是否能正常连接,排除域名解析、网络路由问题。 - 确认FTP凭据正确性:检查生产环境
FTP_STORAGE_LOCATION环境变量包含的主机、用户名、密码、路径是否完全正确,尤其注意密码是否有特殊字符导致解析错误。 - 切换FTP模式:当前为被动模式(
active: False),尝试改为主动模式;或检查前端FTP服务器是否开放被动模式所需的端口范围,是否有防火墙拦截数据流。 - 替换为SFTPStorage:django-storages支持SFTP后端,安全性更高且PythonAnywhere对SFTP出站限制更少。只需将
DEFAULT_FILE_STORAGE改为storages.backends.sftpstorage.SFTPStorage,并配置对应SFTP参数。 - 检查前端主机防火墙:确认前端服务器的21端口(或SFTP的22端口)对PythonAnywhere的IP地址开放,无防火墙规则拒绝连接。
内容的提问来源于stack exchange,提问作者Manu
相关产品推荐
相关产品推荐

