Skip to content
DevOps devops networking 6 min read

HTTP & HTTPS Explained

Almost everything you do on the web rides on HTTP (HyperText Transfer Protocol — the language browsers and servers use to talk). When you open a website, your browser sends an HTTP request and the server sends back an HTTP response. HTTPS is the same protocol with a layer of encryption added on top. As a DevOps engineer you will spend a lot of time reading these requests and responses to figure out why a site is slow, broken, or returning the wrong page — so it pays to understand them deeply.

The request/response model

HTTP is a request/response protocol. The client (usually a browser, but it can be a command-line tool like curl) asks for something, and the server replies. Each exchange is independent — the server does not, by default, remember anything about previous requests. This is called being stateless. Cookies and sessions are bolted on later to add memory.

A single request has four parts:

  1. A method (also called a verb) — what you want to do, like GET or POST.
  2. A path — which resource on the server, like /index.html or /api/users.
  3. Headers — extra key/value information about the request (who is asking, what formats they accept, etc.).
  4. An optional body — data you are sending, used mostly with POST and PUT.

The response mirrors this: a status code (a number saying how it went), headers, and usually a body (the HTML page, JSON data, image, and so on).

Common HTTP methods

The method tells the server your intent. The two you will see most are GET and POST.

MethodWhat it doesHas a body?When to use it
GETFetch a resource. Should not change anything.NoLoading a page, reading data from an API.
POSTSend data to create something.YesSubmitting a form, creating a new record.
PUTReplace a resource entirely.YesUpdating a record when you send the full object.
PATCHUpdate part of a resource.YesChanging one field of a record.
DELETERemove a resource.No (usually)Deleting a record.
HEADLike GET but returns headers only, no body.NoChecking if a page exists or its size, cheaply.

Treat GET as read-only. A GET request should never change data on the server. Search engines and browsers freely re-send GET requests, so if a GET deletes something you will lose data by accident.

Status code families

The server’s reply always starts with a three-digit status code. The first digit tells you the broad category, so learning the five families gets you 90% of the way.

FamilyMeaningCommon examples
1xxInformational — request received, still processing.100 Continue
2xxSuccess — it worked.200 OK, 201 Created, 204 No Content
3xxRedirection — go look somewhere else.301 Moved Permanently, 302 Found, 304 Not Modified
4xxClient error — you (the caller) did something wrong.400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
5xxServer error — the server broke.500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable

The most useful debugging rule: 4xx means fix your request, 5xx means fix the server. For example, a 502 Bad Gateway from Nginx almost always means your application behind it (a reverse proxy is a server that sits in front of your app and forwards requests to it) is down or crashed — check the app, not Nginx.

Headers

Headers carry metadata. A few you will meet constantly:

  • Host — which website you want (one server can host many). Required in HTTP/1.1.
  • User-Agent — what client is asking (browser name, or curl/8.5.0).
  • Content-Type — the format of the body, e.g. application/json or text/html.
  • Authorization — credentials, e.g. a bearer token for an API.
  • Cache-Control — how long the response may be cached.
  • Location — where to go next (sent with 3xx redirects).

Inspecting a request with curl

curl is a command-line tool for making HTTP requests, perfect for debugging from a server where there is no browser. The -v (verbose) flag shows the full request and response, including headers. Install it on Ubuntu if it is missing:

sudo apt update
sudo apt install -y curl

Now make a verbose request:

curl -v https://example.com

Output:

*   Trying 93.184.216.34:443...
* Connected to example.com (93.184.216.34) port 443
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=example.com
*  start date: Jan 30 00:00:00 2026 GMT
*  expire date: Mar  1 23:59:59 2027 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS RSA SHA256 2020 CA1
*  SSL certificate verify ok.
> GET / HTTP/2
> Host: example.com
> user-agent: curl/8.5.0
> accept: */*
>
< HTTP/2 200
< content-type: text/html; charset=UTF-8
< date: Mon, 15 Jun 2026 10:12:44 GMT
< cache-control: max-age=604800
< content-length: 1256
<
<!doctype html>
<html>
...

Lines starting with > are what you sent; lines with < are the response. Lines with * are connection notes from curl. This is the single most useful command for understanding why a request behaves a certain way.

Other handy flags:

curl -I https://example.com          # headers only (sends a HEAD request)
curl -X POST -d '{"name":"sam"}' \
  -H 'Content-Type: application/json' \
  https://api.example.com/users      # send a POST with a JSON body
curl -L https://example.com          # follow redirects automatically

How HTTPS adds TLS encryption

Plain HTTP sends everything as readable text. Anyone between you and the server — your ISP, a coffee-shop Wi-Fi router, an attacker — can read or change it. HTTPS fixes this by wrapping HTTP inside TLS (Transport Layer Security — the modern successor to the older SSL).

TLS does three things:

  1. Encryption — scrambles the data so eavesdroppers see gibberish.
  2. Integrity — detects if anyone tampered with the data in transit.
  3. Authentication — proves the server really is example.com, using a certificate signed by a trusted authority.

When a client connects, it performs a TLS handshake: it agrees on encryption settings and verifies the server’s certificate before any HTTP data flows. You can see this happening in the * Server certificate: lines of the curl output above. HTTPS runs on port 443 by default; plain HTTP uses port 80.

You should always use HTTPS in 2026 — browsers mark plain HTTP sites as “Not Secure”. Free, auto-renewing certificates are available from Let’s Encrypt via the certbot tool:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

This obtains a certificate, edits your Nginx config to enable HTTPS, and sets up automatic renewal via a systemd timer.

A certificate expires (usually after 90 days for Let’s Encrypt). If renewal fails, visitors get scary browser warnings. Check the renewal timer with sudo systemctl status certbot.timer and test it with sudo certbot renew --dry-run.

Best Practices

  • Always serve sites over HTTPS and redirect plain HTTP (port 80) to HTTPS (port 443) with a 301.
  • Use curl -v as your first debugging step — it shows the exact request, response code, and headers.
  • Read the status code first: 4xx points at the request, 5xx points at the server.
  • Keep GET requests side-effect free; use POST/PUT/PATCH/DELETE for changes.
  • Set Content-Type correctly when sending a body, or APIs may reject your request.
  • Automate certificate renewal and monitor expiry so HTTPS never silently breaks.
  • Check application logs in /var/log/nginx/error.log when you see 502 or 504 from a reverse proxy.
Last updated June 15, 2026
Was this helpful?