Merge branch 'fix-docker' of https://github.com/horilla-opensource/Horilla into fix-docker
This commit is contained in:
@@ -1,33 +1,89 @@
|
||||
# Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
media/
|
||||
staticfiles/
|
||||
static_root/
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv/
|
||||
venv/
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# VCS
|
||||
.git/
|
||||
.gitignore
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
|
||||
# OS files
|
||||
# MacOS
|
||||
.DS_Store
|
||||
|
||||
# Node
|
||||
node_modules/
|
||||
|
||||
# Django static/media
|
||||
staticfiles/
|
||||
media/
|
||||
|
||||
# Bytecode & caches
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
docker-compose.yml
|
||||
.vscode
|
||||
.idea
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.pytest_cache/
|
||||
|
||||
# Docker
|
||||
.wheels/
|
||||
__pycache__
|
||||
.pytest_cache
|
||||
.coverage
|
||||
*.log
|
||||
.env
|
||||
horillavenv
|
||||
node_modules
|
||||
.DS_Store
|
||||
|
||||
19
.env.example
Normal file
19
.env.example
Normal file
@@ -0,0 +1,19 @@
|
||||
# Django
|
||||
DJANGO_SETTINGS_MODULE=horilla.settings
|
||||
SECRET_KEY=change-me
|
||||
DEBUG=False
|
||||
ALLOWED_HOSTS=*
|
||||
|
||||
# Database (used by compose to form DATABASE_URL)
|
||||
POSTGRES_DB=horilla
|
||||
POSTGRES_USER=horilla
|
||||
POSTGRES_PASSWORD=horilla
|
||||
|
||||
# Optional: storage/other
|
||||
# AWS_ACCESS_KEY_ID=
|
||||
# AWS_SECRET_ACCESS_KEY=
|
||||
# AWS_STORAGE_BUCKET_NAME=
|
||||
|
||||
# Redis Cache
|
||||
REDIS_PASSWORD=horilla
|
||||
REDIS_URL=redis://:horilla@redis:6379/0
|
||||
114
Dockerfile
114
Dockerfile
@@ -1,65 +1,85 @@
|
||||
# Production Dockerfile (multi-stage) for Horilla v2.0
|
||||
# Builds Python wheels in a builder image, then installs them into a slim runtime.
|
||||
|
||||
FROM python:3.11-slim-bookworm AS builder
|
||||
# Build stage - for compiling dependencies
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
# System deps required to build certain Python packages and render PDFs/images
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
gcc \
|
||||
libffi-dev \
|
||||
libjpeg-dev \
|
||||
zlib1g-dev \
|
||||
libcairo2 \
|
||||
libpango-1.0-0 \
|
||||
libpangocairo-1.0-0 \
|
||||
libmagic1 \
|
||||
libssl-dev \
|
||||
gettext \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# Install build dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
libjpeg-dev \
|
||||
zlib1g-dev \
|
||||
libcairo2-dev \
|
||||
libpango1.0-dev \
|
||||
libgdk-pixbuf-xlib-2.0-dev \
|
||||
libxml2-dev \
|
||||
libxslt1-dev \
|
||||
libffi-dev \
|
||||
pkg-config \
|
||||
gcc \
|
||||
g++ \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
# Create virtual environment
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Leverage layer caching for deps
|
||||
COPY requirements.txt ./
|
||||
RUN python -m pip install --upgrade pip \
|
||||
&& pip wheel --no-cache-dir --no-deps -r requirements.txt -w /wheels
|
||||
# Install Python dependencies
|
||||
COPY requirements.txt .
|
||||
RUN pip install --upgrade pip \
|
||||
&& pip install --no-cache-dir -r requirements.txt gunicorn psycopg2-binary
|
||||
|
||||
# ---------------------------- Runtime image ----------------------------
|
||||
FROM python:3.11-slim-bookworm AS runtime
|
||||
# Production stage - minimal runtime image
|
||||
FROM python:3.12-slim as production
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Runtime libs only (no compilers)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libcairo2 \
|
||||
libpango-1.0-0 \
|
||||
libpangocairo-1.0-0 \
|
||||
libjpeg62-turbo \
|
||||
zlib1g \
|
||||
libmagic1 \
|
||||
libpq5 \
|
||||
gettext \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# Install only runtime dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libpq5 \
|
||||
libjpeg62-turbo \
|
||||
zlib1g \
|
||||
libcairo2 \
|
||||
libpango-1.0-0 \
|
||||
libgdk-pixbuf-xlib-2.0-0 \
|
||||
libxml2 \
|
||||
libxslt1.1 \
|
||||
libffi8 \
|
||||
curl \
|
||||
netcat-openbsd \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# Create non-root user
|
||||
RUN useradd --create-home --uid 1000 appuser
|
||||
|
||||
# Copy virtual environment from builder stage
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install built wheels
|
||||
COPY --from=builder /wheels /wheels
|
||||
RUN pip install --no-cache-dir /wheels/*
|
||||
# Copy application code
|
||||
COPY --chown=appuser:appuser . .
|
||||
|
||||
# Copy project source
|
||||
COPY . .
|
||||
# Copy entrypoint script
|
||||
COPY --chown=appuser:appuser docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Ensure entrypoint is executable
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
# Create necessary directories and set permissions
|
||||
RUN mkdir -p staticfiles media \
|
||||
&& chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# Entrypoint runs migrations, collectstatic, admin creation, and gunicorn
|
||||
CMD ["sh", "./entrypoint.sh"]
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/health/ || exit 1
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["gunicorn", "horilla.wsgi:application", "--config", "docker/gunicorn.conf.py"]
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# Development Dockerfile for Horilla v2.0
|
||||
# Includes compilers and dev tools, runs Django with autoreload.
|
||||
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
# Dev system dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
gcc \
|
||||
libffi-dev \
|
||||
libjpeg-dev \
|
||||
zlib1g-dev \
|
||||
libcairo2 \
|
||||
libpango-1.0-0 \
|
||||
libpangocairo-1.0-0 \
|
||||
libmagic1 \
|
||||
libssl-dev \
|
||||
gettext \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN python -m pip install --upgrade pip \
|
||||
&& pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# Use Django dev server; compose binds volumes for live reload
|
||||
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
||||
@@ -1,10 +0,0 @@
|
||||
import multiprocessing
|
||||
|
||||
bind = "0.0.0.0:8000"
|
||||
workers = max(2, multiprocessing.cpu_count() * 2 + 1)
|
||||
worker_class = "gthread"
|
||||
threads = 4
|
||||
accesslog = "-"
|
||||
errorlog = "-"
|
||||
loglevel = "info"
|
||||
keepalive = 120
|
||||
@@ -1,58 +0,0 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size 50m;
|
||||
|
||||
# Serve static files directly
|
||||
location /static/ {
|
||||
alias /staticfiles/;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
}
|
||||
|
||||
# Serve media files
|
||||
location /media/ {
|
||||
alias /media/;
|
||||
add_header Cache-Control "public, max-age=3600";
|
||||
}
|
||||
|
||||
# Proxy pass to Gunicorn
|
||||
location / {
|
||||
proxy_set_header Host $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_read_timeout 300s;
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_pass http://web:8000;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
name: horilla-dev
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:postgres@db:5432/horilla
|
||||
DEBUG: "true"
|
||||
CREATE_SUPERUSER: "true"
|
||||
volumes:
|
||||
- ./:/app
|
||||
- media:/app/media
|
||||
command: sh ./entrypoint.sh
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
db:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_DB: horilla
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- horilla-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
horilla-data:
|
||||
media:
|
||||
@@ -1,54 +0,0 @@
|
||||
name: horilla
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:postgres@db:5432/horilla
|
||||
CREATE_SUPERUSER: "true"
|
||||
command: sh ./entrypoint.sh
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- media:/app/media
|
||||
- staticfiles:/app/staticfiles
|
||||
|
||||
db:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_DB: horilla
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
# Expose DB only within the compose network (no host port)
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- horilla-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
web:
|
||||
condition: service_started
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- staticfiles:/staticfiles:ro
|
||||
- media:/media:ro
|
||||
|
||||
volumes:
|
||||
horilla-data:
|
||||
media:
|
||||
staticfiles:
|
||||
56
docker-compose.yml
Normal file
56
docker-compose.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- .:/app
|
||||
- staticfiles:/app/staticfiles
|
||||
- media:/app/media
|
||||
environment:
|
||||
- DEBUG=1
|
||||
- SECRET_KEY=dev-secret-key
|
||||
- ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
|
||||
- CSRF_TRUSTED_ORIGINS=http://localhost:8000
|
||||
- DATABASE_URL=postgres://horilla_user:horilla_pass@db:5432/horilla_db
|
||||
- REDIS_URL=redis://:horilla_pass@redis:6379/0
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_DB: horilla_db
|
||||
POSTGRES_USER: horilla_user
|
||||
POSTGRES_PASSWORD: horilla_pass
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --appendonly yes --requirepass horilla_pass
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- staticfiles:/static:ro
|
||||
- media:/media:ro
|
||||
- ./docker/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
depends_on:
|
||||
- web
|
||||
profiles: ["production"]
|
||||
|
||||
volumes:
|
||||
staticfiles:
|
||||
media:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
128
docker.md
128
docker.md
@@ -1,128 +0,0 @@
|
||||
## Horilla v2.0 Docker Guide
|
||||
|
||||
This guide explains how to run Horilla with Docker in development and production (Nginx + Gunicorn).
|
||||
|
||||
### Prerequisites
|
||||
- Docker 24+ and Docker Compose v2
|
||||
- 2 CPU / 2 GB RAM minimum recommended
|
||||
|
||||
### Project layout (Docker-related)
|
||||
- `Dockerfile`: Production multi-stage image (Python 3.11, slim)
|
||||
- `Dockerfile.dev`: Development image with compilers and auto-reload
|
||||
- `docker-compose.yaml`: Production stack (web + db + nginx)
|
||||
- `docker-compose.dev.yaml`: Development stack (web + db) with live reload
|
||||
- `deploy/nginx/nginx.conf`: Nginx reverse proxy config (serves `/static/` and `/media/`)
|
||||
- `deploy/gunicorn.conf.py`: Gunicorn config for production
|
||||
- `entrypoint.sh`: App lifecycle (migrate, collectstatic, start Gunicorn)
|
||||
- `.dockerignore`: Reduces build context
|
||||
|
||||
## Development
|
||||
|
||||
### Start
|
||||
```bash
|
||||
# Build and run (autoreload)
|
||||
docker compose -f docker-compose.dev.yaml up --build
|
||||
# Open the app
|
||||
open http://localhost:8000
|
||||
```
|
||||
|
||||
### Useful dev commands
|
||||
```bash
|
||||
# Shell into the web container
|
||||
docker compose -f docker-compose.dev.yaml exec web bash
|
||||
|
||||
# Run migrations
|
||||
docker compose -f docker-compose.dev.yaml exec web python manage.py migrate
|
||||
|
||||
# Create admin user (example)
|
||||
docker compose -f docker-compose.dev.yaml exec web \
|
||||
python manage.py createhorillauser \
|
||||
--first_name admin --last_name admin \
|
||||
--username admin --password admin \
|
||||
--email admin@example.com --phone 1234567890
|
||||
```
|
||||
|
||||
## Production (Nginx + Gunicorn)
|
||||
|
||||
### Start
|
||||
```bash
|
||||
# Build and start in the background
|
||||
docker compose up --build -d
|
||||
# Open the app (served by Nginx)
|
||||
open http://localhost
|
||||
```
|
||||
|
||||
### Services
|
||||
- `web`: Django app via Gunicorn on port 8000 (internal)
|
||||
- `db`: PostgreSQL 16 (internal only)
|
||||
- `nginx`: Reverse proxy on port 80; serves static and media directly
|
||||
|
||||
### Volumes
|
||||
- `staticfiles`: `collectstatic` output served at `/static/`
|
||||
- `media`: user uploads served at `/media/`
|
||||
- `horilla-data`: Postgres data
|
||||
|
||||
### Environment variables
|
||||
- `DATABASE_URL`: e.g. `postgres://postgres:postgres@db:5432/horilla`
|
||||
- `DEBUG`: should be `false` in production
|
||||
- `ALLOWED_HOSTS`: e.g. `["yourdomain.com"]`
|
||||
- `CSRF_TRUSTED_ORIGINS`: e.g. `["https://yourdomain.com"]`
|
||||
- `TIME_ZONE`: e.g. `Asia/Kolkata`
|
||||
- `SECRET_KEY`: set a strong value (read from `.env` by Django)
|
||||
|
||||
Django reads `.env` from the project root via `django-environ`. Create one if needed.
|
||||
|
||||
### Common operations
|
||||
```bash
|
||||
# View logs
|
||||
docker compose logs -f web
|
||||
|
||||
# Run management commands
|
||||
docker compose exec web python manage.py migrate
|
||||
docker compose exec web python manage.py collectstatic --noinput
|
||||
|
||||
# Create admin user
|
||||
docker compose exec web \
|
||||
python manage.py createhorillauser \
|
||||
--first_name admin --last_name admin \
|
||||
--username admin --password 'CHANGE_ME' \
|
||||
--email admin@example.com --phone 1234567890
|
||||
|
||||
# Stop the stack
|
||||
docker compose down
|
||||
```
|
||||
|
||||
### TLS (HTTPS)
|
||||
- Terminate TLS at Nginx. Provide your certs and update `deploy/nginx/nginx.conf` to listen on 443 and reference your certificate and key.
|
||||
- Then publish `443:443` in the `nginx` service and set `ALLOWED_HOSTS` and `CSRF_TRUSTED_ORIGINS` accordingly.
|
||||
|
||||
### Database backup/restore
|
||||
```bash
|
||||
# Backup (inside db container)
|
||||
docker compose exec db pg_dump -U postgres -d horilla > horilla_backup.sql
|
||||
|
||||
# Restore
|
||||
cat horilla_backup.sql | docker compose exec -T db psql -U postgres -d horilla
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- Static files not loading: ensure `collectstatic` ran successfully; check `staticfiles` volume is mounted to Nginx.
|
||||
- 502 from Nginx: check `web` logs and Gunicorn is listening on 0.0.0.0:8000.
|
||||
- CSRF/host errors: set `ALLOWED_HOSTS` and `CSRF_TRUSTED_ORIGINS` for your domain.
|
||||
- DB connection errors: confirm `DATABASE_URL` and that `db` service is healthy.
|
||||
- Permissions on `media`: ensure Docker user can write; by default, containers run as root in this setup.
|
||||
|
||||
## Upgrades
|
||||
```bash
|
||||
# Rebuild images after changes to requirements or Dockerfiles
|
||||
docker compose build --no-cache
|
||||
# Apply migrations
|
||||
docker compose exec web python manage.py migrate
|
||||
# Reload Nginx (if config changed)
|
||||
docker compose exec nginx nginx -s reload
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Production images are based on Python 3.11 slim and use a multi-stage build for smaller, reliable artifacts.
|
||||
- The database is not exposed to the host in production compose; connect from `web` or via `docker compose exec db psql`.
|
||||
- For multi-host deployments, consider externalizing Postgres and object storage (e.g., S3) via `django-storages`.
|
||||
20
docker/entrypoint.sh
Executable file
20
docker/entrypoint.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Starting Horilla HR..."
|
||||
|
||||
# Wait for PostgreSQL to be ready
|
||||
echo "Waiting for PostgreSQL..."
|
||||
while ! nc -z db 5432; do
|
||||
sleep 0.1
|
||||
done
|
||||
echo "PostgreSQL is ready!"
|
||||
|
||||
# Run migrations
|
||||
python manage.py migrate --noinput
|
||||
|
||||
# Collect static files
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
echo "Starting server..."
|
||||
exec "$@"
|
||||
45
docker/gunicorn.conf.py
Normal file
45
docker/gunicorn.conf.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Gunicorn configuration for Horilla-HR
|
||||
# This file provides advanced configuration options for the WSGI server
|
||||
|
||||
import os
|
||||
import multiprocessing
|
||||
|
||||
# Bind settings
|
||||
bind = f"0.0.0.0:{os.environ.get('PORT', '8000')}"
|
||||
host = "0.0.0.0"
|
||||
port = int(os.environ.get('PORT', '8000'))
|
||||
|
||||
# Worker settings
|
||||
workers = int(os.environ.get('GUNICORN_WORKERS', max(2, min(multiprocessing.cpu_count() * 2 + 1, 8))))
|
||||
worker_class = "gthread"
|
||||
threads = 4
|
||||
worker_connections = 1000
|
||||
max_requests = 1000
|
||||
max_requests_jitter = 50
|
||||
preload_app = True
|
||||
|
||||
# Timeout settings
|
||||
timeout = 120
|
||||
keepalive = 5
|
||||
|
||||
# Logging
|
||||
accesslog = "-"
|
||||
errorlog = "-"
|
||||
loglevel = os.environ.get('GUNICORN_LOG_LEVEL', 'info')
|
||||
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
||||
|
||||
# Process naming
|
||||
proc_name = "horilla-hrms"
|
||||
|
||||
# Server mechanics
|
||||
pidfile = "/tmp/gunicorn.pid"
|
||||
user = None # Run as current user in container
|
||||
group = None
|
||||
tmp_upload_dir = None
|
||||
|
||||
# Development settings
|
||||
reload = os.environ.get('GUNICORN_RELOAD', 'false').lower() == 'true'
|
||||
|
||||
# SSL settings (if needed)
|
||||
# ssl_keyfile = os.environ.get('SSL_KEYFILE')
|
||||
# ssl_certfile = os.environ.get('SSL_CERTFILE')
|
||||
31
docker/nginx.conf
Normal file
31
docker/nginx.conf
Normal file
@@ -0,0 +1,31 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
upstream django {
|
||||
server web:8000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
client_max_body_size 50M;
|
||||
|
||||
location /static/ {
|
||||
alias /static/;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /media/;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://django;
|
||||
proxy_set_header Host $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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Creating migrations..."
|
||||
python3 manage.py makemigrations
|
||||
|
||||
echo "Applying database migrations..."
|
||||
python3 manage.py migrate --noinput
|
||||
|
||||
echo "Collecting static files..."
|
||||
python3 manage.py collectstatic --noinput
|
||||
|
||||
echo "Compiling translations..."
|
||||
python3 manage.py compilemessages || true
|
||||
|
||||
echo "Starting Gunicorn..."
|
||||
exec gunicorn -c ./deploy/gunicorn.conf.py horilla.wsgi:application
|
||||
15844
package-lock.json
generated
15844
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "openhrms-core",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev":"npm run development",
|
||||
"development":"mix"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ArjunCybro/OpenHRMS-Dashboard.git"
|
||||
},
|
||||
"author": "OpenHRMS",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ArjunCybro/OpenHRMS-Dashboard/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ArjunCybro/OpenHRMS-Dashboard#readme",
|
||||
"devDependencies": {
|
||||
"laravel-mix": "^6.0.49"
|
||||
},
|
||||
"dependencies": {
|
||||
"alpinejs": "^3.10.5",
|
||||
"ionicons": "^7.1.0",
|
||||
"jquery": "^3.6.3",
|
||||
"jquery-ui": "^1.13.2",
|
||||
"jquery-ui-touch-punch": "^0.2.3",
|
||||
"js-datepicker": "^5.18.2",
|
||||
"select2": "^4.1.0-rc.0",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ drf-yasg
|
||||
et-xmlfile
|
||||
geopy
|
||||
google-api-python-client
|
||||
google-auth-oauthlib
|
||||
google-cloud-storage==3.0.0
|
||||
html5lib
|
||||
Jinja2
|
||||
|
||||
Reference in New Issue
Block a user