Skip to content

Instantly share code, notes, and snippets.

@simonkuhn
Last active August 31, 2025 04:31
Show Gist options
  • Select an option

  • Save simonkuhn/a380a6fa205db87a3625f26ad09e6593 to your computer and use it in GitHub Desktop.

Select an option

Save simonkuhn/a380a6fa205db87a3625f26ad09e6593 to your computer and use it in GitHub Desktop.

Revisions

  1. simonkuhn revised this gist Jul 24, 2020. 1 changed file with 7 additions and 8 deletions.
    15 changes: 7 additions & 8 deletions geo.vcl
    Original file line number Diff line number Diff line change
    @@ -56,6 +56,12 @@ sub vcl_error {
    "name": ""} json.escape(client.as.name) {"",
    "number": "} json.escape(client.as.number) {"
    },
    "client": {
    "conn_speed": ""} json.escape( if(client.geo.conn_speed != "?", client.geo.conn_speed, "") ) {"",
    "conn_type": ""} json.escape( if(client.geo.conn_type != "?", client.geo.conn_type, "") ) {"",
    "proxy_desc": ""} json.escape( if(client.geo.proxy_description != "?", client.geo.proxy_description, "") ) {"",
    "proxy_type": ""} json.escape( if(client.geo.proxy_type != "?", client.geo.proxy_type, "") ) {""
    },
    "geo": {
    "area_code": "} json.escape(client.geo.area_code) {",
    "city": ""} json.escape( if(client.geo.city.utf8 != "?", client.geo.city.utf8, "") ) {"",
    @@ -69,15 +75,8 @@ sub vcl_error {
    "postal_code": ""} json.escape( if(client.geo.postal_code != "?", client.geo.postal_code, "") ) {"",
    "region": ""} json.escape( if(client.geo.region.utf8 != "?", client.geo.region.utf8, "") ) {""
    },
    "timezone": {
    "gmt_offset": "} json.escape(client.geo.gmt_offset) {",
    "time": {
    "utc_offset": "} json.escape(client.geo.utc_offset) {"
    },
    "client": {
    "conn_speed": ""} json.escape( if(client.geo.conn_speed != "?", client.geo.conn_speed, "") ) {"",
    "conn_type": ""} json.escape( if(client.geo.conn_type != "?", client.geo.conn_type, "") ) {"",
    "proxy_description": ""} json.escape( if(client.geo.proxy_description != "?", client.geo.proxy_description, "") ) {"",
    "proxy_type": ""} json.escape( if(client.geo.proxy_type != "?", client.geo.proxy_type, "") ) {""
    }
    }"};

  2. simonkuhn revised this gist Jul 24, 2020. 1 changed file with 6 additions and 27 deletions.
    33 changes: 6 additions & 27 deletions geo.vcl
    Original file line number Diff line number Diff line change
    @@ -1,16 +1,16 @@
    sub vcl_recv {
    #FASTLY recv
    # We don't do anything else
    # We don't do other methods
    if (req.method != "GET") {
    return(error);
    }

    # Handle IPv4 or IPv6 provided in url path (nothing extraneous, very basic matching)
    # Handle IPv4 or IPv6 provided in url path (nothing extraneous allowed, perform basic matching)
    if (req.url.path ~ "^/([a-f0-9:.]+)$") {
    set client.geo.ip_override = re.group.1;

    # Handle Opera / Silk per https://docs.fastly.com/en/guides/overriding-which-ip-address-the-geolocation-features-use
    } elseif ((req.http.X-OperaMini-Features || req.http.User-Agent ~ " Silk-Accelerated=true$") && req.http.X-Forwarded-For ){
    # Use X-Forwarded-For if it exists (first IP is client)
    } elseif (req.http.X-Forwarded-For) {
    set client.geo.ip_override = regsub(req.http.X-Forwarded-For, ",.+$", "");
    }

    @@ -22,6 +22,7 @@ sub vcl_hash {
    #FASTLY hash
    set req.hash += req.http.host;
    set req.hash += req.url;
    set req.hash += client.ip;
    return(hash);
    }

    @@ -42,35 +43,13 @@ sub vcl_pass {

    sub vcl_fetch {
    #FASTLY fetch
    # In the event of a server-failure response from origin, retry once more
    if ((beresp.status == 500 || beresp.status == 503) && req.restarts < 1 && (req.method == "GET" || req.method == "HEAD")) {
    restart;
    }
    # Log the number of restarts for debugging purposes
    if (req.restarts > 0) {
    set beresp.http.Fastly-Restarts = req.restarts;
    }
    # If the response is setting a cookie, make sure it is not cached
    if (beresp.http.Set-Cookie) {
    return(pass);
    }
    # By default we set a TTL based on the `Cache-Control` header but we don't parse additional directives
    # like `private` and `no-store`. Private in particular should be respected at the edge:
    if (beresp.http.Cache-Control ~ "(private|no-store)") {
    return(pass);
    }
    # If no TTL has been provided in the response headers, set a default
    if (!beresp.http.Expires && !beresp.http.Surrogate-Control ~ "max-age" && !beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
    set beresp.ttl = 3600s;
    }
    return(deliver);
    }

    sub vcl_error {
    #FASTLY error

    # JSON output

    # Assemble JSON output
    synthetic {"{
    "ip": ""} if(client.geo.ip_override, client.geo.ip_override, client.ip) {"",
    "as": {
  3. simonkuhn revised this gist Jul 24, 2020. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion geo.vcl
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,6 @@ sub vcl_recv {
    return(error);
    }


    # Handle IPv4 or IPv6 provided in url path (nothing extraneous, very basic matching)
    if (req.url.path ~ "^/([a-f0-9:.]+)$") {
    set client.geo.ip_override = re.group.1;
  4. simonkuhn created this gist Jul 24, 2020.
    120 changes: 120 additions & 0 deletions geo.vcl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    sub vcl_recv {
    #FASTLY recv
    # We don't do anything else
    if (req.method != "GET") {
    return(error);
    }


    # Handle IPv4 or IPv6 provided in url path (nothing extraneous, very basic matching)
    if (req.url.path ~ "^/([a-f0-9:.]+)$") {
    set client.geo.ip_override = re.group.1;

    # Handle Opera / Silk per https://docs.fastly.com/en/guides/overriding-which-ip-address-the-geolocation-features-use
    } elseif ((req.http.X-OperaMini-Features || req.http.User-Agent ~ " Silk-Accelerated=true$") && req.http.X-Forwarded-For ){
    set client.geo.ip_override = regsub(req.http.X-Forwarded-For, ",.+$", "");
    }

    error 601;
    return(lookup);
    }

    sub vcl_hash {
    #FASTLY hash
    set req.hash += req.http.host;
    set req.hash += req.url;
    return(hash);
    }

    sub vcl_hit {
    #FASTLY hit
    return(deliver);
    }

    sub vcl_miss {
    #FASTLY miss
    return(fetch);
    }

    sub vcl_pass {
    #FASTLY pass
    return(pass);
    }

    sub vcl_fetch {
    #FASTLY fetch
    # In the event of a server-failure response from origin, retry once more
    if ((beresp.status == 500 || beresp.status == 503) && req.restarts < 1 && (req.method == "GET" || req.method == "HEAD")) {
    restart;
    }
    # Log the number of restarts for debugging purposes
    if (req.restarts > 0) {
    set beresp.http.Fastly-Restarts = req.restarts;
    }
    # If the response is setting a cookie, make sure it is not cached
    if (beresp.http.Set-Cookie) {
    return(pass);
    }
    # By default we set a TTL based on the `Cache-Control` header but we don't parse additional directives
    # like `private` and `no-store`. Private in particular should be respected at the edge:
    if (beresp.http.Cache-Control ~ "(private|no-store)") {
    return(pass);
    }
    # If no TTL has been provided in the response headers, set a default
    if (!beresp.http.Expires && !beresp.http.Surrogate-Control ~ "max-age" && !beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
    set beresp.ttl = 3600s;
    }
    return(deliver);
    }

    sub vcl_error {
    #FASTLY error

    # JSON output

    synthetic {"{
    "ip": ""} if(client.geo.ip_override, client.geo.ip_override, client.ip) {"",
    "as": {
    "name": ""} json.escape(client.as.name) {"",
    "number": "} json.escape(client.as.number) {"
    },
    "geo": {
    "area_code": "} json.escape(client.geo.area_code) {",
    "city": ""} json.escape( if(client.geo.city.utf8 != "?", client.geo.city.utf8, "") ) {"",
    "continent_code": ""} json.escape( if(client.geo.continent_code != "?", client.geo.continent_code, "") ) {"",
    "country_code": ""} json.escape( if(client.geo.country_code != "?", client.geo.country_code, "") ) {"",
    "country_code3": ""} json.escape( if(client.geo.country_code3 != "?", client.geo.country_code3, "") ) {"",
    "country_name": ""} json.escape( if(client.geo.country_name.utf8 != "?", client.geo.country_name.utf8, "") ) {"",
    "latitude": "} json.escape(client.geo.latitude) {",
    "longitude": "} json.escape(client.geo.longitude) {",
    "metro_code": "} json.escape(client.geo.metro_code) {",
    "postal_code": ""} json.escape( if(client.geo.postal_code != "?", client.geo.postal_code, "") ) {"",
    "region": ""} json.escape( if(client.geo.region.utf8 != "?", client.geo.region.utf8, "") ) {""
    },
    "timezone": {
    "gmt_offset": "} json.escape(client.geo.gmt_offset) {",
    "utc_offset": "} json.escape(client.geo.utc_offset) {"
    },
    "client": {
    "conn_speed": ""} json.escape( if(client.geo.conn_speed != "?", client.geo.conn_speed, "") ) {"",
    "conn_type": ""} json.escape( if(client.geo.conn_type != "?", client.geo.conn_type, "") ) {"",
    "proxy_description": ""} json.escape( if(client.geo.proxy_description != "?", client.geo.proxy_description, "") ) {"",
    "proxy_type": ""} json.escape( if(client.geo.proxy_type != "?", client.geo.proxy_type, "") ) {""
    }
    }"};

    set obj.status = 200;
    set obj.response = "OK";
    set obj.http.Content-Type = "application/json";

    return (deliver);
    }

    sub vcl_deliver {
    #FASTLY deliver
    return(deliver);
    }

    sub vcl_log {
    #FASTLY log
    }