6

I am moving a Django site to GCP and using Google Cloud Run for the first time. The experience is great. I was also very pleased with the domain mapping feature, but I am having trouble with forwarding the www subdomain to the naked domain URL. For consistent page analytics, I would like visitors who browse to https://www.mycooldomainname.com to be 301 redirected to https://mycooldomainname.com (real domain redacted)

DNS setup

I added the naked and www subdomain to Cloud Run custom domains:

gcr

And added the required A, AAA and CNAME records at my registrar:

registrar

After everything propagated I can visit my site at https://mycooldomainname.com and https://www.mycooldomainname.com, but how can I configure the forwarding/rewriting?

From other posts I have read where people achieved this with Google Cloud DNS, it looks like they used an alias to do the forwarding.

In this case, I am trying to do the forwarding via uwsgi:

Webserver setup

The django app is served via uwsgi with this configuration - notice the redirect rule:

[uwsgi]
plugins-dir = /usr/lib/uwsgi/plugins
plugins = router_uwsgi
route-uri = ^(.*)\/\/www\.(.*)$ redirect-301:$1//$2
hook-master-start = unix_signal:15 gracefully_kill_them_all
http-socket = 0.0.0.0:8000
cheaper = 1
cheaper-algo = backlog
workers = 3
master = true
enable-threads = true
threads = 12
offload-threads = 12
harakiri = 300
http-harakiri = 300
logformat = %(var.HTTP_X_REAL_IP) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)\" %(msecs)ms
static-map = /=webroot
static-gzip-all = true
module = app.wsgi

The actual redirect works fine on other parts of the url, for example, if I include the following redirect test rule:

route-uri = ^(.*)est(.*)$ redirect-301:$1ust$2

browsing to https://www.mycooldomainname.com/test/ correctly redirects to https://www.mycooldomainname.com/tust/

So at this point I'm not sure if there is a GCP limitation on redirecting parts of a verified domain or my regex is wrong.

Jannie Theunissen
  • 28,256
  • 21
  • 100
  • 127
  • My basic understanding in DNS and setting it up, you should configure the result as your naked domain, for example _www_ = _mycooldomainname.com_. Since your naked domain is your primary domain, and www is will be translated to your primary domain. A close familiar set up to this is your hostfile in your system as far as my experience goes with DNS. – Bryan L May 13 '22 at 02:14
  • 3
    DNS servers do not implement redirection. That is an application layer feature that does not exist in the DNS protocol. In other words, implement redirection within your Cloud Run application. If you want all traffic going to `www.example.com` then send a 301 redirect when the hostname matches `example.com`. URL Rewriting is another feature that you will need to implement in your application. Most frameworks have these features built-in. Your question lacks details, so I cannot recommend which features to enable in your framework. – John Hanley May 13 '22 at 19:25
  • Thanks @JohnHanley I have added more information about my framework as suggested. Let's hope someone can help. – Jannie Theunissen May 17 '22 at 14:05
  • 1) Make sure that Cloud Run is configured for both domain names. 2) Your redirect is not evaluating the **host** value. 3) To implement a host based redirect in Django, write **middleware** that checks each request, compares the host value, and issues a redirect. – John Hanley May 17 '22 at 18:12
  • Thanks for the insight @JohnHanley I have a bounty that should go to the most helpful advice, so if you can add an answer, the bounty will not be randomly awarded by the system. – Jannie Theunissen May 18 '22 at 07:25
  • Bounties are not randomly awarded. If you do not select an answer, the bound is lost. There are many tutorials on writing Django middleware. In your case, this is very easy to implement. Example: https://adamj.eu/tech/2020/03/02/how-to-make-django-redirect-www-to-your-bare-domain/ I wish I had more time, but I am deep into a Python Pyscript project. There are other options, but the correct design IMHO is to implement this as Django middleware. Best for customer-facing performance with minimal costs to you (the egress cost of redirects). – John Hanley May 18 '22 at 08:27

2 Answers2

2

I believe you should be able to configure this using Google Load Balancer.

See:

https://stackoverflow.com/a/63987798 and https://stackoverflow.com/a/67207300

Beware of not including the http/https as per the second answer above.

There is also a helpful Medium walkthough with a tonne more steps for before and after:

https://medium.com/@shivamgrg38/setting-up-http-to-https-and-non-www-to-www-redirects-for-external-http-s-load-balancers-on-b73be558eab5

  • Thanks for answering questions! Your contributions are very much appreciated. When including links in your answer, please try to include content from the site directly in your answer, such as quoted content or an exmaple implementation in code. See the guide to [answer]. – Michael Delgado May 16 '22 at 04:09
  • Thank you for these helpful pointers @Arun I am trying to avoid adding an external load balancer just for one redirect rule, but it is good to know it is a possible fall back. – Jannie Theunissen May 17 '22 at 14:09
2

Thanks for all the advice! Here is what I learned:

  1. DNS records can not be used for redirecting especially if the CNAME of a subdomain is used by GCP
  2. Google Cloud Run does not limit URL redirecting in any way
  3. uWSGI has powerful features, but they are hard to discover
  4. The following redirect rule worked for me:
[uwsgi]
plugins-dir = /usr/lib/uwsgi/plugins
plugins = router_uwsgi
route-host = ^www.mycooldomainname.com$ redirect-permanent:https://mycooldomainname.com${REQUEST_URI}

And I needed to install the following in my base image to get the internal rewriting and plugins to be available:

FROM $PYTHON_IMAGE as base 

RUN apt-get update \
    && \
    apt-get install --no-install-recommends -y \
    libpcre3-dev zlib1g-dev \
    uwsgi-core \
    && \
    apt-get clean && rm -rf /var/lib/apt/lists/*
Jannie Theunissen
  • 28,256
  • 21
  • 100
  • 127