Compare commits

..

9 commits

Author SHA1 Message Date
orangci
3fac80dcfc
Revert "Nix" 2026-03-21 17:09:29 +03:00
orangci
1c04d92eb4
Merge pull request #52 from orangci/nix
Nix
2026-03-21 17:06:17 +03:00
orangc
20ebb7da08 fix(nix): importing thing was brokeb 2026-03-21 17:05:14 +03:00
orangc
291bc39a7a feat(nix): recursively import domain files via mapping 2026-03-21 16:52:05 +03:00
orangc
08350def49 style: formatting with nixfmt 2026-03-21 16:32:42 +03:00
satr14washere
a97ad1b804 migrated nix files 2026-03-21 20:13:05 +07:00
satr14washere
71102fabc8 remove apex, managed seperately 2026-03-21 19:33:49 +07:00
satr14washere
e7d62df069 todo implementation 2026-03-21 19:15:20 +07:00
satr14washere
0015313795 base flake.nix and example 2026-03-21 19:13:53 +07:00
41 changed files with 640 additions and 41 deletions

View file

@ -8,7 +8,7 @@
- Github Pull Requests - Github Pull Requests
- How DNS Works - How DNS Works
4. When in doubt, read the docs before asking in PR 4. When in doubt, read the docs before asking in PR
5. **PREVIEWS ARE REQUIRED FOR WEBSITES.** Must be a link. If it's not a website then please state the use of the subdomain. 5. **PREVIEWS ARE REQUIRED FOR WEBSITES.** Can be a screenshot/link. If it's not a website then please state the use of the subdomain.
--> -->
## Requirements ## Requirements
@ -38,5 +38,5 @@ _None provided..._
<!-- <!--
^^^^^^ Remove the line above to provide a link/screenshot ^^^^^^ Remove the line above to provide a link/screenshot
⚠️⚠️ ****REQUIRED IF ITS A WEBSITE**** ⚠️⚠️ ⚠️⚠️ ****REQUIRED IF ITS A WEBSITE**** ⚠️⚠️
Please provide a link (required) and/or screenshot to your website below. Please provide a link/screenshot to your website below.
--> -->

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
creds.json creds.json
types-dnscontrol.d.ts types-dnscontrol.d.ts
result

View file

@ -1,5 +1,5 @@
> [!IMPORTANT] > [!IMPORTANT]
> We are currently rewriting our registration process, CI/CD pipeline, documentation, and website. Due to time constraints, **pull requests are still welcome** and will be migrated to the new syntax after the rewrite. We will document the new registration process in this repository once it's ready. In the meantime, you can join our [discord server](https://discord.gg/rFyRF3MMhc) to get updates and support. > We are currently rewriting our registration process, CI/CD pipeline, documentation, and website. Pull requests are temporarily paused until the new system is ready. We will document the new registration process in this repository once it's ready. In the meantime, you can join our [discord server](https://discord.gg/rFyRF3MMhc) to get updates and support.
> [!CAUTION] > [!CAUTION]
> We currently **DO NOT** support Vercel, Netlify, and other services that requires us to be on the [PSL](https://github.com/publicsuffix/list). _We will apply to be on the list [only if theres high demand](https://publicsuffix.org/submit/#:~:text=We%20will%20generally%20decline%20small%20projects)_, so be patient and invite some of your friends! > We currently **DO NOT** support Vercel, Netlify, and other services that requires us to be on the [PSL](https://github.com/publicsuffix/list). _We will apply to be on the list [only if theres high demand](https://publicsuffix.org/submit/#:~:text=We%20will%20generally%20decline%20small%20projects)_, so be patient and invite some of your friends!

78
docs/example.nix Normal file
View file

@ -0,0 +1,78 @@
{ dns, ... }: let
owner = {
username = "satr14washere";
email = "admin@satr14.my.id";
};
proxy = false;
in with dns.lib.combinators; {
A = [
{ address = "203.0.113.1"; ttl = 60 * 60; }
"203.0.113.2"
(ttl (60 * 60) (a "203.0.113.3"))
];
AAAA = [
"4321:0:1:2:3:4:567:89ab"
];
MX = mx.google;
TXT = [
(with spf; strict [ "a:mail.example.com" google ])
];
DMARC = [ (dmarc.postmarkapp "mailto:re+abcdefghijk@dmarc.postmarkapp.com") ];
CAA = letsEncrypt "admin@example.com";
SRV = [
{
service = "sip";
proto = "tcp";
port = 5060;
target = "sip.example.com";
}
];
SSHFP = [
{
algorithm = "ed25519";
fingerprintType = "sha256";
fingerprint = "899EB4AC9285578AFDA3CCBE152EE78D8618B8F3862FEF2703E1FC7011E9B8AA";
}
];
OPENPGPKEY = [
"very long base64 text"
];
HTTPS = [
{
svcPriority = 1;
targetName = ".";
alpn = [ "http/1.1" "h2" "h3" ];
ipv4hint = [ "203.0.113.1" "203.0.113.2" "203.0.113.3" ];
ipv6hint = [ "4321:0:1:2:3:4:567:89ab" ];
}
];
TLSA = [
{
certUsage = "dane-ee";
selector = "spki";
matchingType = "sha256";
certificate = "899EB4AC9285578AFDA3CCBE152EE78D8618B8F3862FEF2703E1FC7011E9B8AA";
}
];
subdomains = rec {
www.A = [ "203.0.113.4" ];
www2 = host "203.0.113.5" "4321:0:1:2:3:4:567:89bb";
www3 = host "203.0.113.6" null;
www4 = www3;
staging = delegateTo [
"ns1.another.com."
"ns2.another.com."
];
foo.subdomains.www.CNAME = [ "foo.test.com." ];
};
}

View file

@ -1,9 +0,0 @@
{
"description": "dashboard and main website",
"owner": {
"username": "partofmyid"
},
"record": {
"ALIAS": "website-e7n.pages.dev"
}
}

View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "ColinLeDev";
};
description = "Discord verification";
proxy = false;
in with dns.lib.combinators; {
TXT = [ "dh=279643a6f8677dedb1c5c63d007fc4516149679c" ];
}

View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "CuteDog5695";
email = "cutedog5695@gmail.com";
repo = "https://github.com/CuteDog5695/cutedog5695.github.io";
};
proxy = false;
in with dns.lib.combinators; {
TXT = [ "dh=a7c19efb0f6bc38b97a33760f6c1ee84df4151b1" ];
}

View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "justdeveloper@juststudio.is-a.dev";
repo = "https://github.com/JustDeveloper1/Website";
};
proxy = false;
in with dns.lib.combinators; {
TXT = [ "dh=6024027bc233825451e290ac37a4b4a1f838ee70" ];
}

8
domains/_discord.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "satr14washere";
};
proxy = false;
in with dns.lib.combinators; {
TXT = [ "dh=d509fc9014e196311ed887c2e410cdefa833436e" ];
}

View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "Roki100";
discord = "289479495444987904";
};
in with dns.lib.combinators; {
TXT = [ "dh=5633078cd5bfd347a896ddb0f0de017c5423aa06" ];
}

View file

@ -1,9 +0,0 @@
{
"owner": {
"username": "LunarisXOffical"
},
"record": {
"TXT": [ "vc-domain-verify=reallunarisx.part-of.my.id,eb89acab3adcd3ee3acd" ]
},
"proxy": false
}

8
domains/batman.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "shadowe1ite";
};
proxy = true;
in with dns.lib.combinators; {
CNAME = [ "shadowe1ite.github.io." ];
}

9
domains/c.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "orangci";
email = "c@orangc.xyz";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

9
domains/colin.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "ColinLeDev";
};
description = "My personal portfolio hosted on my server";
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "proxy.col1n.fr." ];
}

10
domains/cutedog5695.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "CuteDog5695";
email = "cutedog5695@gmail.com";
repo = "https://github.com/CuteDog5695/cutedog5695.github.io";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

7
domains/elkaff.nix Normal file
View file

@ -0,0 +1,7 @@
{ dns, ... }: let
owner = {
username = "elkhaff";
};
in with dns.lib.combinators; {
CNAME = [ "portofolio-pixel.pages.dev." ];
}

10
domains/j.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "support@juststudio.is-a.dev";
repo = "https://github.com/JustStudio7/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

8
domains/jacob.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "jacobrdale";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "hexon404.onrender.com." ];
}

10
domains/jd.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "justdeveloper@juststudio.is-a.dev";
repo = "https://github.com/JustDeveloper1/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

8
domains/job.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "FWEEaaaa1";
};
proxy = false;
in with dns.lib.combinators; {
A = [ "128.204.223.115" ];
}

16
domains/joel.nix Normal file
View file

@ -0,0 +1,16 @@
{ dns, ... }: let
owner = {
username = "joestr";
email = "strasser999@gmail.com";
};
proxy = false;
in with dns.lib.combinators; {
A = [ "142.132.173.34" ];
AAAA = [ "2a01:4f8:1c0c:6cc0::1" ];
MX = [
{
exchange = "achlys.infra.joestr.at.";
preference = 10;
}
];
}

10
domains/js.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "support@juststudio.is-a.dev";
repo = "https://github.com/JustStudio7/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

10
domains/just.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "justdeveloper@juststudio.is-a.dev";
repo = "https://github.com/JustDeveloper1/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

10
domains/justdev.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "justdeveloper@juststudio.is-a.dev";
repo = "https://github.com/JustDeveloper1/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

10
domains/justdeveloper.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "justdeveloper@juststudio.is-a.dev";
repo = "https://github.com/JustDeveloper1/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

10
domains/juststudio.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "JustDeveloper1";
email = "support@juststudio.is-a.dev";
repo = "https://github.com/JustStudio7/Website";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

8
domains/katz.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "Bananalolok";
};
proxy = false;
in with dns.lib.combinators; {
A = [ "69.197.135.205" ];
}

9
domains/no-one-is.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "EducatedSuddenBucket";
email = "me@esb.is-a.dev";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "educatedsuddenbucket-github-io.onrender.com." ];
}

8
domains/pxl.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "heypxl";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "heypxl.github.io." ];
}

8
domains/rchessauth.nix Normal file
View file

@ -0,0 +1,8 @@
{ dns, ... }: let
owner = {
username = "vortexprime24";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "fire.hackclub.app." ];
}

View file

@ -1,9 +0,0 @@
{
"owner": {
"username": "LunarisXOffical"
},
"record": {
"CNAME": "3bdbf404a94a1470.vercel-dns-017.com"
},
"proxy": false
}

9
domains/roki.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "Roki100";
discord = "289479495444987904";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "edge.redirect.pizza." ];
}

7
domains/satr14.nix Normal file
View file

@ -0,0 +1,7 @@
{ dns, ... }: let
owner = {
username = "satr14washere";
};
in with dns.lib.combinators; {
CNAME = [ "5th-site.pages.dev." ];
}

View file

@ -1,10 +1,10 @@
{ {
"owner": { "owner": {
"email": "me@stefdp.com", "email": "admin@stefdp.lol",
"username": "Stef-00012" "username": "Stef-00012"
}, },
"record": { "record": {
"CNAME": "proxy.stefdp.com" "CNAME": "proxy.stefdp.lol"
}, },
"proxied": false "proxied": false
} }

9
domains/stef.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "Stef-00012";
email = "admin@stefdp.lol";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "proxy.stefdp.lol." ];
}

10
domains/ukriu.nix Normal file
View file

@ -0,0 +1,10 @@
{ dns, ... }: let
owner = {
username = "ukriu";
email = "partofmyid@ukriu.com";
};
description = "my website";
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "ukriu.pages.dev." ];
}

View file

@ -1,6 +1,6 @@
{ {
"owner": { "owner": {
"email": "me@stefdp.com", "email": "admin@stefdp.com",
"username": "Stef-00012" "username": "Stef-00012"
}, },
"record": { "record": {

9
domains/you-are.nix Normal file
View file

@ -0,0 +1,9 @@
{ dns, ... }: let
owner = {
username = "Stef-00012";
email = "admin@stefdp.com";
};
proxy = false;
in with dns.lib.combinators; {
CNAME = [ "proxy.stefdp.com." ];
}

View file

@ -1,5 +1,5 @@
{ {
description = "Zone File Generator For part-of.my.id"; description = "Zone File Generator";
inputs.dns.url = "github:nix-community/dns.nix"; inputs.dns.url = "github:nix-community/dns.nix";
outputs = { dns, ... }: let outputs = { dns, ... }: let
@ -22,9 +22,10 @@
}; };
NS = domain.nameservers; NS = domain.nameservers;
# note: Cloudflare ignores SOA and NS records uploaded via Zone File, they are just so that dns.nix builds a valid zone file. # note: Cloudflare ignores SOA and NS records uploaded via Zone File, they are included just so that dns.nix builds a valid zone file.
A = [ "1.1.1.1" ]; #subdomains = ;
# ^^ todo: implement file imports from ./domains
} }
) )
) domains; ) domains;

279
scripts/migrate-json-to-nix.py Executable file
View file

@ -0,0 +1,279 @@
#!/usr/bin/env python3
"""
Migration script to convert domains/*.json to domains/*.nix
Reads each JSON domain config and generates a corresponding .nix file
following the format from docs/example.nix.
Usage:
python3 scripts/migrate-json-to-nix.py [--dry-run] [--delete-json]
Options:
--dry-run Print generated .nix content to stdout without writing files
--delete-json Delete the original .json files after successful conversion
"""
import json
import sys
import os
from pathlib import Path
DOMAINS_DIR = Path(__file__).resolve().parent.parent / "domains"
def json_to_nix(data: dict) -> str:
"""Convert a single domain JSON config to a .nix file string."""
owner = data.get("owner", {})
description = data.get("description")
record = data.get("record", {})
# Some files use "proxy", others use "proxied"
proxy = data.get("proxied", data.get("proxy"))
lines = []
# Header
lines.append("{ dns, ... }: let")
# Owner block
owner_lines = []
if owner.get("username"):
owner_lines.append(f' username = "{owner["username"]}";')
if owner.get("email"):
owner_lines.append(f' email = "{owner["email"]}";')
if owner.get("discord"):
owner_lines.append(f' discord = "{owner["discord"]}";')
if owner.get("repo"):
owner_lines.append(f' repo = "{owner["repo"]}";')
lines.append(" owner = {")
for ol in owner_lines:
lines.append(ol)
lines.append(" };")
if description is not None:
lines.append(f' description = "{escape_nix_string(description)}";')
if proxy is not None:
lines.append(f" proxy = {'true' if proxy else 'false'};")
lines.append("in with dns.lib.combinators; {")
# Records
record_lines = build_record_lines(record)
for rl in record_lines:
lines.append(rl)
lines.append("}")
lines.append("")
return "\n".join(lines)
def escape_nix_string(s: str) -> str:
"""Escape special characters for a Nix double-quoted string."""
s = s.replace("\\", "\\\\")
s = s.replace('"', '\\"')
s = s.replace("${", "\\${")
return s
def build_record_lines(record: dict) -> list[str]:
"""Build the Nix record lines from the JSON record dict."""
lines = []
if "A" in record:
values = record["A"]
if isinstance(values, list):
if len(values) == 1:
lines.append(f' A = [ "{values[0]}" ];')
else:
lines.append(" A = [")
for v in values:
lines.append(f' "{v}"')
lines.append(" ];")
else:
lines.append(f' A = [ "{values}" ];')
if "AAAA" in record:
values = record["AAAA"]
if isinstance(values, list):
if len(values) == 1:
lines.append(f' AAAA = [ "{values[0]}" ];')
else:
lines.append(" AAAA = [")
for v in values:
lines.append(f' "{v}"')
lines.append(" ];")
else:
lines.append(f' AAAA = [ "{values}" ];')
if "CNAME" in record:
value = record["CNAME"]
if isinstance(value, list):
value = value[0]
lines.append(f' CNAME = [ "{value}." ];')
if "ALIAS" in record:
value = record["ALIAS"]
if isinstance(value, list):
value = value[0]
# ALIAS is typically handled as CNAME in dns.nix
lines.append(f' CNAME = [ "{value}." ];')
if "MX" in record:
values = record["MX"]
if isinstance(values, list):
lines.append(" MX = [")
for i, v in enumerate(values):
# MX records need priority; default to (i+1)*10
priority = (i + 1) * 10
lines.append(" {")
lines.append(f' exchange = "{ensure_fqdn(v)}";')
lines.append(f" preference = {priority};")
lines.append(" }")
lines.append(" ];")
else:
lines.append(" MX = [")
lines.append(" {")
lines.append(f' exchange = "{ensure_fqdn(values)}";')
lines.append(" preference = 10;")
lines.append(" }")
lines.append(" ];")
if "TXT" in record:
values = record["TXT"]
if isinstance(values, list):
if len(values) == 1:
lines.append(f' TXT = [ "{escape_nix_string(values[0])}" ];')
else:
lines.append(" TXT = [")
for v in values:
lines.append(f' "{escape_nix_string(v)}"')
lines.append(" ];")
else:
lines.append(f' TXT = [ "{escape_nix_string(values)}" ];')
if "NS" in record:
values = record["NS"]
if isinstance(values, list):
if len(values) == 1:
lines.append(f' NS = [ "{ensure_fqdn(values[0])}" ];')
else:
lines.append(" NS = [")
for v in values:
lines.append(f' "{ensure_fqdn(v)}"')
lines.append(" ];")
else:
lines.append(f' NS = [ "{ensure_fqdn(values)}" ];')
if "SRV" in record:
values = record["SRV"]
if isinstance(values, list):
lines.append(" SRV = [")
for srv in values:
lines.append(" {")
if "service" in srv:
lines.append(f' service = "{srv["service"]}";')
if "proto" in srv:
lines.append(f' proto = "{srv["proto"]}";')
if "port" in srv:
lines.append(f" port = {srv['port']};")
if "priority" in srv:
lines.append(f" priority = {srv['priority']};")
if "weight" in srv:
lines.append(f" weight = {srv['weight']};")
if "target" in srv:
lines.append(f' target = "{ensure_fqdn(srv["target"])}";')
lines.append(" }")
lines.append(" ];")
if "CAA" in record:
values = record["CAA"]
if isinstance(values, list):
lines.append(" CAA = [")
for caa in values:
lines.append(" {")
if "flags" in caa:
lines.append(f" flags = {caa['flags']};")
if "tag" in caa:
lines.append(f' tag = "{caa["tag"]}";')
if "value" in caa:
lines.append(f' value = "{escape_nix_string(caa["value"])}";')
lines.append(" }")
lines.append(" ];")
return lines
def ensure_fqdn(domain: str) -> str:
"""Ensure a domain name ends with a dot (FQDN)."""
if not domain.endswith("."):
return domain + "."
return domain
def migrate_file(json_path: Path, dry_run: bool = False, delete_json: bool = False) -> bool:
"""Migrate a single JSON file to .nix. Returns True on success."""
try:
with open(json_path, "r") as f:
data = json.load(f)
except json.JSONDecodeError as e:
print(f" ERROR: Failed to parse {json_path.name}: {e}", file=sys.stderr)
return False
nix_content = json_to_nix(data)
nix_filename = json_path.stem + ".nix"
nix_path = json_path.parent / nix_filename
if dry_run:
print(f"--- {nix_filename} ---")
print(nix_content)
return True
with open(nix_path, "w") as f:
f.write(nix_content)
print(f" Created {nix_path.name}")
if delete_json:
json_path.unlink()
print(f" Deleted {json_path.name}")
return True
def main():
dry_run = "--dry-run" in sys.argv
delete_json = "--delete-json" in sys.argv
if not DOMAINS_DIR.exists():
print(f"Error: domains directory not found at {DOMAINS_DIR}", file=sys.stderr)
sys.exit(1)
json_files = sorted(DOMAINS_DIR.glob("*.json"))
if not json_files:
print("No JSON files found in domains/")
sys.exit(0)
print(f"Found {len(json_files)} JSON file(s) to migrate")
if dry_run:
print("(dry run — no files will be written)\n")
success = 0
failed = 0
for json_path in json_files:
print(f"Migrating {json_path.name}...")
if migrate_file(json_path, dry_run=dry_run, delete_json=delete_json):
success += 1
else:
failed += 1
print(f"\nDone: {success} succeeded, {failed} failed")
if failed > 0:
sys.exit(1)
if __name__ == "__main__":
main()

View file

@ -1 +1 @@
32 31