---
title: "01 — Internet Fundamentals for the Backend — The Same Stack, Viewed From the Other End"
uid: internet-fundamentals
tags: ["dns", "roadmap:backend", "networking", "internet", "hosting", "http", "fundamentals"]
excerpt: "The internet stack, re-read from the server's side. The backend lives at the same layers as the frontend — its job is just the opposite: to answer, not to ask."
date: 2026-08-13T03:28:28+0000
source: https://www.aveshina.my.id/en/blog/internet-fundamentals
---

I first learned the internet stack — browser, HTTP, DNS, the network below — as a frontend concern. Re-reading it a second time with the server in mind collapsed it into a simpler frame: **the backend lives at the exact same layers, but its job is to answer, not to ask.** [1] Everything a client does as a request, a server does as a response, over the same conversation.

The shift that mattered for me was directional. The frontend *initiates*; the backend *listens*. A browser types a domain, resolves it, opens a connection, and sends a request. The server's whole existence is sitting on a port, accepting that connection, and producing a response. Once I could see that the server is just the other endpoint of one shared stack, most of "backend" stopped feeling like a separate world.

```figure
<svg viewBox="0 0 740 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Two columns: left is the CLIENT stack (Browser, HTTP, OS+packets) with arrows pointing right labelled request. Right is the SERVER stack in reverse (listening process on a port, HTTP, OS+packets) with an arrow pointing left labelled response. A DNS box in the middle resolves the name for both. The two OS bars at the bottom are connected by a single network line.">
  <defs>
    <marker id="biarrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
      <path d="M0,0 L10,5 L0,10 z" fill="#64748b"/>
    </marker>
  </defs>
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- headers -->
    <text x="150" y="24" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">CLIENT — initiates</text>
    <text x="370" y="24" font-size="12" font-weight="700" fill="#500724" text-anchor="middle">DNS — consulted by both</text>
    <text x="590" y="24" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">SERVER — listens</text>

    <!-- client stack -->
    <rect x="80" y="40" width="140" height="44" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="150" y="61" font-size="13" font-weight="700" fill="#1e1b4b" text-anchor="middle">Browser</text>
    <text x="150" y="76" font-size="10" fill="#475569" text-anchor="middle">renders the response</text>

    <rect x="80" y="104" width="140" height="44" rx="8" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="150" y="125" font-size="13" font-weight="700" fill="#422006" text-anchor="middle">HTTP</text>
    <text x="150" y="140" font-size="10" fill="#475569" text-anchor="middle">request / response lines</text>

    <!-- DNS -->
    <rect x="310" y="40" width="120" height="44" rx="8" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="370" y="61" font-size="13" font-weight="700" fill="#500724" text-anchor="middle">DNS</text>
    <text x="370" y="76" font-size="10" fill="#500724" text-anchor="middle">name → number</text>

    <!-- server stack -->
    <rect x="520" y="40" width="140" height="44" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="590" y="61" font-size="13" font-weight="700" fill="#052e16" text-anchor="middle">Server process</text>
    <text x="590" y="76" font-size="10" fill="#052e16" text-anchor="middle">bound to a port</text>

    <rect x="520" y="104" width="140" height="44" rx="8" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="590" y="125" font-size="13" font-weight="700" fill="#422006" text-anchor="middle">HTTP</text>
    <text x="590" y="140" font-size="10" fill="#475569" text-anchor="middle">same protocol, other end</text>

    <!-- request arrow -->
    <line x1="222" y1="126" x2="518" y2="126" stroke="#64748b" stroke-width="1.5" marker-end="url(#biarrow)"/>
    <text x="370" y="120" font-size="10" fill="#475569" text-anchor="middle">▸ request (GET /)</text>

    <!-- network bar -->
    <rect x="80" y="180" width="580" height="70" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="370" y="202" font-size="13" font-weight="700" fill="#1e1b4b" text-anchor="middle">OS + cables + TCP/IP — packets routed by IP</text>
    <line x1="110" y1="230" x2="630" y2="230" stroke="#64748b" stroke-width="1.5" marker-end="url(#biarrow)"/>
    <text x="370" y="226" font-size="10" fill="#475569" text-anchor="middle">◂ response · HTML / JSON</text>
  </g>
</svg>
```

## HTTP: the conversation the backend answers

The conversation is HTTP — a stateless, line-by-line protocol of requests and responses [3]. The frontend vocabulary (methods, status codes, headers) is the same vocabulary the backend speaks back. The difference is who's producing each part:

- A **request** arrives carrying a method (GET, POST, PUT, DELETE) and a path. The backend's job is to decide what to do with that verb-noun pair.
- A **response** leaves carrying a status code (200 ok, 404 not found, 500 server error) and a body. That code is the backend's first and most honest signal to the client.

Statelessness is the detail that shapes backend architecture more than any other. Because the server remembers nothing between requests, anything that must persist — a login, a cart, a draft — has to be sent back by the client (a token, a cookie) or stored server-side under a key the client carries. Sessions, JWTs, and the whole auth layer exist to fake the memory HTTP refuses to provide.

## HTTPS: the same conversation, encrypted

HTTPS is not a different protocol; it's HTTP wrapped in TLS so nobody between client and server can read or alter the exchange [7]. From the backend's side this matters twice over: the server is the side that holds the TLS certificate, and the server is the side that terminates the encryption before handing the plaintext request to the application code. Termination often happens at a reverse proxy (Nginx, a load balancer) rather than in the app process — a separation I'll come back to when I get to web servers.

## Hosting: a process on a box, listening on a port

"There is no cloud" is the line that did the most work for me. A backend is an ordinary program running on an ordinary machine in a rack somewhere [4]. The program binds to a port (say :3000), and the machine's operating system forwards incoming connections on that port to the process. Hosting is renting that machine plus its always-on connection to the network.

The flavors of hosting are the same layer, differing only in how much of the box I'm willing to manage:

- **Shared / VPS / dedicated** — a slice of a real machine, more or less isolated.
- **PaaS** — I push code, the provider runs the process and binds the port.
- **Serverless / edge** — I stop thinking about the box entirely; the provider runs my function on machines near each user.

The trade-off is always control versus convenience. A VPS gives me root and a port; serverless gives me a function signature and nothing else.

## Naming: domains and DNS, the layer the server hides behind

No client connects to my box by IP — they connect by name. DNS is the distributed phonebook that resolves aveshina.my.id into the number my machine owns, consulted in milliseconds before every connection [5][6]. The lookup fans out through a hierarchy — recursive resolver, root, TLD, then the authoritative nameserver for my domain — and each level is cached so most lookups never make the full trip.

For the backend, the practical consequence is that DNS is the first thing I configure when I deploy. The domain's A (or CNAME) record has to point at my box's IP (or my provider's load balancer) before any traffic can arrive. A misconfigured DNS record is the highest-on-the-stack failure mode: the request never reaches me at all.

```
dig +short aveshina.my.id
```

```
76.76.21.21
```

A name resolving to a number is the last step before the request becomes my problem. Once that number comes back, the client opens a TCP connection to it, and the bottom layer takes over.

## The network: packets, IPs, and one shared agreement

The bottom layer is plumbing — cables (including undersea ones), routers, and TCP/IP, the protocol every network agreed to speak so they could hand data to each other [1][2]. Data moves as **packets**, small self-addressed units routed independently and reassembled at the destination. Every device has an **IP address** that routers use to forward packets roughly in the right direction.

The part that clicked for me as a backend author: my process never sees raw packets. The OS's network stack reassembles them, hands my process a continuous byte stream over the socket, and my HTTP library parses that stream into a request object. The layers below the port are someone else's responsibility — the kernel's, the provider's, the internet's. My code starts at "a connection arrived on my port."

## How I use this

The payoff is diagnostic, the same as on the frontend — except now I'm debugging from the answering end. When a request fails to reach my server, I walk the stack top-down:

- Does the domain resolve? dig it. If not, **DNS**.
- Does it resolve to the right IP? Check the A record vs. the box. If not, **DNS or the provider's routing**.
- Can I reach the port from outside? curl or telnet. If not, **firewall, security group, or the process isn't running**.
- The request arrived but the response is wrong? Now it's **my code** — the HTTP layer, the status code, the body.

Naming the layer before reaching for a fix is the whole habit. The backend isn't a separate internet; it's the same stack, viewed from the port that answers.

## References

[1] cs.fyi, "How does the Internet work?," 2020. [Online]. Available: [https://cs.fyi/guide/how-does-internet-work](https://cs.fyi/guide/how-does-internet-work)

[2] "The Internet Explained," Vox, 2014. [Online]. Available: [https://www.vox.com/2014/6/16/18076282/the-internet](https://www.vox.com/2014/6/16/18076282/the-internet)

[3] Cloudflare, "What is HTTP?," 2024. [Online]. Available: [https://www.cloudflare.com/en-gb/learning/ddos/glossary/hypertext-transfer-protocol-http/](https://www.cloudflare.com/en-gb/learning/ddos/glossary/hypertext-transfer-protocol-http/)

[4] Mozilla, "What is a web server?," MDN Web Docs. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Web_mechanics/What_is_a_web_server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Web_mechanics/What_is_a_web_server)

[5] Cloudflare, "What is DNS?," 2024. [Online]. Available: [https://www.cloudflare.com/en-gb/learning/dns/what-is-dns/](https://www.cloudflare.com/en-gb/learning/dns/what-is-dns/)

[6] "How DNS works," howdns.works. [Online]. Available: [https://howdns.works/](https://howdns.works/)

[7] "How HTTPS works," howhttps.works. [Online]. Available: [https://howhttps.works/](https://howhttps.works/)

```quiz
Q: What is the backend's directional role in the HTTP conversation?
- It initiates requests to clients
- It listens on a port and produces responses to incoming requests
correct: 1
explain: The client initiates; the server listens and answers. They speak the same HTTP protocol, just from opposite ends.

Q: HTTP is stateless. What consequence does that have for backend design?
- The server must remember every client between requests
- Anything that must persist (login, cart) has to be sent back by the client or stored server-side under a key the client carries
correct: 1
explain: Statelessness means the server remembers nothing between requests. Sessions, tokens, and cookies exist precisely to fake the memory HTTP refuses to provide.

Q: Where does TLS termination typically happen in a backend deployment?
- Always inside the application process
- Often at a reverse proxy or load balancer, before traffic reaches the app
correct: 1
explain: TLS is frequently terminated at a reverse proxy (Nginx, a load balancer) which then forwards plaintext to the app process. Separating termination from app code is a common pattern.

Q: A request fails to reach your server. Following the top-down diagnostic, after confirming DNS resolves, what do you check next?
- Your application's response body
- Whether the resolved IP is correct and whether the port is reachable (firewall, security group, process running)
correct: 1
explain: Before the response body matters, the request has to physically arrive. After DNS, the next suspects are the IP mapping, the firewall/security group, and whether the process is bound to the port.

Q: "There is no cloud." A backend actually runs as…
- a process bound to a port on a machine somewhere
- an abstract distributed entity with no physical location
correct: 0
explain: A backend is a program on an ordinary machine, bound to a port, with the OS forwarding incoming connections. Hosting is renting that machine and its network connection.
```
