Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Hosting a Django app with Caddy and PostgreSQL

From Nest Guides
Revision as of 13:16, 24 July 2025 by Twonum (talk | contribs) (source the venv)

THIS IS A WIP!

This (unofficial) guide was made by @twonum (feel free to ask me for help).

I'm using Hypercorn as it's an ASGI server (for WebSockets support). To use a different server, replace the hypercorn commands with the ones that your server uses.

Tools this guide uses
  • Hypercorn ASGI server
  • 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.sh
    • Caddyfile
    • .config
    • ...

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.app

Get 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_NAME

hackclub.app or custom domain?

$PROJECT_NAME.$USERNAME.hackclub.app (free)

export PROJECT_DOMAIN=$PROJECT_NAME.$USERNAME.hackclub.app
nest caddy add $PROJECT_DOMAIN

Custom 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 CNAME

Then:

nest caddy add $PROJECT_DOMAIN

Get your project's files on Nest

Copy the directory containing manage.py to /home/$USERNAME/$PROJECT_NAME. See Quickstart#Using_the_Account.

cd ~/$PROJECT_NAME

Set up venv and dependencies

python3 -m venv .venv
pip install -r requirements.txt

Set up Django settings

Use .env files with Django

Use a .env file. I'll use django-environ:

from environ import Env
...

env = Env(
    DEBUG=(bool, False),
)

...

DEBUG = env("DEBUG")
SECRET_KEY = env("SECRET_KEY")
DATABASES = {
    'default': env.db(),
}
...  # Use the same format for other options

What your .env file should look like

DEBUG=on
SECRET_KEY=please-change-this
DATABASE_URL=psql://$USERNAME:$NEST_PASSWORD@127.0.0.1:5432/$USERNAME_$PROJECT_NAME

Some 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

python3 manage.py migrate
python3 manage.py collectstatic

Set up Hypercorn

Get a port

nest get_port

Remember this number and store it in the mental variable $PORT.

Create the run script

~/$PROJECT_NAME.sh

#!/bin/bash
cd $PROJECT_NAME
source .venv/bin/activate
hypercorn -b 127.0.0.1:$PORT $PROJECT_NAME.asgi:application

Set 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.target

Start the service

systemctl --user daemon-reload
systemctl --user enable --now $PROJECT_NAME.service
systemctl --user status $PROJECT_NAME.service

Set up the Caddy server

~/Caddyfile

Append this:

https://$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.service