is it possible to route a domain differently depending on what the URL is?
e.g.:
/ → backblaze B2
/api/v1/ → v1 api server
/api/v2/ → v2 api server
is it possible to route a domain differently depending on what the URL is?
e.g.:
/ → backblaze B2
/api/v1/ → v1 api server
/api/v2/ → v2 api server
Yes! This is possible.
We have examples of this on the Fastly Developer Hub:
developer.fastly.com/solutions/examples/url-path-based-routing-for-microservices
There you’ll find examples of doing this for both a ‘Deliver’ service (VCL) or a ‘Compute’ service (e.g. Rust, Go, JavaScript etc).
Hope this helps.
Any other questions, just let us know.
Thanks!
Thanks Mark! Did that resolve your question, @nothingwobbles?
not really, followed the guide, it’s still broken.
ah, the “add a custom snippet” thing claims it adds it at the end of the routines. It doesn’t. See:
declare local var.fastly_req_do_shield BOOL;
set var.fastly_req_do_shield = (req.restarts == 0);
# Snippet rcv : 100 ## my code
if (req.url ~ "^/api(/[^?]*)?(\?.*)?$") {
set req.backend = F_nanovm;
} else {
set req.backend = F_Host_1;
} ## end my code
# default conditions ## your code
set req.backend = F_Host_1;
if (!req.http.Fastly-SSL) {
error 801 "Force SSL";
}
Thanks for getting back to us.
It looks like you’re using the Fastly UI to add the VCL snippet to your service, and I too have been able to replicate what you’re experiencing (see ‘Explanation’ section below).
The problem is the VCL snippet is being added to an area of the vcl_recv
subroutine which is resulting in the if
statement in your snippet being made redundant because Fastly inserts any defined backends after the VCL Snippet.
Firstly, delete the VCL Snippet you added via the Fastly UI (e.g. click on “VCL snippets” and click the trashcan/bin icon to delete the snippet).
We need to use “Custom VCL” to ensure the VCL snippet is placed in a more suitable location of the vcl_recv
subroutine. To do that, follow these steps in the Fastly UI:
sub vcl_recv {
#FASTLY recv
# Requests for /status and all subpaths => origin 0
# (query strings allowed)
if (req.url ~ "^/status(/[^?]*)?(\?.*)?$") {
set req.backend = F_Host_1;
# Requests for exactly / => origin 1
# (query strings not allowed)
} else if (req.url == "/") {
set req.backend = F_Host_2;
# Unrecognised path => synthethic 404 error
} else {
error 601;
}
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
return(lookup);
}
sub vcl_error {
#FASTLY error
if (obj.status == 601) {
set obj.status = 404;
set obj.response = "Not found";
set obj.http.Content-Type = "text/html; charset=utf8";
synthetic "Page not found";
return (deliver);
}
return(deliver);
}
This is effectively the same VCL as shown in the examples page I linked originally.
Now if you click on “Show VCL” you should see the correct vcl_recv
being generated.
For anyone else following along with this discussion, please see the below steps that explain in detail how to replicate the issue and an explanation for why this is happening.
Specifically, the problem is the VCL snippet is being added to an area of the vcl_recv
subroutine which is resulting in the if
statement being made redundant because Fastly inserts any defined backends after the VCL Snippet.
Below are the steps I’ve taken (using the Fastly UI) to replicate the issue:
I create a new ‘Deliver’ service.
I click on “Show VCL”. I then look for the vcl_recv
subroutine and I find the following ‘default’ VCL added to my service…
sub vcl_recv {
#--FASTLY RECV BEGIN
if (req.restarts == 0) {
if (!req.http.X-Timer) {
set req.http.X-Timer = "S" time.start.sec "." time.start.usec_frac;
}
set req.http.X-Timer = req.http.X-Timer ",VS0";
}
declare local var.fastly_req_do_shield BOOL;
set var.fastly_req_do_shield = (req.restarts == 0);
# default conditions
# end default conditions
#--FASTLY RECV END
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
return(lookup);
}
I add two hosts (httpbin.org and example.com).
I click on “Show VCL”. I again look for the vcl_recv
subroutine and I find the VCL has changed slightly (e.g. the # default conditions
section now contains a ‘default’ backend being set, it has selected the first backend of the two I added in the previous step)…
sub vcl_recv {
#--FASTLY RECV BEGIN
if (req.restarts == 0) {
if (!req.http.X-Timer) {
set req.http.X-Timer = "S" time.start.sec "." time.start.usec_frac;
}
set req.http.X-Timer = req.http.X-Timer ",VS0";
}
declare local var.fastly_req_do_shield BOOL;
set var.fastly_req_do_shield = (req.restarts == 0);
# default conditions
set req.backend = F_Host_1;
# end default conditions
#--FASTLY RECV END
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
return(lookup);
}
vcl_recv
as the subroutine to insert the snippet into.NOTE: The description in the page says “(following any boilerplate code and preceding any objects)”, now this isn’t very clear if you don’t know what “objects” actually means. So in this case I happen to know that creating a host is effectively creating a ‘backend object’ so I’m going to presume that my snippet will be placed in-between the
#--FASTLY RECV BEGIN
macro block and the# default conditions
block. Which as has already been explained, means the example won’t work because the# default conditions
block is going to override my VCL snippet logic. This means we’ll ultimately need Custom VCL to ensure the VCL Snippet is placed into a more appropriate location (e.g. after where the default backend is set).
vcl_recv
subroutine and, as expected (see my above ‘NOTE’) I find the VCL has changed and the snippet is set in a location which means my service won’t work as expected…sub vcl_recv {
#--FASTLY RECV BEGIN
if (req.restarts == 0) {
if (!req.http.X-Timer) {
set req.http.X-Timer = "S" time.start.sec "." time.start.usec_frac;
}
set req.http.X-Timer = req.http.X-Timer ",VS0";
}
declare local var.fastly_req_do_shield BOOL;
set var.fastly_req_do_shield = (req.restarts == 0);
# Snippet Test Snippet : 100
# Requests for /status and all subpaths => origin 0
# (query strings allowed)
if (req.url ~ "^/status(/[^?]*)?(\?.*)?$") {
set req.backend = F_Host_1;
# Requests for exactly / => origin 1
# (query strings not allowed)
} else if (req.url == "/") {
set req.backend = F_Host_2;
# Unrecognised path => synthethic 404 error
} else {
error 601;
}
# default conditions
set req.backend = F_Host_1;
# end default conditions
#--FASTLY RECV END
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
return(lookup);
}