Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
COPY ./ ./

# Create directories.
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./hypha/media
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./media

# Build front end.
RUN npm run dev:build
Expand Down
20 changes: 20 additions & 0 deletions docker/prod/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
DJANGO_SETTINGS_MODULE="hypha.settings.production"
SECRET_KEY="changeme"

PRIMARY_HOST="https://test.hypha.app"
EMAIL_HOST="hypha.app"

EMAIL_SUBJECT_PREFIX="[Hypha]"
ORG_EMAIL="hello@hypha.app"
SERVER_EMAIL="test@hypha.app"

DATABASE_URL="postgres://hypha:hypha@postgres:5432/hypha"
POSTGRES_USER=hypha
POSTGRES_PASSWORD=hypha
POSTGRES_DB=hypha
POSTGRES_HOST=postgres
POSTGRES_PORT=5432

PYTHON_TIMEOUT=120
PYTHON_THREADS=4
PYTHON_WORKERS=2
42 changes: 32 additions & 10 deletions docker/prod/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ ENV UV_LINK_MODE=copy
# Set work directory.
WORKDIR /opt/app

# Create the hypha user and group
ARG APP_UID=1000
ARG APP_GID=1000
RUN groupadd -g "${APP_GID}" hypha \
&& useradd --create-home --no-log-init -u "${APP_UID}" -g "${APP_GID}" hypha \
&& chown hypha:hypha -R /opt/app

# Set user (default is otherwise root)
USER hypha

# Create directories.
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./hypha/media
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./media

# Install node.
COPY --from=node:24-slim /usr/local/bin /usr/local/bin
Expand All @@ -26,7 +36,7 @@ COPY --from=node:24-slim /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin

# Install node dependencies.
COPY package*.json ./
COPY --chown=hypha:hypha package*.json ./
RUN npm install --quiet

# Install python dependencies.
Expand All @@ -36,7 +46,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev

# Copy the project into the image
COPY ./ ./
COPY --chown=hypha:hypha ./ ./

# Build front end.
RUN npm run build && python manage.py collectstatic --noinput --verbosity=0
Expand All @@ -45,26 +55,38 @@ RUN npm run build && python manage.py collectstatic --noinput --verbosity=0
#
# Production stage.
#
FROM python:3.12-slim-bookworm
FROM python:3.12-slim-bookworm AS app

# Add venv/bin to PATH.
ENV PATH="/opt/app/.venv/bin:/usr/local/bin:$PATH"

# Set work directory.
WORKDIR /opt/app

# Create the hypha user and group
ARG APP_UID=1000
ARG APP_GID=1000
RUN groupadd -g "${APP_GID}" hypha \
&& useradd --create-home --no-log-init -u "${APP_UID}" -g "${APP_GID}" hypha \
&& chown hypha:hypha -R /opt/app

# Set user (default is otherwise root)
USER hypha

# Create directories.
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./hypha/media
RUN mkdir -p ./hypha/static_compiled && mkdir -p ./media

# Copy venv and assets from builder.
COPY --from=builder /opt/app/.venv /opt/app/.venv
COPY --from=builder /opt/app/static /opt/app/static
COPY --chown=hypha:hypha --from=builder /opt/app/.venv /opt/app/.venv
COPY --chown=hypha:hypha --from=builder /opt/app/static /opt/app/static

# Copy the project into the image
COPY ./ ./
COPY --chown=hypha:hypha ./ ./

# Run entrypoint.sh.
ENTRYPOINT ["/opt/app/docker/prod/entrypoint.sh"]

# Expose the port gunicorn is running on for other Docker containers.
EXPOSE 8000

# Run entrypoint.sh.
ENTRYPOINT ["/opt/app/docker/prod/entrypoint.sh"]
CMD ["gunicorn", "--config", "/opt/app/docker/prod/config/gunicorn.py"]
17 changes: 17 additions & 0 deletions docker/prod/config/gunicorn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import multiprocessing
import os

wsgi_app = "hypha.wsgi:application"
bind = "0.0.0.0:8000"

errorlog = "-" # '-' logs to stderr
accesslog = "-" # '-' logs to stdout
access_log_format = (
"%(h)s %(l)s %(u)s %(t)s '%(r)s' %(s)s %(b)s '%(f)s' '%(a)s' in %(D)sµs" # noqa: E501
)

worker_tmp_dir = "/dev/shm"
worker_class = "gthread"
workers = int(os.getenv("PYTHON_WORKERS", multiprocessing.cpu_count() * 2))
threads = int(os.getenv("PYTHON_THREADS", 1))
timeout = int(os.getenv("PYTHON_TIMEOUT", 120))
3 changes: 0 additions & 3 deletions docker/prod/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@ python manage.py migrate --noinput
python manage.py clear_cache --cache=default
python manage.py sync_roles

# Start gunicorn server.
gunicorn hypha.wsgi:application --env DJANGO_SETTINGS_MODULE=hypha.settings.production --worker-tmp-dir /dev/shm --workers=2 --threads=4 --worker-class=gthread --bind 0.0.0.0:8000

exec "$@"
Loading