aboutsummaryrefslogtreecommitdiff
path: root/web_interface
diff options
context:
space:
mode:
authoruser@node5.net <user@node5.net>2025-12-07 17:23:21 +0100
committeruser@node5.net <user@node5.net>2025-12-07 17:23:21 +0100
commitf92874002dfe8477c97bce5c7c1564a707f09075 (patch)
tree99f9a8408e8963d97ce78cfd533f6d78210301fc /web_interface
parentb00da901a46b0710ad8bd29522e33bed2c4a1c77 (diff)
Prod setup works
Diffstat (limited to 'web_interface')
-rw-r--r--web_interface/README.md15
-rw-r--r--web_interface/drinks_machine/settings.py37
-rw-r--r--web_interface/misc/prod_configs/drinks-machine.service13
-rw-r--r--web_interface/misc/prod_configs/drinks_machine_nginx.conf42
-rw-r--r--web_interface/pyproject.toml11
-rw-r--r--web_interface/uv.lock42
6 files changed, 142 insertions, 18 deletions
diff --git a/web_interface/README.md b/web_interface/README.md
index 418ba3b..5342e4d 100644
--- a/web_interface/README.md
+++ b/web_interface/README.md
@@ -2,11 +2,24 @@
## Setup & running
-### Dev setup & running
+### Setup dev
1. [Download nix](https://nixos.org/download/)
2. Run: `nix-shell --command make`
+
+### Setup prod
+
+```bash
+python3 -m venv venv
+source venv/bin/activate
+pip install .[prod]
+./manage.py collectstatic
+sudo ln -sr misc/prod_configs/drinks_machine_nginx.conf /etc/nginx/sites-enabled/
+sudo ln -sr misc/prod_configs/drinks-machine.service /etc/systemd/system/
+sudo systemctl daemon-reload
+```
+
![ER Diagram](../docs/diagrams/ER.svg)
## TODO
diff --git a/web_interface/drinks_machine/settings.py b/web_interface/drinks_machine/settings.py
index 098254d..738e5ba 100644
--- a/web_interface/drinks_machine/settings.py
+++ b/web_interface/drinks_machine/settings.py
@@ -13,6 +13,8 @@ https://docs.djangoproject.com/en/6.0/ref/settings/
from pathlib import Path
import os
+from django.core.management.utils import get_random_secret_key
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -24,13 +26,33 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'django-insecure-m(z7kz1$nf)4r^uu^0t#o4&5kxvvotpw0#!e(^=womt&4e=@^8'
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+# Define the path to your secret key file inside the .secrets folder
+secret_key_file = os.path.join(BASE_DIR, '.secrets', 'secret_key.txt')
+
+# Ensure the .secrets directory exists
+os.makedirs(os.path.dirname(secret_key_file), exist_ok=True)
-ALLOWED_HOSTS = []
+# Check if the file exists
+if not os.path.exists(secret_key_file):
+ # Generate a new secret key
+ secret_key = get_random_secret_key()
+ # Save the secret key to the file
+ with open(secret_key_file, 'w') as f:
+ f.write(secret_key)
+else:
+ # Read the secret key from the file
+ with open(secret_key_file, 'r') as f:
+ secret_key = f.read().strip()
+
+# Set the SECRET_KEY setting
+SECRET_KEY = secret_key
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = "DEBUG" in os.environ and os.environ["DEBUG"] == "INSECURE"
+
+ALLOWED_HOSTS = ['drinks-machine.node5.net']
# Application definition
@@ -120,9 +142,6 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
-STATIC_URL = 'static/'
-
-STATICFILES_DIRS = [
- BASE_DIR / "static",
-]
+STATIC_URL = '/static/'
+STATIC_ROOT = os.path.join(BASE_DIR, "static")
diff --git a/web_interface/misc/prod_configs/drinks-machine.service b/web_interface/misc/prod_configs/drinks-machine.service
new file mode 100644
index 0000000..a13ce0c
--- /dev/null
+++ b/web_interface/misc/prod_configs/drinks-machine.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=uWSGI instance to serve drinks machine web interface
+After=network.target
+
+[Service]
+User=drinks
+Group=www-data
+WorkingDirectory=/opt/drinks_machine/web_interface
+Environment="PATH=/opt/drinks_machine/web_interface/venv/bin"
+ExecStart=/opt/drinks_machine/web_interface/venv/bin/gunicorn --bind unix:/tmp/drinks-machine.sock drinks_machine.wsgi --log-level debug
+
+[Install]
+WantedBy=multi-user.target
diff --git a/web_interface/misc/prod_configs/drinks_machine_nginx.conf b/web_interface/misc/prod_configs/drinks_machine_nginx.conf
new file mode 100644
index 0000000..959a5f3
--- /dev/null
+++ b/web_interface/misc/prod_configs/drinks_machine_nginx.conf
@@ -0,0 +1,42 @@
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ ssl_certificate /etc/letsencrypt/live/node5.net-0001/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/node5.net-0001/privkey.pem;
+ server_name drinks-machine.node5.net;
+
+ location /static/ {
+ root /opt/drinks_machine/web_interface;
+ }
+
+ location /media/ {
+ root /opt/drinks_machine/web_interface;
+ }
+
+ location / {
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_pass_request_headers on;
+
+ proxy_pass http://unix:/tmp/drinks-machine.sock;
+ }
+
+ charset UTF-8;
+
+ error_page 404 /404.html;
+}
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name drinks-machine.node5.net www.drinks-machine.node5.net;
+
+ return 301 https://$host$request_uri;
+
+ return 404;
+
+
+}
diff --git a/web_interface/pyproject.toml b/web_interface/pyproject.toml
index cf7cc36..90b92ec 100644
--- a/web_interface/pyproject.toml
+++ b/web_interface/pyproject.toml
@@ -2,10 +2,10 @@
name = "drinks-machine"
version = "0.1.0"
dependencies = [
- "Django==6.0",
+ "Django==5.2.9",
"django-colorfield==0.14.0"
]
-requires-python = ">=3.12"
+requires-python = ">=3.11.2"
authors = [
]
maintainers = [
@@ -13,7 +13,14 @@ maintainers = [
description = "Webinterface for the drinks machine"
readme = "README.md"
+[tool.setuptools]
+py-modules = []
+
[project.optional-dependencies]
dev = [
]
+prod = [
+ "gunicorn==23.0.0"
+]
+
diff --git a/web_interface/uv.lock b/web_interface/uv.lock
index e6bd3a6..ebc283f 100644
--- a/web_interface/uv.lock
+++ b/web_interface/uv.lock
@@ -1,6 +1,6 @@
version = 1
revision = 2
-requires-python = ">=3.12"
+requires-python = ">=3.11.2"
[[package]]
name = "asgiref"
@@ -13,16 +13,16 @@ wheels = [
[[package]]
name = "django"
-version = "6.0"
+version = "5.2.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/15/75/19762bfc4ea556c303d9af8e36f0cd910ab17dff6c8774644314427a2120/django-6.0.tar.gz", hash = "sha256:7b0c1f50c0759bbe6331c6a39c89ae022a84672674aeda908784617ef47d8e26", size = 10932418, upload-time = "2025-12-03T16:26:21.878Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/eb/1c/188ce85ee380f714b704283013434976df8d3a2df8e735221a02605b6794/django-5.2.9.tar.gz", hash = "sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495", size = 10848762, upload-time = "2025-12-02T14:01:08.418Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d7/ae/f19e24789a5ad852670d6885f5480f5e5895576945fcc01817dfd9bc002a/django-6.0-py3-none-any.whl", hash = "sha256:1cc2c7344303bbfb7ba5070487c17f7fc0b7174bbb0a38cebf03c675f5f19b6d", size = 8339181, upload-time = "2025-12-03T16:26:16.231Z" },
+ { url = "https://files.pythonhosted.org/packages/17/b0/7f42bfc38b8f19b78546d47147e083ed06e12fc29c42da95655e0962c6c2/django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a", size = 8290652, upload-time = "2025-12-02T14:01:03.485Z" },
]
[[package]]
@@ -46,12 +46,18 @@ dependencies = [
{ name = "django-colorfield" },
]
+[package.optional-dependencies]
+prod = [
+ { name = "uwsgi" },
+]
+
[package.metadata]
requires-dist = [
- { name = "django", specifier = "==6.0" },
+ { name = "django", specifier = "==5.2.9" },
{ name = "django-colorfield", specifier = "==0.14.0" },
+ { name = "uwsgi", marker = "extra == 'prod'", specifier = "==2.0.31" },
]
-provides-extras = ["dev"]
+provides-extras = ["dev", "prod"]
[[package]]
name = "pillow"
@@ -59,6 +65,17 @@ version = "12.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" }
wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798, upload-time = "2025-10-15T18:21:47.763Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589, upload-time = "2025-10-15T18:21:49.515Z" },
+ { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472, upload-time = "2025-10-15T18:21:51.052Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887, upload-time = "2025-10-15T18:21:52.604Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964, upload-time = "2025-10-15T18:21:54.619Z" },
+ { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756, upload-time = "2025-10-15T18:21:56.151Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075, upload-time = "2025-10-15T18:21:57.759Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955, upload-time = "2025-10-15T18:21:59.372Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440, upload-time = "2025-10-15T18:22:00.982Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256, upload-time = "2025-10-15T18:22:02.617Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025, upload-time = "2025-10-15T18:22:04.598Z" },
{ url = "https://files.pythonhosted.org/packages/2c/90/4fcce2c22caf044e660a198d740e7fbc14395619e3cb1abad12192c0826c/pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371", size = 5249377, upload-time = "2025-10-15T18:22:05.993Z" },
{ url = "https://files.pythonhosted.org/packages/fd/e0/ed960067543d080691d47d6938ebccbf3976a931c9567ab2fbfab983a5dd/pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082", size = 4650343, upload-time = "2025-10-15T18:22:07.718Z" },
{ url = "https://files.pythonhosted.org/packages/e7/a1/f81fdeddcb99c044bf7d6faa47e12850f13cee0849537a7d27eeab5534d4/pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f", size = 6232981, upload-time = "2025-10-15T18:22:09.287Z" },
@@ -120,6 +137,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" },
{ url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" },
{ url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068, upload-time = "2025-10-15T18:23:59.594Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994, upload-time = "2025-10-15T18:24:01.669Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639, upload-time = "2025-10-15T18:24:03.403Z" },
+ { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839, upload-time = "2025-10-15T18:24:05.344Z" },
+ { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505, upload-time = "2025-10-15T18:24:07.137Z" },
+ { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654, upload-time = "2025-10-15T18:24:09.579Z" },
+ { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850, upload-time = "2025-10-15T18:24:11.495Z" },
]
[[package]]
@@ -139,3 +163,9 @@ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be76
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
]
+
+[[package]]
+name = "uwsgi"
+version = "2.0.31"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9f/49/2f57640e889ba509fd1fae10cccec1b58972a07c2724486efba94c5ea448/uwsgi-2.0.31.tar.gz", hash = "sha256:e8f8b350ccc106ff93a65247b9136f529c14bf96b936ac5b264c6ff9d0c76257", size = 822796, upload-time = "2025-10-11T19:17:28.794Z" }