Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/usr/bin/env python3
"""
This script will move all your current Netlify zones to GeoScaling DNS2.
Netlify records would be stored as Smart Subdomains, resolving to a CNAME
everywhere except for Russia, where it will resolve to a known Netlify IP
not blocked by Roskomnadzor. Everything else will be stored as simple
records.
Please study http://www.geoscaling.com/ carefully before proceeding.
After migrating, you'll need to update your nameservers in your
registrar's panel (set them to ns1-ns5.geoscaling.com).
Author: Alexander Pushkov (alexander@notpushk.in)
License: GPLv3
"""
import re
from textwrap import dedent
import requests
#: https://app.netlify.com/user/applications#personal-access-tokens
NETLIFY_TOKEN = "..."
#: Sign into your Geoscaling account and copy this from PHPSESSID cookie
GEOSCALING_PHPSESSID = "..."
#: Known to open alright in Russia, replace if needed
FAILSAFE_IPV4 = "195.123.225.31"
FAILSAFE_IPV6 = "2a03:b0c0:3:d0::d24:5001"
NETLIFY_DNS_API_URL = "https://api.netlify.com/api/v1/dns_zones/{domain_name}/dns_records"
GEOSCALING_API_URL = "http://www.geoscaling.com/dns2/index.php"
domain_name = "ale.sh"
## Create domain in GeoScaling:
domain, tld = domain_name.rsplit(".")
r = requests.post(GEOSCALING_API_URL,
params={'module': 'domains'},
data={"domain": domain, "tld": tld},
cookies={"PHPSESSID": GEOSCALING_PHPSESSID}
)
match = re.search(r'domain&id=(\d+)[^>]+><b>' + re.escape(domain_name), r.text)
assert match is not None
domain_id = int(match[1])
## Fetch and process records from Netlify:
r = requests.get(NETLIFY_DNS_API_URL.format(domain_name=domain_name.replace(".", "_")),
headers={
"Authorization": f"Bearer {NETLIFY_TOKEN}"
}
)
r.raise_for_status()
bind_file = ""
netlify_subdomains = {}
for rec in r.json():
if rec['type'].startswith("NETLIFY"):
if rec['hostname'].count(".") > 1:
netlify_subdomains[rec['hostname']] = rec['value']
elif rec['type'] == "NETLIFYv6":
bind_file += f"{rec['hostname']}. {rec['ttl']} IN AAAA {rec['priority'] or ''} {FAILSAFE_IPV6}\n"
else:
bind_file += f"{rec['hostname']}. {rec['ttl']} IN A {rec['priority'] or ''} {FAILSAFE_IPV4}\n"
else:
bind_file += f"{rec['hostname']}. {rec['ttl']} IN {rec['type']} {rec['priority'] or ''} {rec['value']}\n"
## Post simple records in one go as a BIND file:
r = requests.post(GEOSCALING_API_URL,
params={'module': 'domain', 'id': domain_id},
data={"bindtext": bind_file},
cookies={"PHPSESSID": GEOSCALING_PHPSESSID}
)
## For each of NETLIFY(v6) records (except for the apex @), make a Smart Subdomain:
for hostname, cname_value in netlify_subdomains.items():
subdomain_name = hostname.rsplit(domain_name, 1)[0].rstrip(".")
r = requests.post(GEOSCALING_API_URL,
params={"module": "smart_subdomains", "id": domain_id},
data={"smart_subdomain_name": subdomain_name},
cookies={"PHPSESSID": GEOSCALING_PHPSESSID}
)
match = re.search(r'subdomain_id=(\d+)[^>]+>' + re.escape(subdomain_name), r.text)
assert match is not None
subdomain_id = int(match[1])
r = requests.post(GEOSCALING_API_URL,
params={
'module': 'smart_subdomain',
'id': domain_id,
'subdomain_id': subdomain_id,
},
data={
"name": subdomain_name,
"share_country_info": "on",
"failsafe_ip": FAILSAFE_IPV4,
"code": dedent(f"""\
if ($country == "ru") {{
$output[] = array("A", "{FAILSAFE_IPV4}");
$output[] = array("AAAA", "{FAILSAFE_IPV6}");
}} else {{
$output[] = array("CNAME", "{cname_value}");
}}
"""),
},
cookies={"PHPSESSID": GEOSCALING_PHPSESSID}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.