Upgrading GeoSquare to latest Django

When trying to play with the latest fasthtml framework launched recently, I did not want to use a service provider like vercel or railway and wanted to deploy on my ec2 instance at Amazon. The problem was my current django apps that host geosq.com were running very old versions of python(I know, I know)

Previous setup

uWSGI was running as emperor and had multiple Django apps that were all Python 2.7

Current Setup

The main goal for this go-around is to isolate each app under its own environment. Each of the sites will have its own service so they can be started and shutdown individually

The file to host the individual django app will be

First create a conda environment

conda create -n geosq python=3.11

Install the required packages

conda activate geosq
pip install django
pip install mysqlclient

Then create a service

sudo vi /etc/systemd/system/gunicorn_geosq.service 
[Unit]
Description=Gunicorn daemon for geosq Django application
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/geosq
ExecStart=/home/ubuntu/miniconda3/envs/geosq/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/geosq/geosq.sock geosq.wsgi:application

[Install]
WantedBy=multi-user.target

Reload the daemon

sudo sudo systemctl daemon-reload

Bring up the service

sudo systemctl start gunicorn_geosq

Check status

sudo systemctl status gunicorn_geosq

If everything is good, enable so it starts at boot time

sudo systemctl enable gunicorn_geosq

Django code Upgrade

I used mostly Claude 3.5 Sonnet to quickly port from the old Django to the lastest version. The only tricky part was to create a local test database when upgrading locally on my Mac. For this I used sqlite in dev and using an environment variable to connect to MySql in prod.

The database configuration would be driven by DEBUG variable

DEBUG = os.environ.get('DJANGO_DEBUG', 'True') == 'True'

# Database configuration
if DEBUG:
    # Development database (SQLite)
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'geosq.sqlite3',
        }
    }
else:
    # Production database (MySQL)
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': os.environ.get('DB_NAME', 'yourdatabasename'),
            'USER': os.environ.get('DB_USERNAME', 'yourusername'),
            'PASSWORD': os.environ.get('DB_PASSWORD', 'yourpassword'),
            'HOST': os.environ.get('DB_HOST', ''),
            'PORT': os.environ.get('DB_PORT', ''),
        }
    }

This way I could test the functionality before migrating to production.

nginx and Gunicorn

When you start Gunicorn service for GeoSquare, It will create a sock file which needs to be presented to nginx so it can route the traffic. Here is how I did it. In addition you can serve static files using nginx which is much more efficient than python, so you would intercept any /static GET calls and serve them directly.

server {
    server_name www.geosq.com;
    
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/ubuntu/geosq;
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://unix:/home/ubuntu/geosq/geosq.sock;
    }

    listen 80;
}
By: Gavi Narra on: