0

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.

  1. My website runs on a Linux server successfully via Gunicorn & via an app.sock
  2. 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
  3. 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 &amp; 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:

  1. 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
  2. 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
  3. it thinks that blog.cerlulix.com/blog is what I am telling it do display in the address bar, despite telling it to rewrite the URL in the django.conf file?

Further notes All error logs are returning 200 status codes.

Thank you for any guidance in advance.

7
  • 1
    Have you done anything to verify that django is the problem? What does your logs show? If it's django I'd say it's closer to being on topic on StackOverflow than here... Commented Aug 5 at 10:13
  • @vidarlo All logs return no errors, Django is having a hard time doing what I'm telling it to do & I need to know why it's not doing as it's told Commented Aug 5 at 11:58
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. Commented Aug 5 at 12:16
  • 2
    I don't see anything wrong with the nginx configuration. From the behavior you describe, it looks like a Django (or, less likely, user browser caching) problem rather than any other server part, and as already noted, the question seems better suited to the Stack Overflow site. Editing the post to fix the broken Markdown is helpful if you want others to easily read your question and try to help you. Commented Aug 5 at 13:01
  • 1
    @vidarlo I believe I have finally understood what the OP is complaining about and what is causing the described behavior. Pretty funny :) Commented Aug 6 at 12:53

1 Answer 1

2

I have a website at cerulinux.com that works great.

The configs you included use a different domain name, cerulix.com. It seems neither is your actual domain. It is a common practice on ServerFault and StackOverflow to use the example.com domain name in code and configuration snippets if you want to hide your actual domain, as recommended by RFC 2606. I'm glad to hear your site works great.

But then I introduced subdomains.

As I understand, by "introducing subdomains" you mean:

  • adding an A record for your subdomain to the DNS records for your domain;
  • adding the 'blog.cerulix.com' line to your settings.py;
  • completely duplicating the configuration serving your main domain to serve your blog.cerulix.com subdomain, pointing to the same Django app;
  • adding a rewrite rule for redirecting https://cerulix.com/blog/<article> to https://blog.cerulix.com/<article> in the nginx configuration for your main domain.

You haven't introduced any other changes to your Django app code logic, and I'm assuming you weren't the one who developed this application. I had to read your question a couple of times before I fully grasped what behavior you are complaining about and what's actually happening "under the hood".

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.

I assume the mentioned link is something like https://cerulix.com/blog/. Your Nginx honestly followed your rewrite rule, redirecting you to https://blog.cerulix.com/. Since the configuration for the blog.cerulix.com domain points to the same app, it's obvious the app will render the index page when it receives a / "root" request.

I'm a little puzzled as to why you were expecting a different outcome. Did you perhaps add some code to analyze the Host HTTP header of the incoming request and behave differently depending on its value? From what you've shown, it doesn't seem like you did (or even changed the current app routes list in any way). You haven't even provided the contents of your proxy_params file to confirm you're actually passing this header to your application (although in this case I'm almost certain you are, otherwise your app wouldn't have "worked great" initially).

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.

I am almost perfectly sure your Django app is rendering your links as relative, omitting the scheme and domain parts (which is a common practice). When you click on the link, your browser asks your server for the /blog/ page from the current domain, which is blog.cerulix.com. Since no redirection occurs in the second nginx configuration, your Django app honestly renders the blog page for you, according to the /blog/ route it received.

You're now on said page, and it shows <subdomain>.<domain>/<subdomain> in the address bar.

The second <subdomain> is an app route. The fact that this route literally matches the subdomain name is because you named your subdomain after this app route. Once again, I'm surprised you expected something different.

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.

Since it is the same app rendering its links as relative ones, with no changes to the app's logic, why should it "think" something different?

Now, why is Django under the impression that...

Your Django app is just an app (a pretty deterministic one, as most apps are). It cannot magically guess that you want its logic to change based on the HTTP Host header's value unless you explicitly change its logic.

Summarizing all this up, to achieve the desired behavior, you need to make changes to your app's code. Don't blame it without a reason; it's not at fault for being unable to read your mind and guess what you want it to do.


Update

It seems that the django-hosts middleware provides the functionality you want to add to your Django app. Questions about this middleware integration, if any, are definitely off-topic for ServerFault and should be asked on StackOverflow. The only thing I can add is that if you successfully integrate this middleware into your Django app, you definitely would not need either the nginx rewrite rule or a separate nginx configuration for the blog subdomain.

1
  • Your interpretation certainly makes sense... but I fail to understand why it was expected to work. Commented Aug 6 at 13:28

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.