I have a website at cerulinux.com
that works great.
But then I introduced subdomains.
You click on the link for the page you want to have your subdomain pointed to, it shows the subdomain in the URL bar, but stays on the index page. Only when you click the same link for a second time, does it wake up and begrudging decide it's actually going to take you to said page.
You're now on said page, and it shows <subdomain>.<domain>/<subdomain>
in the address bar.
For example, I have a subdomain blog.cerulix.com
Now, when you go to another section of the website after having been on the page where the subdomain begrudgingly points to, apparently, Django seems to think that every single page can now be accessed by the one subdomain. All pages are now accessible via blog.<domain>/legal
or blog.<domain>/careers
or blog.<domain>/investors
.
- My website runs on a Linux server successfully via
Gunicorn
& via anapp.sock
- I have successfully routed my domain and my subdomain with A records to my server's IP address. This is confirmed by
nslookup <domain>.com
&nslookup blog.<domain>.com
- The host name of the subdomain set in my A records which was successfully routed to my server's IP address is
blog
.
Take the blog section as an example, and we will call my domain cerulix
.
The blog page is normally accessed via cerulix.com/blog
and a blog item will be accessed by cerulix.com/blog/<blog_name>
Pretty logical, right?
Here's my MRE
#settings.py ALLOWED_HOSTS = [ '127.0.0.1', 'cerulix.com', 'www.cerulix.com', 'blog.cerulix.com' ]
#main.urls from . import views from django.conf import settings from django.conf.urls.static import static from django.views.static import serve urlpatterns = [ # Other paths, # Other paths, path('blog/', include('blog.urls')), # Other paths, # Other paths, ]
#blog.urls from django.urls import path, from. import views urlpatterns = [ path('', views.blog, name="blog"), path('<slug:slug>', views.blog__details), ]
#index.html <a href = "{% url 'blog' %}" class="" title="Blog & Podcasts">Blog</a>
Linux Server Configurations
#django.conf # accessed via /etc/nginx/sites-available$ and linked to sites-enabled # HTTP - Redirect www → non-www (safe & specific) server { listen 80; server_name www.cerulix.com; return 301 https://cerulix.com$request_uri; } # HTTP - Redirect non-www (cerulix.com only) server { listen 80; server_name cerulix.com; return 301 https://cerulix.com$request_uri; } # HTTP - Catch-all block for unknown domains (blocks them silently) server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 444; # Drop the connection (no response sent) } # HTTPS - Redirect www → non-www server { listen 443 ssl; server_name www.cerulix.com; ssl_certificate /etc/nginx/ssl/cerulix.com.combined.cer; ssl_certificate_key /etc/nginx/ssl/cerulix.com.key; return 301 https://cerulix.com$request_uri; } # HTTPS - Main secure application server server { listen 443 ssl; server_name cerulix.com; ssl_certificate /etc/nginx/ssl/cerulix.com.combined.cer; ssl_certificate_key /etc/nginx/ssl/cerulix.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers HIGH:!aNULL:!MD5; # Deny all attempts to access private files location ~ /\.(?!well-known).* { deny all; access_log off; log_not_found off; } # Static files (from collectstatic) location /static/ { alias /var/www/cerulix/staticfiles/; access_log /var/log/nginx/static_access.log; error_log /var/log/nginx/static_error.log; } # Media uploads location /media/ { alias /var/www/cerulix/media/; } # Assets (custom images, PDFs, etc.) location /assets/ { alias /var/www/cerulix/assets/; autoindex off; } # Redirect all /blog/* requests to blog subdomain location /blog/ { rewrite ^/blog(/.*)?$ https://blog.cerulix.com$1 permanent; } # Proxy all other requests to Gunicorn via UNIX socket location / { include proxy_params; proxy_pass http://unix:/var/www/cerulix/app.sock; } }
# blog.cerulix.conf # accessed via /etc/nginx/sites-available$ and linked to sites-enabled server { listen 80; server_name blog.cerulix.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name blog.cerulix.com; ssl_certificate /etc/nginx/ssl/cerulix.com.combined.cer; ssl_certificate_key /etc/nginx/ssl/cerulix.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers HIGH:!aNULL:!MD5; # Serve static files location /static/ { alias /var/www/cerulix/staticfiles/; } # Serve media files location /media/ { alias /var/www/cerulix/media/; } location /assets/ { alias /var/www/cerulix/assets/; } # Proxy all other requests to Gunicorn location / { include proxy_params; proxy_pass http://unix:/var/www/cerulix/app.sock; } }
After this, I run the following commands:
sudo nginx -t && sudo systemctl reload nginx
It successfully returns the following:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
I have ONE Gunicorn config file which serves the app:sock
located in the root of the project, which is accessed via /var/www/cerulix/
The Gunicorn
file is as follows and is accessed via /etc/supervisor/conf.d$
[program:gunicorn] directory=/var/www/cerulix command=/var/www/cerulix/.venv/bin/gunicorn --workers 3 --bind unix:/var/www/cerulix/app.sock cerulix.wsgi:application autostart=true autorestart=true stderr_logfile=/var/log/gunicorn/gunicorn.err.log stdout_logfile=/var/log/gunicorn/gunicorn.out.log [group:guni] programs:gunicorn
I then check the Gunicorn status and it successfully returns this:
guni:gunicorn RUNNING pid 126996, uptime 1 day, 1:01:39
Now, why is Django under the impression that:
- it thinks that you it's a feature that you have to click the link to a page that is accessible to a subdomain twice before it decides it's going to actually take you to said page
- it thinks it's a feature that the subdomain in the address bar remains the same regardless as to which section of the website you visit after you go to the blog section
- it thinks that
blog.cerlulix.com/blog
is what I am telling it do display in the address bar, despite telling it torewrite
the URL in thedjango.conf
file?
Further notes All error logs are returning 200 status codes.
Thank you for any guidance in advance.