A while ago, I created a simple internal short URL service (with Django).
If an entry exists, for example, /abc
(or whatever), it redirects to the stored, longer URL with a HTTP-Status of 301. So far, so good…
However, now I have the requirement to set up this service for the main website.
However, there is already a CMS running with nginx try_files
and proxy_pass
configured.
Nginx:
location / {
try_files /maintenance.html $uri @cms;
}
location @cms {
rewrite ^/(.*)/$ /$1 permanent;
rewrite ^(.*)$ /VirtualHostBase/$scheme/$host:$server_port/cms/VirtualHostRoot$1 break;
proxy_pass http://example_cms;
include /etc/nginx/cfg/proxy.conf;
include /etc/nginx/cfg/security.conf;
gzip_static on; # to serve pre-gzipped version
}
Can these be combined?
So, the desired flow is as follows:
- if
/abc
found and returned in the short URL service, redirect with a HTTP Status from URL-Service; - otherwise, use the CMS and display a URL from the CMS using
try_files
+rewrite
+proxy_pass
. - If none of these apply, show a 404, which can also be served by the CMS.
2
Answers
You want to prioritize the short URL service by checking its route first and, if no match is found, then proceeding to handle the request with the CMS as usual.
You would need to modify the Nginx configuration by adding a new
location
block specifically for handling the paths that might match your short URLs. The Django application must be set up to serve on a specific endpoint or port, which can then be proxied by Nginx.As Dmitry notes in the comments, a
try_files
directive in Nginx does not support specifying more than one named location as a fallback.The last parameter of the
try_files
directive can indeed point to a named location or a URI, but only one such fallback is permitted.You can instead try to first attempt to serve the request as a static file, or via the short URL service, and use a single named location as the final fallback, which will then decide whether to serve the content from the CMS or return a 404.
You would route the request internally within Nginx based on the presence or absence of the requested resource in the short URL service.
try_files
, decide if the request should be served by the CMS or if a 404 should be returned.The
@check_short_url
location is a named location which attempts to proxy every request to the Django short URL service. Depending on your Django app’s behavior, if a short URL does not exist, the app should either redirect (for valid short URLs) or signal back to Nginx (e.g., via a custom header or specific status code) that the request should be passed to the CMS.You might need to employ additional Nginx features like
error_page
directives within the@check_short_url
location to internally redirect requests to@cms
based on the response from the Django app.The "Using NGINX and NGINX Plus as an Application Gateway with uWSGI and Django" guide focuses on Nginx’s ability to serve as an application gateway in front of a Django application running via uWSGI, which is not your case.
One possible solution is to intercept the 404 error from Short URL Service (
@sus
) and pass the request to CMS (@cms
), which is configured as aerror_page
. A bit hacky, but it works.Example
Demo