NOC site for AS203496 served at noc.obr.sh
This commit is contained in:
commit
6758bda3cb
10 files changed
+102
No files matched your search
@@ -0,0 +1 @@
|
||||
public/
|
||||
@@ -0,0 +1,8 @@
|
||||
# noc-site
|
||||
|
||||
Static NOC site for AS203496, served at https://noc.obr.sh. `python3 build.py` writes `public/`.
|
||||
|
||||
- Brand name, domain, ASN, upstreams, contacts and PGP keys: `site.json` (rebrand = change `brand` and the contact fields there).
|
||||
- Prose: `content/*.txt`.
|
||||
- Deploy: copy `public/` to CT114 web-static `/opt/static-sites/sites/noc.obr.sh/current` (see `deploy.sh`).
|
||||
- noc.obnh.network returns 301 to https://noc.obr.sh (path kept), set up in the CT110 edge traefik and the CT114 nginx.
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the NOC site into ./public. Brand, domain and facts come from site.json; prose from content/*.txt."""
|
||||
import json, html, shutil, pathlib
|
||||
root = pathlib.Path(__file__).parent
|
||||
S = json.load(open(root / "site.json"))
|
||||
out = root / "public"
|
||||
shutil.rmtree(out, ignore_errors=True)
|
||||
shutil.copytree(root / "static", out)
|
||||
e = html.escape
|
||||
CSS = """:root{--bg:#fff;--fg:#1c1f24;--mut:#5b6470;--ac:#0b5cad;--bd:#d9dee4}
|
||||
@media (prefers-color-scheme:dark){:root{--bg:#14171b;--fg:#e6e9ed;--mut:#9aa4b0;--ac:#6cb2ff;--bd:#2d333b}}
|
||||
body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 system-ui,sans-serif}
|
||||
.w{max-width:46rem;margin:0 auto;padding:0 16px}header{border-bottom:1px solid var(--bd);padding:1rem 0}
|
||||
header a.b{font-weight:700;color:var(--fg);text-decoration:none}nav{margin-top:.4rem}nav a{margin-right:1rem}
|
||||
a{color:var(--ac)}h1{margin-top:2rem}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid var(--bd);padding:.4rem .5rem;text-align:left;vertical-align:top}
|
||||
th{color:var(--mut);font-weight:600;width:35%}code{word-break:break-all}footer{color:var(--mut);border-top:1px solid var(--bd);margin:3rem 0 2rem;padding-top:1rem;font-size:.9rem}"""
|
||||
NAV = [("/", "Home"), ("/peering/", "Peering"), ("/pgp/", "PGP keys"), ("/contact/", "Contact")]
|
||||
def paras(name):
|
||||
return "".join(f"<p>{e(l)}</p>" for l in (root / "content" / f"{name}.txt").read_text().splitlines() if l.strip())
|
||||
def page(path, title, body):
|
||||
nav = "".join(f'<a href="{u}">{t}</a>' for u, t in NAV)
|
||||
doc = f"""<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>{e(title)} - {e(S['brand'])}</title><meta name="description" content="{e(S['asn'])} {e(S['tagline'])}">
|
||||
<link rel="canonical" href="https://{S['domain']}{path}"><style>{CSS}</style></head><body>
|
||||
<header><div class="w"><a class="b" href="/">{e(S['brand'])}</a><nav>{nav}</nav></div></header>
|
||||
<main class="w">{body}</main><footer class="w">{e(S['brand'])} · {e(S['asn'])} · <a href="{S['peeringdb']}">PeeringDB</a></footer></body></html>"""
|
||||
d = out / path.strip("/"); d.mkdir(parents=True, exist_ok=True)
|
||||
(d / "index.html").write_text(doc)
|
||||
ups = "".join(f"<li>{e(u['asn'])} {e(u['name'])} ({e(u['site'])})</li>" for u in S["upstreams"])
|
||||
facts = f"""<table>
|
||||
<tr><th>ASN</th><td>{e(S['asn'])}</td></tr>
|
||||
<tr><th>Prefix</th><td><code>{e(S['prefix'])}</code> (IPv6 only)</td></tr>
|
||||
<tr><th>Upstreams</th><td><ul>{ups}</ul></td></tr>
|
||||
<tr><th>AS-SET</th><td><code>{e(S['as_set'])}</code> (RIPE)</td></tr>
|
||||
<tr><th>RPKI</th><td>ROA {e(S['prefix'])}, origin {e(S['asn'])}, maxLength 48; ASPA providers AS41051, AS6517</td></tr>
|
||||
<tr><th>PeeringDB</th><td><a href="{S['peeringdb']}">{S['peeringdb']}</a></td></tr>
|
||||
<tr><th>Policy</th><td>Open, IPv6 preferred</td></tr></table>"""
|
||||
page("/", S["tagline"], f"<h1>{e(S['brand'])}</h1><p><strong>{e(S['tagline'])}</strong></p>{paras('home')}<h2>Network facts</h2>{facts}")
|
||||
page("/peering/", "Peering", f"<h1>Peering</h1>{paras('peering')}{facts}")
|
||||
keys = "".join(f"<tr><th>{e(a)}</th><td><code>{e(f)}</code></td></tr>" for a, f in S["pgp"])
|
||||
page("/pgp/", "PGP keys", f"<h1>PGP keys</h1>{paras('pgp')}<table>{keys}</table>")
|
||||
c = S["contacts"]
|
||||
cbody = f"""<h1>Contact</h1>{paras('contact')}<table>
|
||||
<tr><th>NOC for {e(S['asn'])}</th><td><a href="mailto:{c['noc']}">{c['noc']}</a></td></tr>
|
||||
<tr><th>Abuse</th><td><a href="mailto:{c['abuse']}">{c['abuse']}</a></td></tr>
|
||||
<tr><th>Emergency</th><td>{e(c['phone'])}</td></tr>
|
||||
<tr><th>Threema</th><td>{e(c['threema'])}<br><img src="/threema-{c['threema']}.jpg" alt="Threema QR code" width="160"></td></tr></table>"""
|
||||
page("/contact/", "Contact", cbody)
|
||||
(out / "robots.txt").write_text(f"User-agent: *\nAllow: /\nSitemap: https://{S['domain']}/sitemap.xml\n")
|
||||
urls = "".join(f"<url><loc>https://{S['domain']}{u}</loc></url>" for u, _ in NAV)
|
||||
(out / "sitemap.xml").write_text(f'<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">{urls}</urlset>')
|
||||
print("built", S["domain"])
|
||||
@@ -0,0 +1 @@
|
||||
Send operational questions to the NOC address. Report abuse to the abuse address. For emergencies, call the number below. Threema is an alternative channel.
|
||||
@@ -0,0 +1,2 @@
|
||||
AS203496 is a small, IPv6-only network for research and training. It exists to learn, test and operate real internet infrastructure the way a production network would.
|
||||
The network announces one prefix, 2001:67c:1948::/48, from two sites. Each site has its own transit provider, so the network stays reachable if one upstream fails.
|
||||
@@ -0,0 +1,4 @@
|
||||
Peering is welcome. AS203496 peers directly where your network shares a facility (a meet-me room) or an internet exchange.
|
||||
The network prefers IPv6. Direct sessions are IPv6 only. IPv4 sessions are set up only with IXP route servers, and there are no direct IPv4-only sessions. For direct peerings and interconnects, an MD5 password is appreciated.
|
||||
Customers of AS203496 are not treated as peers at any location. Transit can be provided where that is feasible.
|
||||
For filtering, use the AS-SET AS203496:AS-OBNH-NETWORK (RIPE). The route6 object and the ROA both cover 2001:67c:1948::/48 with origin AS203496, and an ASPA record lists AS41051 and AS6517 as providers.
|
||||
@@ -0,0 +1 @@
|
||||
Public keys for signed and encrypted mail are listed below.
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
# Build and push public/ to web-static CT114 on nibbler (nibbler tailnet 100.82.124.16).
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
python3 build.py
|
||||
tar czf - -C public . | ssh root@100.82.124.16 'pct exec 114 -- sh -c "rm -rf /opt/static-sites/sites/noc.obr.sh/current.new && mkdir -p /opt/static-sites/sites/noc.obr.sh/current.new && tar xzf - -C /opt/static-sites/sites/noc.obr.sh/current.new && rm -rf /opt/static-sites/sites/noc.obr.sh/current.old; [ -d /opt/static-sites/sites/noc.obr.sh/current ] && mv /opt/static-sites/sites/noc.obr.sh/current /opt/static-sites/sites/noc.obr.sh/current.old; mv /opt/static-sites/sites/noc.obr.sh/current.new /opt/static-sites/sites/noc.obr.sh/current"'
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"brand": "OBNH Network Baumert",
|
||||
"domain": "noc.obr.sh",
|
||||
"old_domain": "noc.obnh.network",
|
||||
"tagline": "IPv6-only training and research network",
|
||||
"asn": "AS203496",
|
||||
"prefix": "2001:67c:1948::/48",
|
||||
"as_set": "AS203496:AS-OBNH-NETWORK",
|
||||
"upstreams": [
|
||||
{"asn": "AS41051", "name": "FreeTransit (Openfactory)", "site": "leela"},
|
||||
{"asn": "AS6517", "name": "Lake Networks", "site": "kiff"}
|
||||
],
|
||||
"peeringdb": "https://www.peeringdb.com/net/30644",
|
||||
"contacts": {
|
||||
"noc": "noc@obnh.network",
|
||||
"abuse": "abuse@obnh.network",
|
||||
"phone": "+41 76 263 0152",
|
||||
"threema": "XKSBXYFZ"
|
||||
},
|
||||
"pgp": [
|
||||
["admin@obnh.network", "05dc62d7ab054e72c6aea639ba0ee08972efd755"],
|
||||
["admin@obnh.org", "b6475ed1ff426b3c16b7366c3450c39c710127f1"],
|
||||
["noc@obnh.network", "f50d798f7b7e1a84fe5d0b8f828c4b32f92444c6"],
|
||||
["olaf@baumert.cc", "cf8e073a7bba64da51308540638a2a01c171b4f9"],
|
||||
["olaf@obnh.network", "8ac0a93854d0a59ec28c8b4dd0a70dba97115a8a"]
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
Reference in new issue
Block a user