Hosting a website on an 8-bit microcontroller
Hosting a website on an 8-bit microcontroller
在 8 位微控制器上托管网站
2026-05-11 — 2026-05-14 (Electronics) (Programming) 2026-05-11 — 2026-05-14(电子)(编程)
In today’s episode of “dumb things to do with an AVR microcontroller”: Does your server come with real wood? MCU website demo (may go down if this gets posted to HN). 在今天这期“用 AVR 微控制器做蠢事”的节目中:你的服务器是用实木做的吗?MCU 网站演示(如果这篇文章被发到 Hacker News 上,网站可能会挂掉)。
My victim is the AVR64DD32 which is quite similar to the Atmega328 of Arduino fame. Compared to the older Atmega, these AVR DD lines are cheaper for the same memory, use a single programming pin and have nicer peripherals: 我的“受害者”是 AVR64DD32,它与大名鼎鼎的 Arduino 所用的 Atmega328 非常相似。与老款 Atmega 相比,这些 AVR DD 系列在相同内存下更便宜,使用单引脚编程,并且拥有更好的外设:
- CPU: Single 8-bit AVR core @ 24 MHz (max)
- RAM: 8 kB (static RAM)
- Flash: 64 kB
- EEPROM: 256 bytes
- Voltage: 1.8 - 5.5 Volts
- Cost: $1
- CPU:单核 8 位 AVR,主频 24 MHz(最大)
- RAM:8 kB(静态内存)
- 闪存:64 kB
- EEPROM:256 字节
- 电压:1.8 - 5.5 伏
- 成本:1 美元
So that’s the computer (a rather spacious one at that) but it’ll need an internet connection to host a website. The obvious choice is Ethernet, but even the slowest version (10BASE-T) still runs at 10 megabits/second. Worse, it uses Manchester encoding: a zero is sent as “10” and a one as “01”, so 10 megabits of data is actually 20 megabits at the wire. This is simply too fast for the AVR to generate. While it’s processor can run at 24 MHz, but all the peripherals and IO pins max out at a 12 MHz clock. (although some other 8-bit chips should be able to do it) 这就是这台计算机(空间相当充裕),但要托管网站,它需要连接互联网。显而易见的选择是以太网,但即使是最慢的版本(10BASE-T)运行速度也达到了 10 Mbps。更糟糕的是,它使用曼彻斯特编码:0 被发送为“10”,1 被发送为“01”,因此 10 Mbps 的数据在物理线路上的实际速率是 20 Mbps。这对 AVR 来说太快了,无法生成。虽然它的处理器可以运行在 24 MHz,但所有外设和 IO 引脚的时钟频率上限仅为 12 MHz。(尽管其他一些 8 位芯片或许能做到)
The proper solution is to buy a dedicated ethernet chip from DigiKey, but then I’d be waiting weeks to finish this project. … and ethernet is far from the only option: Serial Line Internet Protocol (RFC 1055) is a very old and very simple standard for running networks over serial: 正规的解决方案是从 DigiKey 买一个专用的以太网芯片,但我得等上几周才能完成这个项目……而且以太网远非唯一的选择:串行线路网际协议(SLIP,RFC 1055)是一种非常古老且简单的标准,用于通过串口运行网络:
Before sending a packet, wrap it in 0xC0 bytes. If the packet contains any 0xC0 bytes, replace them with 0xDB 0xDC. To avoid ambiguity, any pre-existing 0xDB bytes are replaced with 0xDB 0xDD. This scheme was widely used for connecting to the internet in the olden days: A dial up modem creates a serial link over a phone line, and it’s up the the computer to do anything with it. (This also means that they are not limited to networking: those same modems could be connected to a terminal for remote access) 在发送数据包之前,用 0xC0 字节将其包裹起来。如果数据包中包含任何 0xC0 字节,则将其替换为 0xDB 0xDC。为了避免歧义,任何预先存在的 0xDB 字节都会被替换为 0xDB 0xDD。这种方案在过去被广泛用于连接互联网:拨号调制解调器通过电话线创建串行链路,剩下的工作由计算机处理。(这也意味着它们不仅限于网络:同样的调制解调器也可以连接到终端进行远程访问)
… which is why SLIP is still supported by modern Linux: ……这就是为什么现代 Linux 仍然支持 SLIP:
# Just a normal USB to Serial adapter
stty -F /dev/ttyUSB0 115200 raw cs8
slattach -m -F -L -p slip /dev/ttyUSB0
# ... and now it's a network interface
# 只是一个普通的 USB 转串口适配器
# ... 现在它就是一个网络接口了
The hardware on the microcontroller’s end is trivial: www.c: Source code. www.elf: Prebuilt binary. It does work with no external components, but I wanted some blinkenlights, and an idiot-proofing diode for when Inevitable connection of power backwards. Because it only draws a few milliwatts, it can run the server of the serial adapter’s 5 volt rail: it’s really nice to only have one cable to deal with. 微控制器端的硬件非常简单:www.c:源代码。www.elf:预编译二进制文件。它确实可以在没有任何外部组件的情况下工作,但我想要一些闪烁的灯,以及一个防呆二极管,以防我不可避免地把电源接反。因为它只消耗几毫瓦的功率,所以它可以直接由串口适配器的 5 伏电源轨供电:只需要处理一根线,感觉真好。
Now it has an internet connection, but that’s hardly a server. In order for my web page to get to your computer, it needs to pass through dozens of different networks. To do this, each packet has an IP header: 40 bytes that contain the address of the source and destination computers, and some other stuff I don’t really care about. The protocol used to be a lot more complex, with features like packet fragmentation that require a lot of memory to handle correctly, but I don’t have to: every modern operating system disables fragmentation and IPv6 removed it entirely. This makes implementing it very easy: Just swap around the source and destination of a recieved packet to generate the header for the response. (and reset the TTL counter) 现在它有了互联网连接,但这还算不上服务器。为了让我的网页到达你的电脑,它需要经过几十个不同的网络。为此,每个数据包都有一个 IP 头部:40 字节,包含源计算机和目标计算机的地址,以及一些我不太关心的其他信息。该协议过去复杂得多,具有诸如数据包分片之类的功能,需要大量内存才能正确处理,但我不需要这样做:每个现代操作系统都禁用了分片,而 IPv6 则完全移除了它。这使得实现变得非常容易:只需交换接收到的数据包的源地址和目标地址,即可生成响应的头部。(并重置 TTL 计数器)
The other protocol, TCP is a lot harder: Implementing it requires the microcontroller to track connection states, periodically retransmit lost packets and handle a huge number edge cases. It took several days to get my custom implementation working well enough, and it’s still got a few bugs. As for implementing HTTP, I didn’t: The server always sends a hardcoded “response” back to the client. This works fine as long as there’s only a single URL on the site. 另一个协议 TCP 要难得多:实现它需要微控制器跟踪连接状态、定期重传丢失的数据包并处理大量的边缘情况。我花了几天时间才让我的自定义实现运行得足够好,而且它仍然有一些 bug。至于实现 HTTP,我没有做:服务器总是向客户端发送硬编码的“响应”。只要网站上只有一个 URL,这就完全没问题。
[Video of the page loading. See web or files directory: loading.mp4] [页面加载视频。请参阅 web 或 files 目录:loading.mp4]
Ok great, but what if I want to share it with friends? Unfortunately, for their requests to reach it, it needs a publically routable IPv4 address. Not only are these expensive but it’s impossible to get a good internet connection at my place. (no, Starlink is not good) I do have a machine with a publically routable address, but it’s at a datacenter near Helsinki: I’d need a very long serial cable… another cool thing Linux supports is wireguard, which creates a virtual network link over the internet. This works even if one of the machines is behind (CG)NAT or other annoyances. Problem solved: have the Linux router box connect to the VPS to get a proper internet connection? 好吧,很棒,但如果我想和朋友分享呢?不幸的是,为了让他们的请求到达这里,它需要一个可公开路由的 IPv4 地址。这些地址不仅昂贵,而且在我住的地方根本无法获得良好的互联网连接。(不,Starlink 并不好)我确实有一台拥有可公开路由地址的机器,但它在赫尔辛基附近的数据中心:我需要一根非常长的串口线……Linux 支持的另一个很酷的功能是 WireGuard,它可以在互联网上创建虚拟网络链路。即使其中一台机器位于 (CG)NAT 或其他麻烦的网络环境之后,它也能工作。问题解决了:让 Linux 路由器连接到 VPS 以获得正常的互联网连接?
… except the MCU still doesn’t have it’s own IP address: I could forward everything from my VPS’s address to it, but that would break my normal website. Instead, I setup the server to proxy any requests under /mcu to the server using a local address block. This means that visitors aren’t directly connecting to the MCU’s TCP/IP stack… but hey, it’s the same setup that the Vape Server uses and no one complained. (It also makes it slightly harder to break by sending SYN packets, but it’s not exactly hard to DDoS a server connected over what’s effectively dial-up) ……除了 MCU 仍然没有自己的 IP 地址:我可以把 VPS 地址上的所有请求转发给它,但这会破坏我正常的网站。相反,我设置服务器将 /mcu 下的任何请求代理到使用本地地址块的服务器。这意味着访问者并没有直接连接到 MCU 的 TCP/IP 协议栈……但嘿,这和“电子烟服务器”(Vape Server)使用的设置是一样的,没人抱怨过。(这也使得通过发送 SYN 数据包来破坏它变得稍微困难了一些,但对于一个实际上通过拨号连接的服务器来说,进行 DDoS 攻击并不难)
This whole problem wouldn’t exist if we could just get our stuff together: IPv6 has existed for thirty years but most people still don’t have access. 如果我们能齐心协力,整个问题就不会存在:IPv6 已经存在了三十年,但大多数人仍然无法使用。
Related: 相关链接:
- /mcu: The page hosted from the microcontroller. (由微控制器托管的页面)
- http://ewaste.fka.wtf/: The Vape Server, a website hosted off a 32-bit MCU pulled from the trash. (电子烟服务器,一个由从垃圾堆里捡来的 32 位 MCU 托管的网站)
- https://lcamtuf.substack.com/p/psa-if-youre-a-fan-of-atmega-try: lcamtuf on the AVR Dx line. (lcamtuf 关于 AVR Dx 系列的介绍)