Skip to content
Open
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
46 changes: 46 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Git
.git
.gitignore

# Python
__pycache__
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
env.bak/
venv.bak/
*.egg-info/
.pytest_cache/
.coverage
htmlcov/

# Django
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
/static_root/
/media_root/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Vagrant
.vagrant/
Vagrantfile

# Deployment
deploy/
*.sql
54 changes: 54 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Use Python 3.11 slim image as base
FROM python:3.11-slim-bookworm
Comment on lines +1 to +2
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The base requirements pin Django to <3.3 (Django 3.2.x), which is not compatible with Python 3.11 per Django’s supported Python versions. This image is likely to fail at runtime or during dependency install; either use a Python 3.10 base image or upgrade Django (and any deps) to a version that supports 3.11.

Suggested change
# Use Python 3.11 slim image as base
FROM python:3.11-slim-bookworm
# Use Python 3.10 slim image as base (compatible with Django 3.2.x)
FROM python:3.10-slim-bookworm

Copilot uses AI. Check for mistakes.

# Set environment variables
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
g++ \
make \
libpq-dev \
postgresql-client \
gdal-bin \
libgdal-dev \
libproj-dev \
proj-bin \
binutils \
libspatialindex-dev \
git \
&& rm -rf /var/lib/apt/lists/*

# Set work directory
WORKDIR /app

# Copy requirements and install Python dependencies
COPY requirements.txt /app/
RUN pip install --upgrade pip && \
pip install -r requirements.txt

# Copy project files
COPY . /app/

# Copy and set entrypoint script
COPY docker-entrypoint.sh /app/
Comment on lines +37 to +38
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COPY . /app/ already brings docker-entrypoint.sh into the image, so the later COPY docker-entrypoint.sh /app/ is redundant and can cause confusion when editing. Consider removing one of the copies (typically keep the explicit copy and move it before COPY . if you want better layer caching).

Suggested change
# Copy and set entrypoint script
COPY docker-entrypoint.sh /app/
# Set entrypoint script as executable

Copilot uses AI. Check for mistakes.
RUN chmod +x /app/docker-entrypoint.sh

# Create necessary directories
RUN mkdir -p /app/bluepages/static_root /app/bluepages/media_root

# Set working directory to Django project
WORKDIR /app/bluepages

# Expose port
EXPOSE 8000

# Use entrypoint script
ENTRYPOINT ["/app/docker-entrypoint.sh"]

# Default command (can be overridden in docker-compose)
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
18 changes: 18 additions & 0 deletions README.docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Docker Setup for WC Bluepages

## Quick Start

### Pre-requisites

- Have a dump of the database called `db_dump.sql` in the `wcbluepages` directory. This is necessary to alter the tables to the expected form until the migrations work correctly.

### 1. Build and start the containers:

```bash
docker-compose up --build
```

### 2. Access the application:

- Web application: http://localhost:8000
- Admin interface: http://localhost:8000/admin
28 changes: 28 additions & 0 deletions bluepages/bluepages/docker_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Docker-specific settings that override base settings.py
This file is imported at the end of settings.py when running in Docker.
"""
import os

# Database configuration from environment variables
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': os.environ.get('DB_NAME', 'bluepages'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD', 'postgres'),
'HOST': os.environ.get('DB_HOST', 'db'),
'PORT': os.environ.get('DB_PORT', '5432'),
}
}

# Debug mode from environment
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEBUG = os.environ.get('DEBUG', 'False') == 'True' is case-sensitive and treats values like true/1/yes as False, which is easy to misconfigure. Consider using a more robust boolean parser (e.g., normalize to lowercase and accept common truthy values).

Suggested change
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
DEBUG = os.environ.get('DEBUG', 'False').strip().lower() in ('true', '1', 'yes', 'y', 'on')

Copilot uses AI. Check for mistakes.

# Allow all hosts in Docker (configure properly for production)
ALLOWED_HOSTS = ['*']
Comment on lines +22 to +23
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting ALLOWED_HOSTS = ['*'] makes the container accept requests for any Host header, which is unsafe if the port is ever exposed beyond localhost (e.g., on a shared network). Prefer restricting to local/dev hosts (localhost/127.0.0.1/0.0.0.0) or making this configurable via an env var.

Suggested change
# Allow all hosts in Docker (configure properly for production)
ALLOWED_HOSTS = ['*']
# Allowed hosts: configurable via env, with safe local defaults
_allowed_hosts_env = os.environ.get('DJANGO_ALLOWED_HOSTS')
if _allowed_hosts_env:
ALLOWED_HOSTS = [h.strip() for h in _allowed_hosts_env.split(',') if h.strip()]
else:
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']

Copilot uses AI. Check for mistakes.

# Static and media files
STATIC_ROOT = '/app/bluepages/static_root'
MEDIA_ROOT = '/app/bluepages/media_root'
MEDIA_URL = '/media/'
11 changes: 10 additions & 1 deletion bluepages/bluepages/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,13 @@
from .local_settings import *
except Exception as e:
print("Unable to import local_settings")
pass
pass
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary 'pass' statement.

Copilot uses AI. Check for mistakes.

# Import Docker settings if running in Docker
if os.environ.get('DOCKER_CONTAINER'):
try:
from .docker_settings import *
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import pollutes the enclosing namespace, as the imported module bluepages.docker_settings does not define 'all'.

Copilot uses AI. Check for mistakes.
print("Docker settings loaded")
except Exception as e:
print(f"Unable to import docker_settings: {e}")
pass
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary 'pass' statement.

Copilot uses AI. Check for mistakes.
48 changes: 48 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
services:
db:
image: postgis/postgis:16-3.4
platform: linux/amd64
container_name: bluepages_db
Comment on lines +3 to +5
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding platform: linux/amd64 reduces portability (e.g., Apple Silicon will run under emulation, slower; some setups may fail). If this is only needed for specific environments, consider making it optional/configurable (e.g., via an env var) or documenting why it’s required.

Copilot uses AI. Check for mistakes.
environment:
POSTGRES_DB: bluepages
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db_dump.sql:/tmp/db_dump.sql:ro
- ./init-db.sh:/docker-entrypoint-initdb.d/01-init-db.sh:ro
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

web:
build: .
container_name: bluepages_web
volumes:
- .:/app
- static_volume:/app/bluepages/static_root
- media_volume:/app/bluepages/media_root
ports:
- "8000:8000"
environment:
- DOCKER_CONTAINER=1
- DEBUG=True
- DB_NAME=bluepages
- DB_USER=postgres
- DB_PASSWORD=postgres
- DB_HOST=db
- DB_PORT=5432
depends_on:
db:
condition: service_healthy
stdin_open: true
tty: true

volumes:
postgres_data:
static_volume:
media_volume:
17 changes: 17 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
set -e

echo "Waiting for PostgreSQL..."
while ! pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" > /dev/null 2>&1; do
sleep 1
done
Comment on lines +4 to +7
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PostgreSQL wait loop has no timeout, so a misconfigured DB_* env or an unavailable database will hang the container indefinitely. Add a max retry count / deadline and exit non-zero with a clear error when exceeded.

Copilot uses AI. Check for mistakes.
echo "PostgreSQL is ready!"

echo "Running database migrations..."
python manage.py migrate --noinput

echo "Collecting static files..."
python manage.py collectstatic --noinput

echo "Starting server..."
exec "$@"
12 changes: 12 additions & 0 deletions init-db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

# This script runs automatically when the PostgreSQL container is first initialized
# It will only run if the database is empty (first time setup)

echo "Importing database dump..."

# Import the SQL dump, ignoring meta-command errors
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=0 < /tmp/db_dump.sql
Comment on lines +9 to +10
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using -v ON_ERROR_STOP=0 will continue on SQL errors and can silently produce a partially imported/corrupt initial database. Since this runs on first init of an empty DB, it’s safer to stop on the first error (ON_ERROR_STOP=1) and fail the container startup, or explicitly handle only expected errors.

Suggested change
# Import the SQL dump, ignoring meta-command errors
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=0 < /tmp/db_dump.sql
# Import the SQL dump, stopping on the first error to avoid partial/corrupt state
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 < /tmp/db_dump.sql

Copilot uses AI. Check for mistakes.

echo "Database import completed!"
Loading