Skip to content

Commit a52652b

Browse files
Copilotpirus99
andcommitted
Add dedicated nginx static-server for Django admin and DRF static files
- Created static-server with nginx to serve /static files - Reverted urls.py to remove static() helper (Django no longer serves static files) - Reverted entrypoint.sh to remove collectstatic command - Updated Traefik routing: /static now routes to static-server instead of backend - Backend routes only /api and /admin paths - Static files collected during backend build and shared via volume - Added wget to static-server for health checks Co-authored-by: pirus99 <206077632+pirus99@users.noreply.github.com>
1 parent 8e8cf24 commit a52652b

File tree

5 files changed

+95
-16
lines changed

5 files changed

+95
-16
lines changed

backend/core/urls.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
"""
1717
from django.contrib import admin
1818
from django.urls import path, include
19-
from django.conf import settings
20-
from django.conf.urls.static import static
2119

2220
urlpatterns = [
2321
path('admin/', admin.site.urls),
@@ -26,10 +24,3 @@
2624
path('api/v1/auth/', include('user_auth_app.api.urls')),
2725
path('api-auth', include('rest_framework.urls')),
2826
]
29-
30-
# Serve static files in production
31-
# Note: This serves Django admin and DRF static files through Django.
32-
# For high-traffic production, consider using WhiteNoise middleware or
33-
# configuring nginx/CDN to serve static files directly.
34-
if not settings.DEBUG:
35-
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

backend/entrypoint.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ echo "Starting entrypoint script..."
66
# Wait a bit for any database to be ready (useful for PostgreSQL/MySQL in the future)
77
sleep 2
88

9-
# Collect static files to the volume-mounted directory
10-
echo "Collecting static files..."
11-
python manage.py collectstatic --noinput --clear
12-
139
# Run database migrations
1410
echo "Running database migrations..."
1511
python manage.py migrate --noinput

docker-compose.yml

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ services:
6969
- web
7070
labels:
7171
- "traefik.enable=true"
72-
# HTTP router - backend accessible at /api/, /admin/, and /static/ paths on main domain
73-
- "traefik.http.routers.backend.rule=Host(`${DOMAIN:-localhost}`) && (PathPrefix(`/api`) || PathPrefix(`/admin`) || PathPrefix(`/static`))"
72+
# HTTP router - backend accessible at /api/ and /admin/ paths on main domain
73+
- "traefik.http.routers.backend.rule=Host(`${DOMAIN:-localhost}`) && (PathPrefix(`/api`) || PathPrefix(`/admin`))"
7474
- "traefik.http.routers.backend.entrypoints=web"
7575
- "traefik.http.routers.backend.priority=100"
7676
- "traefik.http.services.backend.loadbalancer.server.port=8000"
7777
# HTTPS router - uses Traefik default certificate (or Let's Encrypt if configured)
78-
- "traefik.http.routers.backend-secure.rule=Host(`${DOMAIN:-localhost}`) && (PathPrefix(`/api`) || PathPrefix(`/admin`) || PathPrefix(`/static`))"
78+
- "traefik.http.routers.backend-secure.rule=Host(`${DOMAIN:-localhost}`) && (PathPrefix(`/api`) || PathPrefix(`/admin`))"
7979
- "traefik.http.routers.backend-secure.entrypoints=websecure"
8080
- "traefik.http.routers.backend-secure.priority=100"
8181
- "traefik.http.routers.backend-secure.tls=true"
@@ -88,6 +88,40 @@ services:
8888
retries: 3
8989
start_period: 40s
9090

91+
# Static Server - Serves Django admin and DRF static files
92+
static-server:
93+
build:
94+
context: ./static-server
95+
dockerfile: Dockerfile
96+
container_name: join-static-server
97+
restart: unless-stopped
98+
volumes:
99+
- backend-static:/usr/share/nginx/html/static:ro
100+
networks:
101+
- web
102+
labels:
103+
- "traefik.enable=true"
104+
# HTTP router - serves /static/ path
105+
- "traefik.http.routers.static-server.rule=Host(`${DOMAIN:-localhost}`) && PathPrefix(`/static`)"
106+
- "traefik.http.routers.static-server.entrypoints=web"
107+
- "traefik.http.routers.static-server.priority=100"
108+
- "traefik.http.services.static-server.loadbalancer.server.port=80"
109+
# HTTPS router - uses Traefik default certificate (or Let's Encrypt if configured)
110+
- "traefik.http.routers.static-server-secure.rule=Host(`${DOMAIN:-localhost}`) && PathPrefix(`/static`)"
111+
- "traefik.http.routers.static-server-secure.entrypoints=websecure"
112+
- "traefik.http.routers.static-server-secure.priority=100"
113+
- "traefik.http.routers.static-server-secure.tls=true"
114+
# Uncomment the next line to use Let's Encrypt instead of Traefik default certificate
115+
# - "traefik.http.routers.static-server-secure.tls.certresolver=letsencrypt"
116+
healthcheck:
117+
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
118+
interval: 30s
119+
timeout: 10s
120+
retries: 3
121+
start_period: 10s
122+
depends_on:
123+
- backend
124+
91125
# Frontend - Angular Application
92126
frontend:
93127
build:

static-server/Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Static Server Dockerfile - Serves Django admin and DRF static files
2+
FROM nginx:alpine
3+
4+
# Install wget for health checks
5+
RUN apk add --no-cache wget
6+
7+
# Copy nginx configuration
8+
COPY nginx.conf /etc/nginx/conf.d/default.conf
9+
10+
# Create directory for static files
11+
RUN mkdir -p /usr/share/nginx/html/static
12+
13+
# The static files will be copied from the backend build stage
14+
# This is done in docker-compose.yml using a shared volume
15+
16+
# Expose port
17+
EXPOSE 80
18+
19+
CMD ["nginx", "-g", "daemon off;"]

static-server/nginx.conf

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
server {
2+
listen 80;
3+
server_name localhost;
4+
root /usr/share/nginx/html;
5+
6+
# Gzip compression
7+
gzip on;
8+
gzip_vary on;
9+
gzip_min_length 10240;
10+
gzip_proxied expired no-cache no-store private auth;
11+
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
12+
13+
# Security headers
14+
add_header X-Frame-Options "SAMEORIGIN" always;
15+
add_header X-Content-Type-Options "nosniff" always;
16+
add_header X-XSS-Protection "1; mode=block" always;
17+
18+
# Serve static files from /static path
19+
location /static/ {
20+
alias /usr/share/nginx/html/static/;
21+
expires 1y;
22+
add_header Cache-Control "public, immutable";
23+
24+
# Handle missing files gracefully
25+
try_files $uri $uri/ =404;
26+
}
27+
28+
# Health check endpoint
29+
location /health {
30+
access_log off;
31+
return 200 "healthy\n";
32+
add_header Content-Type text/plain;
33+
}
34+
35+
# Return 404 for all other paths
36+
location / {
37+
return 404;
38+
}
39+
}

0 commit comments

Comments
 (0)