More actions
No edit summary |
|||
| (5 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
This (unofficial) guide was made by [https://hackclub.slack.com/team/U094NTBR1S5 @twonum] (feel free to <abbr title="Dungeon Master</joke>Direct Message">DM</abbr> me for help). | This (unofficial) guide was made by [https://hackclub.slack.com/team/U094NTBR1S5 @twonum] (feel free to <abbr title="Dungeon Master</joke>Direct Message">DM</abbr> me for help). | ||
This guide works with all [https://docs.djangoproject.com/en/5.2/howto/deployment/ WSGI and ASGI servers] <em><strong>that is not</strong> Django's built-in [https://docs.djangoproject.com/en/5.2/ref/django-admin/#django-admin-runserver {{code|runserver}}] command</em>. | |||
; Tools this guide uses | ; Tools this guide uses | ||
* Hypercorn ASGI | * A [https://docs.djangoproject.com/en/5.2/howto/deployment/ WSGI and ASGI server] <em><strong>that is not</strong> Django's built-in [https://docs.djangoproject.com/en/5.2/ref/django-admin/#django-admin-runserver {{code|runserver}}] command</em> | ||
** I'll be using Hypercorn but this works with all WSGI/ASGI servers. | |||
* Caddy reverse proxy and web server with automatic HTTPS | * Caddy reverse proxy and web server with automatic HTTPS | ||
* PostgreSQL relational database for Django's ORM | * PostgreSQL relational database for Django's ORM | ||
| Line 78: | Line 77: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Also, install | Also, install {{code|psycopg}} and your WSGI/ASGI server. | ||
psycopg | |||
== Set up Django settings == | == Set up Django settings == | ||
| Line 114: | Line 109: | ||
DEBUG = env("DEBUG") | DEBUG = env("DEBUG") | ||
ALLOWED_HOSTS = env('ALLOWED_HOSTS') | ALLOWED_HOSTS = env('ALLOWED_HOSTS') | ||
CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS] | |||
SECRET_KEY = env("SECRET_KEY") | SECRET_KEY = env("SECRET_KEY") | ||
DATABASES = { | DATABASES = { | ||
| Line 149: | Line 145: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Set up | == Set up the WSGI/ASGI server == | ||
=== Get a port === | === Get a port === | ||
| Line 171: | Line 167: | ||
cd ~/$PROJECT_NAME | cd ~/$PROJECT_NAME | ||
source .venv/bin/activate | source .venv/bin/activate | ||
# WSGI/ASGI server command | |||
</syntaxhighlight> | |||
Add your WSGI or ASGI server's command. Bind it to {{code|127.0.0.1:$PORT}} with the application name of {{code|$PACKAGE_NAME.wsgi.application}} for WSGI and {{code|$PACKAGE_NAME.asgi:application}} for ASGI. See the [https://docs.djangoproject.com/en/5.2/howto/deployment/ Django deployment page] for info about servers. | |||
===== Example for Hypercorn ===== | |||
<syntaxhighlight lang="bash"> | |||
hypercorn -b 127.0.0.1:$PORT $PACKAGE_NAME.asgi:application | hypercorn -b 127.0.0.1:$PORT $PACKAGE_NAME.asgi:application | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Latest revision as of 03:00, 25 July 2025
This (unofficial) guide was made by @twonum (feel free to DM me for help).
This guide works with all WSGI and ASGI servers that is not Django's built-in runserver command.
- Tools this guide uses
- A WSGI and ASGI server that is not Django's built-in
runservercommand- I'll be using Hypercorn but this works with all WSGI/ASGI servers.
- Caddy reverse proxy and web server with automatic HTTPS
- PostgreSQL relational database for Django's ORM
- systemd "daemon" (as it's called in Unix) to manage services
I'll assume that orpheus is your username and this is your directory structure:
- ~ (/home/orpheus)
- project
- .venv
- manage.py
- ...
- static
- project
- static
- media
- project
- project.sh
- Caddyfile
- .config
- ...
- project
I'll use $THIS_VARIABLE_NOTATION. Make a mental note of exports and replace the pseudo-variables with actual values.
Getting ready
First, get a shell to Nest. Don't have a Nest account?
ssh orpheus@hackclub.appGet Nest resources
export PROJECT_NAME="your project directory name" # set this to your project's directory name (like "project" in /home/$USERNAME/project)
nest db create $PROJECT_NAMEhackclub.app or custom domain?
$PROJECT_NAME.$USERNAME.hackclub.app (free)
export PROJECT_DOMAIN=$PROJECT_NAME.$USERNAME.hackclub.app
nest caddy add $PROJECT_DOMAINCustom domain (looks better, but you need your own DNS)
Add a CNAME record to $USERNAME.hackclub.app.
If you use Cloudflare or another proxy, turn the proxy off.
Wait and run this to check your DNS record:
export PROJECT_DOMAIN="hello.example.com" # set this
dig $PROJECT_DOMAIN CNAMEThen:
nest caddy add $PROJECT_DOMAINGet your project's files on Nest
Copy the directory containing manage.py to /home/$USERNAME/$PROJECT_NAME. See Quickstart#Using_the_Account.
cd ~/$PROJECT_NAMESet up venv and dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtAlso, install psycopg and your WSGI/ASGI server.
Set up Django settings
Use .env files with Django
Use a .env file. I'll use django-environ:
from pathlib import Path
import os
from environ import Env
...
env = Env(
DEBUG=(bool, False),
ALLOWED_HOSTS=(list, []),
)
BASE_DIR = Path(__file__).resolve().parent.parent
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
def _env_file(key: str) -> str:
env_ = env(key)
if env_[:2] == './':
return str(BASE_DIR / env_[2:])
return str(Path(env_))
...
DEBUG = env("DEBUG")
ALLOWED_HOSTS = env('ALLOWED_HOSTS')
CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS]
SECRET_KEY = env("SECRET_KEY")
DATABASES = {
'default': env.db(),
}
STATIC_URL = env("STATIC_URL")
STATIC_ROOT = _env_file("STATIC_ROOT")
MEDIA_URL = env("MEDIA_URL")
MEDIA_ROOT = _env_file("MEDIA_ROOT")
... # Use the same format for other optionsWhat your .env file should look like
DEBUG=False
ALLOWED_HOSTS=$PROJECT_DOMAIN
SECRET_KEY=please-change-this
DATABASE_URL=psql://$USERNAME:$NEST_PASSWORD@127.0.0.1:5432/$USERNAME_$PROJECT_NAMESome other options to tweak
STATIC_ROOT=$HOME/static/$PROJECT_NAME/static
STATIC_URL=/static/
MEDIA_ROOT=$HOME/static/$PROJECT_NAME/media
MEDIA_URL=/media/Migration and static collection
source .env
python3 manage.py migrate
python3 manage.py collectstaticSet up the WSGI/ASGI server
Get a port
nest get_portRemember this number and store it in the mental variable $PORT.
From my experience, the port might get taken quickly. In that case, just get a new port and change the old one in existing files.
This is the internal port (on Nest); the actual application uses port 443 (the standard HTTPS port).
Create the run script
~/$PROJECT_NAME.sh
$PACKAGE_NAME is the name of the directory with settings.py.
#!/bin/bash
cd ~/$PROJECT_NAME
source .venv/bin/activate
# WSGI/ASGI server commandAdd your WSGI or ASGI server's command. Bind it to 127.0.0.1:$PORT with the application name of $PACKAGE_NAME.wsgi.application for WSGI and $PACKAGE_NAME.asgi:application for ASGI. See the Django deployment page for info about servers.
Example for Hypercorn
hypercorn -b 127.0.0.1:$PORT $PACKAGE_NAME.asgi:applicationSet up systemd with the run script
~/.config/systemd/user/$PROJECT_NAME.service
[Unit]
Description=YOUR DESCRIPTION HERE
[Service]
WorkingDirectory=%h/$PROJECT_NAME
EnvironmentFile=%h/$PROJECT_NAME/.env
ExecStart=bash ../$PROJECT_NAME.sh
Restart=on-failure
[Install]
WantedBy=default.targetStart the service
systemctl --user daemon-reload
systemctl --user enable --now $PROJECT_NAME.service
systemctl --user status $PROJECT_NAME.serviceSet up the Caddy server
~/Caddyfile
Append this:
http://$PROJECT_DOMAIN {
bind unix/.$PROJECT_DOMAIN.webserver.sock|777
handle /static* {
root * $HOME/static/$PROJECT_NAME
file_server
}
handle /media* {
root * $HOME/static/$PROJECT_NAME
file_server
}
reverse_proxy :$PORT
}Restart Caddy service
systemctl --user restart caddy.serviceCheck it out
Go to $PROJECT_DOMAIN in your browser.
First load takes some time as Caddy needs to get a certificate from Let's Encrypt.
It should probably work. If not, please Dungeon Master @twonum who is at fault for writing this guide.
Avoiding hiccups
Make sure that it continues to work; if not, there's probably something wrong with the config.