Back to blog
Writeup May 24, 2026 9 min read

Three Vilnius Tech labs in one semester: Wireshark, a DAoC server, and a Hugo blog

By Armandas Kaleinykas (ITnt-25)

This semester at Vilnius Tech I went through three labs ("namų darbas" — ND) for the Debesų kompiuterija (Cloud Computing) course. Each one tackled a different layer of the stack: ND1 was raw packets, ND2 was a full game server, ND3 was deploying a website. Together they make a surprisingly tidy tour of how the internet actually works, from "who-has-this-IP" to "deploy-with-one-command". Here is what I built and what surprised me.

ND1 — Wireshark: looking at the network through a window

The brief was to use Wireshark to capture and dissect five different protocols against my actual home network and a public server.

What I caught:

  • ARP — flushed the Windows ARP cache with netsh interface ip delete arpcache, then pinged my gateway (192.168.0.1). Wireshark caught the broadcast Who has 192.168.0.1? Tell 192.168.0.95 and the unicast reply from the TP-Link router with MAC a8:42:a1:0b:15:54 — classic request/reply with the target MAC zeroed out before resolution.
  • DHCP ipconfig /release + /renew triggered the full DORA cycle (Discover, Offer, Request, ACK) plus a Release. The ACK carried a 2-hour lease in option 51, and five IPs showed up across the packets, each with a different role.
  • DNS nslookup vilniustech.lt returned 158.129.192.195. Authoritative servers alfa.vgtu.lt and rasa.vgtu.lt; the SOA responsible mail addr decoded to it@vilniustech.lt. DNS over UDP/53, source ports incrementing as queries went out.
  • tracert — to a server in Toronto, 16 hops, ~7,450 km. Theoretical minimum RTT through fiber: 2 × 7450 / 200000 = 74.5 ms. Real ping: 121 ms. The difference is router queuing, encoding overhead, and the route not being a straight line.
  • Telnet — connected to a Realms of Despair MUD server on port 4000 and watched my own password go down the wire in plaintext in the TCP stream. A solid argument for SSH.

What surprised me: how little you need on top of ARP, DHCP and DNS for everything to work. Three small protocols, and the entire LAN self-organises without anyone configuring anything.

ND2 — MMO Serveris: same game, two architectures

Brief: stand up a private Dark Age of Camelot game server, then re-stand it up a second way, and compare the times.

Part A — manual Windows install (~75 minutes)

  • Windows Server 2022 VM on Azure (Standard_D2s_v3, North Europe)
  • MariaDB 10.11 + HeidiSQL + .NET 10 runtime + DOLServer 2.2.9.3910
  • Patched serverconfig.xml from SQLite to MySQL, hard-coded RegionIP to the public IP (DetectRegionIP=False) to fix "unable to connect to world", and swapped game.dll for an older client-compatible version
  • Dual-boxed two clients on the same host with a renamed camelot2.exe (single-instance mutex bypass)

Part B — Docker Compose on Ubuntu (~12 minutes)

services:
  db:
    image: mariadb:10.6
    container_name: opendaoc-db
    environment:
      MYSQL_DATABASE: opendaoc
      MYSQL_ROOT_PASSWORD: ***
  gameserver:
    image: ghcr.io/opendaoc/opendaoc-core:latest
    container_name: opendaoc-server
    ports:
      - "10300:10300"
      - "10400:10400"
    depends_on: [db]
    environment:
      SERVER_NAME: "Armandas"
      DB_CONNECTION_STRING: "server=db;port=3306;database=opendaoc;userid=root;password=***;treattinyasboolean=true"

Shipped via cloud-init so the first boot of an Ubuntu VM is enough to get both containers running.

Windows manualDocker Compose
Time to "open for connections"~75 min~12 min
Reproducible?not reallyyes (docker compose up -d)
Reliable on first try?needed config patchingneeded an up -d re-run for a race
Client compatibilityolder game.dll neededOpenDAoC wanted v1.127; my v1109 client → receive-buffer overflow

The container path was roughly 6× faster to bring up, and the whole setup lives in one docker-compose.yml. The trade-off was a client version mismatch in OpenDAoC that DOLServer happened to tolerate — a reminder that "containerised" does not mean "compatibility-free".

ND3 — Hugo + git: kill the VM, host for free

Brief: build a static page with nginx on a Linux VM, then build a real blog with Hugo and host it free on GitHub Pages.

  • The nginx VM should have used Standard_B1s (free tier on Azure for Students), but B1s came back SkuNotAvailable - Capacity Restrictions in 9 regions I tried. Fell back to Standard_D2s_v3 in eastus2. The full nginx + neofetch install + a custom index.html went in via one az vm run-command invoke call — no SSH needed for setup.
  • For the Hugo half: two GitHub repos linked by a submodule. Source (.md, theme, config) lives in a private repo; compiled HTML lives in the public dason222.github.io repo, mounted into the source repo as public/ via git submodule add -b main. Theme: Beautiful Hugo.
  • Once that was up the Azure VM was deleted the same day — the live site costs nothing to keep online.

What surprised me: the az vm run-command invoke workflow. Shell-scripting a remote Linux VM by uploading a script to the Azure control plane (no SSH key wrangling, no ports to open) is much cleaner than I expected — essentially "poor-man's Ansible" without the inventory file.

What ties the three labs together

Looking back, ND1 → ND2 → ND3 is basically an OSI-layer climb:

  • ND1 lives on L2/L3/L4 — frames, IP, ARP, UDP, TCP.
  • ND2 lives on L7 infrastructure — a real application, but you choose how to package and deploy it.
  • ND3 lives above the VM entirely — you stop caring about the machine and ship to a managed Pages provider.

The cost goes the same way: ND1 cost €0 (my own machine), ND2 burned the most credits (Windows D2s_v3 over several days), ND3 burns €0 forever now that the VM is torn down.

Resources

The full writeup, lab reports, and source live on GitHub. If you are also at Vilnius Tech and stuck on one of these, ping me there.

Related Articles

Last updated: May 2026