staging #2
14
README.md
14
README.md
@ -29,6 +29,8 @@ The file contains the following environment variables:
|
|||||||
|
|
||||||
```conf
|
```conf
|
||||||
TIMEZONE=Europe/Berlin
|
TIMEZONE=Europe/Berlin
|
||||||
|
DJANGO_DEBUG_MODE=false
|
||||||
|
DJANGO_SECRET_KEY=abc123mySecret
|
||||||
PG_NAME=medwings
|
PG_NAME=medwings
|
||||||
PG_USER=medwings
|
PG_USER=medwings
|
||||||
PG_PASSWORD=secret
|
PG_PASSWORD=secret
|
||||||
@ -46,9 +48,11 @@ You should set the values of the following variables:
|
|||||||
|
|
||||||
| variable | description | value |
|
| variable | description | value |
|
||||||
|----------|-------------|-------|
|
|----------|-------------|-------|
|
||||||
| PG_PASSWORD | password for the PostgreSQL admin user | a random string of 32 characters |
|
| DJANGO_DEBUG_MODE | whether or not to enable Django's debug mode | 'true' during development and 'false' in production |
|
||||||
| GOTIFY_USER | name of the Gotify admin user | a random string of 32 characters |
|
| DJANGO_SECRET_KEY | private session secret | a random string of 64 characters or more |
|
||||||
| GOTIFY_PASSWORD | password for the Gotify admin user | a random string of 32 characters |
|
| PG_PASSWORD | password for the PostgreSQL admin user | a random string of 32 characters or more |
|
||||||
|
| GOTIFY_USER | name of the Gotify admin user | a random string of 32 characters or more |
|
||||||
|
| GOTIFY_PASSWORD | password for the Gotify admin user | a random string of 32 characters or more |
|
||||||
| GOTIFY_PUBLIC_URL | URL where your public Gotify server can be reached | this depends on your deployment environment |
|
| GOTIFY_PUBLIC_URL | URL where your public Gotify server can be reached | this depends on your deployment environment |
|
||||||
| WITHINGS_CLIENT_ID | Your Withings API client id | see [Withings API](./app/withings/README.md#api-access) |
|
| WITHINGS_CLIENT_ID | Your Withings API client id | see [Withings API](./app/withings/README.md#api-access) |
|
||||||
| WITHINGS_CLIENT_SECRET | Your Withings API client secret | see [Withings API](./app/withings/README.md#api-access) |
|
| WITHINGS_CLIENT_SECRET | Your Withings API client secret | see [Withings API](./app/withings/README.md#api-access) |
|
||||||
@ -80,10 +84,10 @@ sudo docker exec -itu django medwings-django <command>
|
|||||||
Run database migrations inside the running container like so:
|
Run database migrations inside the running container like so:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo docker exec -itu medwings-django python manage.py migrate
|
sudo docker exec -itu django medwings-django python manage.py migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
To enter django's interactive shell, run:
|
To enter django's interactive shell, run:
|
||||||
```bash
|
```bash
|
||||||
sudo docker exec -itu medwings-django python manage.py shell
|
sudo docker exec -itu django medwings-django python manage.py shell
|
||||||
```
|
```
|
||||||
|
@ -8,14 +8,18 @@
|
|||||||
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
||||||
<h2>Register</h2>
|
<h2>Register</h2>
|
||||||
<p>
|
<p>
|
||||||
Something something glad you're signing up.
|
We're thrilled that you're taking the next step towards a healthier future by signing up for Medwings!
|
||||||
|
By linking your Withings account, we can seamlessly integrate your health data with Medwings.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col gap-2 items-center call-to-action-box">
|
<div class="flex flex-col gap-2 items-center call-to-action-box">
|
||||||
<p class="font-semibold">To get started, please allow us to access your health data</p>
|
<p class="font-semibold">To get started, please allow us to access your health data</p>
|
||||||
<a class="btn text-lg" href="{{ auth_url }}">Link Withings Account</a>
|
<a class="btn text-lg" href="{{ auth_url }}">Link Withings Account</a>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Something something why this is necessary.
|
The registration process will continue after you've linked your Withings account.
|
||||||
|
This step is essential as it allows Medwings to securely access your health data from the Withings cloud.
|
||||||
|
We use OAuth2, a standard and secure method, to ensure that your personal data remains private and under your control.+
|
||||||
|
Once your accounts are linked, you'll be all set to start exploring your health data and insights through Medwings.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -12,6 +12,7 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from os import getenv
|
from os import getenv
|
||||||
|
from .utils import parse_string_as_bool
|
||||||
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
@ -21,14 +22,17 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure-s^q)z%f-7=1h5b00ctki2*-w=#3!k@p-#sq%=eajw)x2axx-e5'
|
SECRET_KEY = getenv('DJANGO_SECRET_KEY')
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = parse_string_as_bool(getenv('DJANGO_DEBUG_MODE', 'false'))
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [ '*' ]
|
||||||
'localhost',
|
|
||||||
'127.0.0.1',
|
# Force HttpRequest.build_absolute_uri() to generate HTTPS links in production
|
||||||
'192.168.2.141'
|
# This is necessary when running behind a reverse proxy
|
||||||
]
|
#USE_X_FORWARDED_HOST = False if DEBUG else True
|
||||||
|
#SECURE_PROXY_SSL_HEADER = () if DEBUG else ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
USE_X_FORWARDED_HOST = True
|
||||||
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
@ -80,8 +84,8 @@ DATABASES = {
|
|||||||
'ENGINE': 'django.db.backends.postgresql',
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
'NAME': getenv('PG_NAME', 'medwings'),
|
'NAME': getenv('PG_NAME', 'medwings'),
|
||||||
'USER': getenv('PG_USER', 'medwings'),
|
'USER': getenv('PG_USER', 'medwings'),
|
||||||
'PASSWORD': getenv('PG_PASSWORD', 'medwings'),
|
'PASSWORD': getenv('PG_PASSWORD'),
|
||||||
'HOST': getenv('PG_HOST', 'medwings-postgres'),
|
'HOST': getenv('PG_HOST'),
|
||||||
'PORT': getenv('PG_PORT', '5432'),
|
'PORT': getenv('PG_PORT', '5432'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,6 +126,7 @@ STATIC_URL = 'static/'
|
|||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [
|
||||||
BASE_DIR / 'static',
|
BASE_DIR / 'static',
|
||||||
]
|
]
|
||||||
|
STATIC_ROOT = '/srv/static'
|
||||||
|
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
|
27
app/core/utils.py
Normal file
27
app/core/utils.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""Miscellaneous utility functions."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def parse_string_as_bool(value: str) -> bool:
|
||||||
|
"""Parses the given string into a boolean based on its content.
|
||||||
|
|
||||||
|
This is used to parse environment variables as boolean values.
|
||||||
|
|
||||||
|
The following strings are parsed as `True`: "yes", "Yes", "YES", "true", "True", "TRUE", "1"
|
||||||
|
The following strings are parsed as `False`: "no", "No", "NO", "false", "False", "FALSE", "0"
|
||||||
|
|
||||||
|
In any other case, a `ValueError` is raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(value, str):
|
||||||
|
raise TypeError("Expected a string argument.")
|
||||||
|
|
||||||
|
regex_true = re.compile(r"^(YES)|(Yes)|(yes)|(TRUE)|(True)|(true)|(1)$")
|
||||||
|
regex_false = re.compile(r"^(NO)|(No)|(no)|(FALSE)|(False)|(false)|(0)$")
|
||||||
|
|
||||||
|
if regex_true.fullmatch(value):
|
||||||
|
return True
|
||||||
|
if regex_false.fullmatch(value):
|
||||||
|
return False
|
||||||
|
raise ValueError(f"Failed to parse the supplied value as a boolean: {value!r}")
|
@ -1,9 +1,11 @@
|
|||||||
asgiref==3.7.2
|
asgiref==3.7.2
|
||||||
certifi==2023.7.22
|
certifi==2023.7.22
|
||||||
charset-normalizer==3.2.0
|
charset-normalizer==3.2.0
|
||||||
|
click==8.1.6
|
||||||
Django==4.2.3
|
Django==4.2.3
|
||||||
django-widget-tweaks==1.4.12
|
django-widget-tweaks==1.4.12
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
|
h11==0.14.0
|
||||||
idna==3.4
|
idna==3.4
|
||||||
psycopg==3.1.9
|
psycopg==3.1.9
|
||||||
psycopg-binary==3.1.9
|
psycopg-binary==3.1.9
|
||||||
@ -12,3 +14,4 @@ requests==2.31.0
|
|||||||
sqlparse==0.4.4
|
sqlparse==0.4.4
|
||||||
typing_extensions==4.7.1
|
typing_extensions==4.7.1
|
||||||
urllib3==2.0.4
|
urllib3==2.0.4
|
||||||
|
uvicorn==0.23.2
|
||||||
|
10
development.Caddyfile
Normal file
10
development.Caddyfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
:8000 {
|
||||||
|
handle * {
|
||||||
|
reverse_proxy * medwings-django:8000
|
||||||
|
}
|
||||||
|
|
||||||
|
log {
|
||||||
|
output stderr
|
||||||
|
format console
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ RUN addgroup --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
|||||||
|
|
||||||
# Copy caddy config
|
# Copy caddy config
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} Caddyfile /app/
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} development.Caddyfile /app/Caddyfile
|
||||||
|
|
||||||
# Run Caddy in development mode
|
# Run Caddy in development mode
|
||||||
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
|
@ -26,7 +26,7 @@ services:
|
|||||||
- ${PG_HOST}
|
- ${PG_HOST}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./development.django.Dockerfile
|
dockerfile: development.django.Dockerfile
|
||||||
args:
|
args:
|
||||||
CUSTOM_UID: 1000
|
CUSTOM_UID: 1000
|
||||||
CUSTOM_GID: 1000
|
CUSTOM_GID: 1000
|
||||||
|
21
production.Caddyfile
Normal file
21
production.Caddyfile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
servers {
|
||||||
|
trusted_proxies static private_ranges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:8000 {
|
||||||
|
handle_path /static/* {
|
||||||
|
root * /srv/static
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
handle * {
|
||||||
|
reverse_proxy * medwings-django:8000
|
||||||
|
}
|
||||||
|
|
||||||
|
log {
|
||||||
|
output stderr
|
||||||
|
format console
|
||||||
|
}
|
||||||
|
}
|
25
production.caddy.Dockerfile
Normal file
25
production.caddy.Dockerfile
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Install caddy
|
||||||
|
RUN apk add --no-cache caddy
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
ARG CUSTOM_UID
|
||||||
|
ARG CUSTOM_GID
|
||||||
|
ENV CUSTOM_USERNAME=webserver
|
||||||
|
ENV CUSTOM_GROUPNAME=webserver
|
||||||
|
RUN addgroup --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
adduser --uid ${CUSTOM_UID:-1000} --shell /bin/ash ${CUSTOM_USERNAME} --ingroup ${CUSTOM_GROUPNAME} --disabled-password && \
|
||||||
|
mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app && chmod 700 /app && \
|
||||||
|
mkdir -p /srv/static && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /srv/static && chmod 700 /srv/static
|
||||||
|
|
||||||
|
# Copy caddy config
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} production.Caddyfile /app/Caddyfile
|
||||||
|
|
||||||
|
# Run Caddy in development mode
|
||||||
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
|
EXPOSE 8000
|
||||||
|
ENTRYPOINT ["caddy", "run", "--config", "/app/Caddyfile", "--adapter", "caddyfile"]
|
35
production.django.Dockerfile
Normal file
35
production.django.Dockerfile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM python:alpine
|
||||||
|
|
||||||
|
# Install cron daemon and supervisord
|
||||||
|
RUN apk add --no-cache dcron supervisor
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
ARG CUSTOM_UID
|
||||||
|
ARG CUSTOM_GID
|
||||||
|
ENV CUSTOM_USERNAME=django
|
||||||
|
ENV CUSTOM_GROUPNAME=django
|
||||||
|
RUN addgroup --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
adduser --uid ${CUSTOM_UID:-1000} --shell /bin/ash ${CUSTOM_USERNAME} --ingroup ${CUSTOM_GROUPNAME} --disabled-password && \
|
||||||
|
mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app && chmod 700 /app && \
|
||||||
|
mkdir -p /srv/static && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /srv/static && chmod 700 /srv/static
|
||||||
|
ENV PATH "$PATH:/home/${CUSTOM_GROUPNAME}/.local/bin"
|
||||||
|
|
||||||
|
# Add supervisord conf
|
||||||
|
COPY production.supervisord.conf /etc/supervisord.conf
|
||||||
|
|
||||||
|
# Add cron job
|
||||||
|
COPY --chmod=600 django.crontab /etc/crontabs/django
|
||||||
|
|
||||||
|
# Copy source files
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} app/ /app/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Run supervisord
|
||||||
|
EXPOSE 8000/tcp
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
||||||
|
#CMD ["uvicorn", "core.asgi:application", "--host", "0.0.0.0", "--port", "8000", "--access-log"]
|
114
production.docker-compose.yml
Normal file
114
production.docker-compose.yml
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
medwings-caddy:
|
||||||
|
container_name: medwings-caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: production.caddy.Dockerfile
|
||||||
|
args:
|
||||||
|
CUSTOM_UID: 1000
|
||||||
|
CUSTOM_GID: 1000
|
||||||
|
expose:
|
||||||
|
- "8000"
|
||||||
|
networks:
|
||||||
|
- medwings
|
||||||
|
- proxy
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE}
|
||||||
|
volumes:
|
||||||
|
- /srv/medwings/static:/srv/static:ro
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.medwings.entrypoints=https"
|
||||||
|
- "traefik.http.routers.medwings.rule=Host(`medwings.lobbes.dev`)"
|
||||||
|
- "traefik.http.routers.medwings.middlewares=default@file"
|
||||||
|
- "traefik.http.routers.medwings.tls=true"
|
||||||
|
- "traefik.http.services.medwings.loadbalancer.server.port=8000"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
medwings-django:
|
||||||
|
container_name: medwings-django
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- medwings-caddy
|
||||||
|
- ${PG_HOST}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: production.django.Dockerfile
|
||||||
|
args:
|
||||||
|
CUSTOM_UID: 1000
|
||||||
|
CUSTOM_GID: 1000
|
||||||
|
expose:
|
||||||
|
- "8000"
|
||||||
|
networks:
|
||||||
|
- medwings
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE}
|
||||||
|
DJANGO_DEBUG_MODE: ${DJANGO_DEBUG_MODE}
|
||||||
|
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
|
||||||
|
PG_NAME: ${PG_NAME}
|
||||||
|
PG_USER: ${PG_USER}
|
||||||
|
PG_PASSWORD: ${PG_PASSWORD}
|
||||||
|
PG_HOST: ${PG_HOST}
|
||||||
|
PG_PORT: ${PG_PORT}
|
||||||
|
WITHINGS_CLIENT_ID: ${WITHINGS_CLIENT_ID}
|
||||||
|
WITHINGS_CLIENT_SECRET: ${WITHINGS_CLIENT_SECRET}
|
||||||
|
GOTIFY_USER: ${GOTIFY_USER}
|
||||||
|
GOTIFY_PASSWORD: ${GOTIFY_PASSWORD}
|
||||||
|
GOTIFY_HOST: ${GOTIFY_HOST}
|
||||||
|
GOTIFY_PUBLIC_URL: ${GOTIFY_PUBLIC_URL}
|
||||||
|
volumes:
|
||||||
|
- /srv/medwings/static:/srv/static
|
||||||
|
medwings-postgres:
|
||||||
|
image: postgres:alpine
|
||||||
|
container_name: ${PG_HOST}
|
||||||
|
restart: unless-stopped
|
||||||
|
expose:
|
||||||
|
- ${PG_PORT}
|
||||||
|
networks:
|
||||||
|
- medwings
|
||||||
|
volumes:
|
||||||
|
- /srv/medwings/db:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${PG_NAME}
|
||||||
|
POSTGRES_USER: ${PG_USER}
|
||||||
|
POSTGRES_PASSWORD: ${PG_PASSWORD}
|
||||||
|
TZ: ${TIMEZONE}
|
||||||
|
medwings-gotify:
|
||||||
|
image: gotify/server
|
||||||
|
container_name: medwings-gotify
|
||||||
|
restart: unless-stopped
|
||||||
|
expose:
|
||||||
|
- "80"
|
||||||
|
networks:
|
||||||
|
- medwings
|
||||||
|
- proxy
|
||||||
|
volumes:
|
||||||
|
- /srv/medwings/gotify:/app/data
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE}
|
||||||
|
GOTIFY_SERVER_SSL_REDIRECTTOHTTPS: false
|
||||||
|
GOTIFY_DEFAULTUSER_NAME: ${GOTIFY_USER}
|
||||||
|
GOTIFY_DEFAULTUSER_PASS: ${GOTIFY_PASSWORD}
|
||||||
|
GOTIFY_SERVER_CORS_ALLOWORIGINS: "- \"medwings-django:8000\"\n- \"medwings-notifications.lobbes.dev\"\n- \"medwings.lobbes.dev\""
|
||||||
|
GOTIFY_SERVER_CORS_ALLOWMETHODS: "- \"GET\"\n- \"POST\""
|
||||||
|
GOTIFY_SERVER_CORS_ALLOWHEADERS: "- \"Authorization\"\n- \"content-type\""
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.medwings-notifications.entrypoints=https"
|
||||||
|
- "traefik.http.routers.medwings-notifications.rule=Host(`medwings-notifications.lobbes.dev`)"
|
||||||
|
- "traefik.http.routers.medwings-notifications.middlewares=default@file"
|
||||||
|
- "traefik.http.routers.medwings-notifications.tls=true"
|
||||||
|
- "traefik.http.services.medwings-notifications.loadbalancer.server.port=80"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
medwings:
|
||||||
|
external: false
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
...
|
17
production.supervisord.conf
Normal file
17
production.supervisord.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
|
||||||
|
[program:django]
|
||||||
|
command=sh -c 'uvicorn core.asgi:application --host 0.0.0.0 --port 8000 --access-log'
|
||||||
|
directory=/app
|
||||||
|
user=django
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:crond]
|
||||||
|
command=crond -f
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
redirect_stderr=true
|
Loading…
x
Reference in New Issue
Block a user