How to Serve Django Admin and API on Separate Subdomains

sanju saini
3 min readOct 7, 2024

--

‘Separating Django’s Admin panel and API on different subdomains can provide added security, cleaner organization, and more manageable scaling. In this guide, we’ll configure a Django project to run the Admin panel on one subdomain, such as admin.example.com, and the API on another, such as api.example.com. Using Django’s routing along with Nginx as a reverse proxy, this setup offers flexibility and security for your project.

Why Separate Admin and API?

  1. Enhanced Security: Isolating the Admin panel from the main API reduces exposure to potential security threats.
  2. Easier Scaling: Separating components allows for targeted scaling. For instance, you can prioritize scaling the API under high user demand while isolating the admin.
  3. Organized Management: With different domains, users can easily differentiate between API and admin endpoints, reducing the chance of accidental access.

Step 1: Set Up Django Settings

1.1 Add Subdomains to ALLOWED_HOSTS

In Django’s settings.py, define the subdomains that will host the Admin panel and API. This allows Django to serve requests only from these specific domains.

# settings.py
ALLOWED_HOSTS = ['api.example.com', 'admin.example.com']

1.2 Configure Separate URL Patterns for Admin and API

Let’s create dedicated URL configuration files for both the Admin panel and API. This way, each subdomain will direct requests to a specific set of routes.

  1. Create Admin and API URL Files
  • Admin URLs (admin_urls.py):
# admin_urls.py
from django.contrib import admin
from django.urls import path

urlpatterns = [
path('admin/', admin.site.urls), # Admin route
]
  • API URLs (api_urls.py):
# api_urls.py
from django.urls import path, include

urlpatterns = [
path('v1/', include('your_app.api_urls')), # API routes
]

2. Main urls.py Configuration
In the primary urls.py file, conditionally include admin_urls or api_urls based on the subdomain in use. To do this, set a HOST variable that captures the incoming request’s subdomain.

# urls.py
from django.conf import settings
from django.urls import include, path

urlpatterns = []

# Determine which URLs to serve based on HOST setting
if settings.HOST == 'admin':
urlpatterns += [
path('', include('project_name.admin_urls')),
]
elif settings.HOST == 'api':
urlpatterns += [
path('', include('project_name.api_urls')),
]

1.3 Dynamic HOST Assignment

To capture and use the request’s subdomain, modify wsgi.py (or asgi.py for ASGI deployments). Here, we’ll set the HOST environment variable based on the incoming request’s subdomain, which we’ll use in urls.py for routing.

# wsgi.py (or asgi.py)
import os
from django.core.wsgi import get_wsgi_application

def application(environ, start_response):
os.environ['DJANGO_SETTINGS_MODULE'] = 'project_name.settings'
os.environ['HOST'] = environ['HTTP_HOST'].split('.')[0] # Set host based on subdomain
return get_wsgi_application()(environ, start_response)

Step 2: Configure Nginx for Subdomain Routing

To properly route requests to the correct Django views, use Nginx to set up reverse proxies that will direct requests from admin.example.com to the Django admin interface and api.example.com to the API.

2.1 Define Server Blocks for Each Subdomain

  1. Admin Subdomain Configuration
    Create a new Nginx configuration file for the Admin panel:
# /etc/nginx/sites-available/admin.example.com
server {
listen 80;
server_name admin.example.com;

location / {
proxy_pass http://127.0.0.1:8000; # Local Django server
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. API Subdomain Configuration
    Create another configuration file for the API:
# /etc/nginx/sites-available/api.example.com
server {
listen 80;
server_name api.example.com;

location / {
proxy_pass http://127.0.0.1:8000; # Same Django app instance
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;
}
}

2.2 Enable Nginx Configuration

To activate these configurations, create symbolic links from sites-available to sites-enabled:

sudo ln -s /etc/nginx/sites-available/admin.example.com /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled

Afterward, test the Nginx configuration to ensure no syntax errors, then reload Nginx.

sudo nginx -t
sudo systemctl reload nginx

Step 3: Verify the Setup

Once Django and Nginx are configured, you can test the setup by accessing each subdomain:

  1. Visit admin.example.com/admin/ to check the Admin panel.
  2. Test the API endpoints at api.example.com/v1/.

If both subdomains resolve to the correct routes, your setup is complete! This configuration enhances security, scalability, and manageability for your Django project.

Conclusion

Setting up Django to serve Admin and API on separate subdomains is a smart approach for applications that demand modularity and security. This guide provided step-by-step instructions for configuring Django and Nginx to achieve a seamless, subdomain-based routing structure. Now you can maintain clean, separated routes for your Admin and API, each of which can scale and secure independently.

--

--

sanju saini
sanju saini

Written by sanju saini

Senior Software Engineer with 4.5+ years of experience in full-stack development, specializing in Python, Golang, PHP, Django, FastAPI, React, and RESTful APIs.

No responses yet