🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 6 Min Lesezeit
0

Someone said "let's make a new internet" — sarcastically.

↗ Quelle (dev.to)
🗣️ Stimme:

Thomas Verhave

Home

Projects

Writing



Writing · Build Notes

I built a tiny alternative internet in pure Python — a protocol, a browser, and a firewall



Someone said "let's make a new internet" — sarcastically.



Someone said "let's make a new internet" — sarcastically. So I made a working one.



Not a metaphor, not a framework. weft is a small line-based protocol over raw TCP, with its own address scheme, its own markup, a terminal browser that speaks it, and an application-layer firewall you can drive in the browser. Three little servers link to each other to form a network. It's all pure Python standard library — zero dependencies — and the whole thing is a few hundred lines.



It will never scale to a billion users. That was the point.

The bet



The web we have is heavy. Every page drags a megabyte of JavaScript to show a paragraph of text, and something is always measuring you. weft is the opposite bet, and the whole design falls out of four rules:




CODE
text first, always
no client-side code, so there's no surveillance surface
a page is a file you can read with cat
the network is small enough to hold in your head




Here's what building each layer taught me.

Layer 1 — the protocol



I didn't want HTTP. HTTP is enormous once you include everything real clients expect. So weft borrows its shape from Gemini: a request is one line, a response is one status line then the body.



address: weft://host:port/path

request: GET /path\n

response: 20 text/weft\n ...then the body bytes



Four status codes, deliberately. That's the entire vocabulary:



20 ok, body follows

30 redirect, body is the new address

40 not found

50 server error



The client is almost nothing — one connection, one page, then the socket closes:



def fetch(addr, *, timeout=5.0):

with socket.create_connection((addr.host, addr.port), timeout=timeout) as sock:

sock.sendall(f"GET {addr.path}\n".encode())

sock.shutdown(socket.SHUT_WR) # I'm done writing; send me the page

raw = b""

while chunk := sock.recv(65536):

raw += chunk

header, _, body = raw.partition(b"\n")

status, _, meta = header.decode(errors="replace").partition(" ")

return Response(int(status), meta, body)



That shutdown(SHUT_WR) is the whole flow-control story: the client half-closes to say "I've sent my one line, everything you send back is the response." No content-length, no chunked encoding, no keep-alive. The connection is the framing.



(The default port is 1965 — a wink at Gemini. The year, not the protocol.)

Layer 2 — the markup



If a page is meant to be readable with cat, the markup has to be plain text that already looks right. So .weft pages are line-based, like Gemtext. A line starting with => is a link; # and ## are headings; everything else is a paragraph.






a small manifesto



The web we have is heavy. weft is the opposite bet:

text first, no client-side code, a page you can read with cat.



=> / home

=> weft://127.0.0.1:1966/ visit the garden



No inline styling, no nesting, no ambiguity. The parser is a for loop over splitlines(). Because links live on their own lines, the terminal browser can just number them and let you follow a link by typing its number — no cursor, no mouse.

Layer 3 — the server



Each "node" serves one site (a folder of .weft files) with a thread per connection. The only real defensive code is path-traversal protection — map a request path to a file under the root, or refuse:



def resolve(root, path):

rel = path.lstrip("/") or "index.weft"

candidate = (root / rel).resolve()

if root.resolve() not in candidate.parents and candidate != root.resolve():

return None # tried to escape the site root — deny

return candidate if candidate.is_file() else None



Three nodes run on ports 1965/1966/1967, and their pages link to each other with weft:// addresses — so you get an actual little inter-network you can browse between.

Layer 4 — the browser



The browser is a terminal REPL. It fetches a page, renders the text, prints the links as a numbered list, and waits:



follow that link

b back

r reload

g go to a weft:// address

q quit



That's the entire client. It's oddly calming to use — no tabs, no spinner, no cookie banner. Just text and numbered doors.

Layer 5 — the firewall (the fun part)



This is where it stopped being a toy for me. I put an application-layer firewall in front of a node — a filtering gateway that inspects every connection (source IP + requested path), evaluates an ordered ruleset, enforces a default policy and rate limits, logs every decision, then transparently forwards allowed traffic to the backend.



The ruleset reads like an iptables chain or a pf config — first match wins, default-deny:



policy deny






a loose overall cap, plus a tighter one just for search



ratelimit 10/10s

ratelimit 2/10s path /search*



deny path /admin* # nobody reaches the admin area

allow from 127.0.0.0/8 path / # loopback is trusted

allow from 127.0.0.0/8 path /manifesto

deny from 192.0.2.0/24 # a blocked network (RFC 5737 TEST-NET)






everything else falls through to policy deny



Conditions AND together; a rule with no conditions is a catch-all. Matching is CIDR for sources and shell-glob for paths (/admin* catches /admin/keys). And because editing rules shouldn't drop live connections, it hot-reloads on SIGHUP:



kill -HUP # re-reads firewall.rules without closing the socket



Writing a default-deny, first-match-wins engine by hand is the single best way I've found to actually understand why firewall rule order matters — you feel it the moment you put an allow after a deny that shadows it.

The part that surprised me



The same rule engine runs in the browser. The project page has a live simulator where you can type a source IP and a path, watch the rules evaluate top-to-bottom, and see exactly which line decides the verdict — driven by a JavaScript port of the same logic in firewall.py. Building it twice, in two languages, forced me to write the rules as data rather than control flow, which made both versions cleaner.

What I actually learned




CODE
Constraints are a design tool. "No client-side code" isn't a limitation, it's what makes the markup, the browser, and the privacy story all fall into place at once.
The stdlib is bigger than you think. socket, threading, dataclasses, re, pathlib, fnmatch, ipaddress — that's the entire dependency list, and it's plenty to build a protocol stack.
You understand a thing when you rebuild it. I've used firewalls for years; I only really got rule-order shadowing and default-deny posture after writing 380 lines that enforce them.




A build-story · see the live project → · more writing →

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Someone said "let's make a new internet" — sarcastically.

Thematisch verwandte Begriffe: Someone, said, lets, make · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...