Django Webapp 的 CGI 部署,例如 Strato.de Webhosting

CGI deployment for a Django Webapp e.g. Strato.de Webhosting

提问人:Revero 提问时间:9/28/2023 最后编辑:Revero 更新时间:11/1/2023 访问量:97

问:

IAM 尝试通过 strato.de 上的 CGI 部署我的 Django 应用程序。Strato 仅支持基本的 cgi,因此 iam 被迫使用此方法。

通过本教程,我已经通过 cgi 在 strato 上运行了一个烧瓶应用程序(顺便说一句,很棒的指南)。我试图改变它并将其熟练地用于 django 应用程序以使其在 Web 服务器上运行,但看起来我遗漏了一些东西。

如果我调用该网站,我会遇到 500 内部服务器错误。(我也会感谢一些如何调试这个的提示,我不知道从哪里开始)。提一下:在开发环境中一切正常。

已完成的步骤:

  1. 我确实检查了 requirements.txt 文件中列出的服务器上是否安装了所有必需的软件包。
  2. 我确实创建了一个 cgi 文件来加载带有 django cgi-handler 的 django 应用程序pip install django-cgi
  3. 更改了部署 settings.py(密钥设置、允许的主机设置、debug = false)
  4. 阅读部署指南和官方文档
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', '6ps8j!crjgrxt34cqbqn7x&b3y%(fny8k8nh21+qa)%ws3fh!q')
# SECURITY WARNING: don't run with debug turned on in production!
#DEBUG = True
DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'

ALLOWED_HOSTS = ['*']

我确实设置了,因为我读到如果 django 为空 [] ,它就不会运行。allowed_hosts=['*']

问:是否有可能我必须使用一些 bash 命令设置Secret_key,以便应用程序找到它? 问:我到底需要将allowed_hosts设置为什么?类似 allowed_hosts=['www.website.de']

settings.py 文件:

"""
Django settings for commerce project.

Generated by 'django-admin startproject' using Django 3.0.2.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os
from urllib.parse import urlparse


# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
#SECRET_KEY = '6ps8j!crjgrxt34cqbqn7x&b3y%(fny8k8nh21+qa)%ws3fh!q'
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', '6ps8j!crjgrxt34cqbqn7x&b3y%(fny8k8nh21+qa)%ws3fh!q')
# SECURITY WARNING: don't run with debug turned on in production!
#DEBUG = True
DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'trainer',
    'tinymce',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    '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 = 'denisevreden.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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 = 'denisevreden.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

AUTH_USER_MODEL = 'trainer.User'

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

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',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# The absolute path to the directory where collectstatic will collect static files for deployment.

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# rest of the code

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# The URL to use when referring to static files (where they will be served from)
STATIC_URL = '/static/'

# Email settings

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.strato.de'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = *******
EMAIL_HOST_PASSWORD = *******

#csrf settings
CSRF_TRUSTED_ORIGINS = ['https://*.mydomain.com','https://*.127.0.0.1', 'https://localhost:8000']

# TinyMCE settings


TINYMCE_JS_URL = 'https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js'
TINYMCE_COMPRESSOR = False

TINYMCE_DEFAULT_CONFIG = {
    "height": "320px",
    "width": "960px",
    "menubar": "file edit view insert format tools table help",
    "plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code "
    "fullscreen insertdatetime  table paste code help wordcount spellchecker",
    "toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft "
    "aligncenter alignright alignjustify | outdent indent |  numlist bullist checklist | forecolor "
    "backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | "
    "fullscreen  preview save print | insertfile image pageembed template link anchor codesample | "
    "a11ycheck ltr rtl | showcomments addcomment code",
    "custom_undo_redo_levels": 10,
}


manage.py 文件:

#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import dependencies
import os, sys


def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'denisevreden.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

** cgi_handler.py:**

#!/usr/local/python/3.10.4/bin/python
import wsgiref.handlers

from denisevreden.wsgi import application

wsgiref.handlers.CGIHandler().run(application)

快乐的 .cgi 文件:

#!/usr/bin/python3
import os
import sys
#!/usr/bin/env python
import os
import sys

# Add the path to the Django project to the system path
sys.path.append('/mnt/web315/a3/18/512337018/htdocs/.cgi-bin/Happy-dv')

# Set the environment variable to tell Django where the settings module is
os.environ['DJANGO_SETTINGS_MODULE'] = 'Happy-dv.settings'

# Import the CGIHandler class
from wsgiref.handlers import CGIHandler

# Run the application using the CGIHandler
CGIHandler().run(application)
try:
    import wsgiref.handlers
    from denisevreden.wsgi import application
    wsgiref.handlers.CGIHandler().run(application)


except Exception as err:
    print("Content-Typ: text/html\n\n")
    print(err)

dependencies.py 文件:

#!/usr/bin/python3
import os
import sys
#!/usr/bin/env python
import os
import sys

# Add the path to the Django project to the system path
sys.path.append('/mnt/web315/a3/18/512337018/htdocs/.cgi-bin/Happy-dv')

# Set the environment variable to tell Django where the settings module is
os.environ['DJANGO_SETTINGS_MODULE'] = 'Happy-dv.settings'

# Import the CGIHandler class
from wsgiref.handlers import CGIHandler

# Run the application using the CGIHandler
CGIHandler().run(application)
try:
    import wsgiref.handlers
    from denisevreden.wsgi import application
    wsgiref.handlers.CGIHandler().run(application)


except Exception as err:
    print("Content-Typ: text/html\n\n")
    print(err)

谢谢

Django 部署 CGI

评论

0赞 nigel239 9/28/2023
嘿!我使用strato。你用的是他们的什么服务?我敢肯定他们支持的不仅仅是 CGI。如果您只是使用普通的托管包,也许最好投资 VPS,这样您就可以感受到真实的服务器环境,并以相同的价格加载更多部署选项。如果您只是在尝试,可以尝试云服务,他们为您提供 X 数量的免费积分。
0赞 nigel239 9/28/2023
哦,对不起,要回答你的其他一些问题(CGI是一个痛苦的屁股,所以不是这个.):你可以用以下命令设置密钥:,允许的主机应该设置为你要使用的所有域,这应该是一个列表。export DJANGO_SECRET_KEY="my-super-secure-key"["www.example.com", "example.com"]
0赞 Revero 9/28/2023
我正在使用托管基本计划。你认为有必要制定更高的计划吗?也许您可以稍微指导我在 strato 上完成此部署。
0赞 nigel239 9/30/2023
如果您已经发送了消息,请回复此消息。想想看,我们的邮件网关可能已经阻止了它。我们封锁了很多。;)
0赞 Revero 9/30/2023
刚刚给你发了一封电子邮件。如果没有什么东西能联系到你,请告诉我。谢谢

答:

0赞 nigel239 11/1/2023 #1

有一个 CGI 脚本可用于 Django。
然而,这确实有一些严重的缺点。
因为CGI的工作方式;每次发出请求时,它都会生成一个新进程。 这基本上意味着它将在每个请求上启动 django。 它还可能具有一些严重的安全隐患;如上所列。

CGI软件有可能产生一些巨大的安全漏洞 在您的系统上。如果它们被粗心地编程,它们允许 在互联网上将 Unix 命令输入到表单中的恶人 并让它们在您的 Web 服务器上执行。本文介绍了 确保 CGI 软件安全的基础知识。

撇开这一点不谈;该脚本在以下 GitHub 存储库中公开发布:https://github.com/chibiegg/django-cgi/blob/master/django-python3.cgi

回购相当旧;所以我不能保证它会开箱即用。

#!/home/user/.pyenv/versions/envname/bin/python
# encoding: utf-8
"""
django-.cgi

A simple cgi script which uses the django WSGI to serve requests.

Code copy/pasted from PEP-0333 and then tweaked to serve django.
http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side

This script assumes django is on your sys.path, and that your site code is at
/djangoproject/src. Copy this script into your cgi-bin directory (or do
whatever you need to to make a cgi script executable on your system), and then
update the paths at the bottom of this file to suit your site.

This is probably the slowest way to serve django pages, as the python
interpreter, the django code-base and your site code has to be loaded every
time a request is served. FCGI and mod_python solve this problem, use them if
you can.

In order to speed things up it may be worth experimenting with running
uncompressed zips on the sys.path for django and the site code, as this can be
(theorectically) faster. See PEP-0273 (specifically Benchmarks).
http://www.python.org/dev/peps/pep-0273/

Make sure all python files are compiled in your code base. See
http://docs.python.org/lib/module-compileall.html

"""


import os, sys

# Change this to the directory above your site code.
# sys.path.append("/home/user/local/lib/python3.4/site-packages")
# sys.path.append("/djangoproject/src")

def run_with_cgi(application):

    environ                      = dict(os.environ.items())
    environ['wsgi.input']        = sys.stdin.buffer
    environ['wsgi.errors']       = sys.stderr.buffer
    environ['wsgi.version']      = (1,0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True

    if environ.get('HTTPS','off') in ('on','1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    headers_set  = []
    headers_sent = []

    def write(data):
        if not headers_set:
             raise AssertionError("write() before start_response()")

        elif not headers_sent:
             # Before the first output, send the stored headers
             status, response_headers = headers_sent[:] = headers_set
             sys.stdout.buffer.write(('Status: %s\r\n' % status).encode("ascii"))
             for header in response_headers:
                 sys.stdout.buffer.write(('%s: %s\r\n' % header).encode("ascii"))
             sys.stdout.buffer.write(('\r\n').encode("ascii"))

        sys.stdout.buffer.write(data)
        sys.stdout.buffer.flush()

    def start_response(status,response_headers,exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
            finally:
                exc_info = None     # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status,response_headers]
        return write

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result,'close'):
            result.close()

# Change to the name of your settings module
os.environ['DJANGO_SETTINGS_MODULE'] = 'application.settings'
from django.core.wsgi import get_wsgi_application
run_with_cgi(get_wsgi_application())