The 2026 Hardware Decision: Wi-Fi vs. Hardwired Ethernet
When builders search for a 'web server with Arduino', they usually fall into two camps: those who want wireless convenience, and those who need rock-solid reliability for home automation or industrial logging. Wi-Fi modules drop connections, require RF tuning, and struggle through concrete walls. Hardwired Ethernet never sleeps.
| Requirement | Board Pick | Verdict |
|---|---|---|
| Mobile / Battery powered | ESP32-WROOM-32 DevKit | Use when wiring is impossible. |
| Low-cost Wi-Fi node | Arduino Nano 33 IoT | Good for small sensor payloads. |
| Always-on, high reliability | Arduino Uno R4 Minima + W5500 | DEFAULT PICK. Best for permanent dashboards. |
The classic Uno R3 has only 2KB of SRAM. A single HTTP request and response buffer can easily consume 1KB, leaving almost no room for your actual application logic. The Arduino Uno R4 Minima features a Renesas RA4M1 processor with 32KB of SRAM and 256KB Flash. This 16x memory increase eliminates the buffer-overflow crashes that plague R3 web servers, all while maintaining 5V logic tolerance for legacy shields.
Parts List and Spec Sheet
This build targets the Arduino Uno R4 Minima paired with a WIZnet W5500-based shield. Do not buy the older W5100 shields; they run hotter, consume more power, and lack the hardware TCP/IP offload efficiency of the W5500.
- Microcontroller: Arduino Uno R4 Minima (ABX00080) - ~$20.00
- Network Shield: WIZnet W5500 Ethernet Shield (or HanRun HR911105A variant) - ~$14.00
- Power Supply: 5V 2A USB-C Power Adapter (Do not rely on PC USB ports; the W5500 PHY draws up to 130mA during TX bursts)
- Networking: CAT6 Ethernet Patch Cable
- Indicator: 5mm LED with 220Ω current-limiting resistor
Pin Mapping and Physical Wiring
The W5500 communicates via SPI. While the Uno R4 routes SPI to the 6-pin ICSP header, the standard Ethernet shield form factor bridges these signals to the digital pins for backward compatibility. You must explicitly manage the Chip Select (CS) pins to prevent bus collisions.
| W5500 Shield Pin | Uno R4 Minima Pin | Function / Notes |
|---|---|---|
| SS / CS | D10 | Ethernet Chip Select. Must be OUTPUT. |
| MOSI | D11 (or ICSP 4) | Master Out Slave In |
| MISO | D12 (or ICSP 1) | Master In Slave Out |
| SCK | D13 (or ICSP 3) | SPI Clock |
| SD CS | D4 | SD Card Chip Select. Must be set HIGH to disable. |
| RESET | D9 | Hardware reset (optional, tied to RST on most shields) |
| LED Control | D8 | Our application output pin |
Numbered Wiring Steps
- Disable the SD Card: If your W5500 shield has a microSD slot, bend the D4 pin slightly so it doesn't insert into the Uno, OR handle it in software (included in the code below). An unmanaged SD card will hijack the SPI bus.
- Stack the Shield: Press the W5500 shield firmly into the Uno R4 headers. Ensure no ICSP pins are bent backward.
- Wire the LED: Connect the anode (long leg) of the LED to D8 via a 220Ω resistor. Connect the cathode to GND.
- Connect Network & Power: Plug the CAT6 cable into your router/switch. Power the Uno R4 via the USB-C port using the 5V 2A wall adapter.
Complete Arduino Web Server Code (C++)
This code targets the Arduino Uno R4 Minima. It uses the official Arduino Ethernet library (ensure you have v2.0.0 or newer installed via Library Manager for native W5500 support). It includes robust hardware and link-state error handling.
#include <SPI.h>
#include <Ethernet.h>
// --- PIN DEFINITIONS ---
#define W5500_CS_PIN 10
#define SD_CS_PIN 4
#define LED_PIN 8
// --- NETWORK CONFIG ---
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress fallbackIP(192, 168, 1, 177); // Used if DHCP fails
EthernetServer server(80);
bool ledState = false;
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); } // Wait for serial monitor
// Initialize Pins
pinMode(W5500_CS_PIN, OUTPUT);
pinMode(SD_CS_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
// Disable SD Card to free up SPI bus
digitalWrite(SD_CS_PIN, HIGH);
digitalWrite(W5500_CS_PIN, HIGH);
Serial.println("Initializing Ethernet...");
// Attempt DHCP
if (Ethernet.begin(mac) == 0) {
Serial.println("[WARN] DHCP Failed. Falling back to Static IP.");
Ethernet.begin(mac, fallbackIP);
}
// Hardware Error Handling
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("[FATAL] Ethernet shield not found. Check SPI wiring and CS pin.");
while (true) { delay(1); } // Halt execution
}
// Link Error Handling
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("[ERROR] Ethernet cable unplugged. Please connect CAT6.");
}
server.begin();
Serial.print("[OK] Web Server online at http://");
Serial.println(Ethernet.localIP());
}
void loop() {
EthernetClient client = server.available();
if (client) {
Serial.println("-- New Client Connected --");
String currentLine = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
if (c == '\n') {
// If the line is blank, we've reached the end of the HTTP request
if (currentLine.length() == 0) {
// Send HTTP Headers
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// Send HTML Body
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<style>body{font-family:sans-serif;text-align:center;margin-top:50px;}");
client.println(".btn{padding:15px 30px;font-size:20px;background:#007BFF;color:#fff;border:none;border-radius:5px;}</style></head>");
client.println("<body><h1>Arduino R4 Web Server</h1>");
client.print("<p>LED State: <strong>");
client.print(ledState ? "ON" : "OFF");
client.println("</strong></p>");
client.println("<a href=\"/toggle\"><button class=\"btn\">Toggle LED</button></a>");
client.println("</body></html>");
break;
} else {
// Parse HTTP GET request for toggle action
if (currentLine.startsWith("GET /toggle")) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
Serial.println(">> LED Toggled");
}
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
client.stop();
Serial.println("-- Client Disconnected --\n");
}
}
Debugging: Exact Errors and Ranked Causes
Embedded networking fails in predictable ways. When your web server with Arduino refuses to load, do not start rewriting code. Follow this diagnostic path.
The First Three Things to Check
- The RJ45 Link Light: Look at the physical Ethernet jack on the shield. The green LED must be solid (link established) and the yellow LED should flicker (traffic). If both are dark, you have a physical layer failure (bad cable, dead switch port, or unpowered shield).
- Serial Monitor DHCP Timeout: Open the Serial Monitor at 115200 baud. If it hangs for 60 seconds and prints
[WARN] DHCP Failed, your router is blocking unknown MAC addresses or the SPI bus is failing to read the W5500 registers. - Subnet Mismatch: If the Serial Monitor prints an IP like
192.168.1.177but your PC is on10.0.0.x, you cannot route to it. Change thefallbackIPin the code to match your router's subnet.
Common Error Strings and Fixes
fatal error: Ethernet.h: No such file or directoryCause: The IDE is missing the core networking library.
Fix: Go to Sketch > Include Library > Manage Libraries. Search for 'Ethernet' by Arduino. Install version 2.0.0 or higher. Do not use the deprecated 'Ethernet2' library unless you are on a very old IDE version.
ERR_CONNECTION_REFUSED or ERR_CONNECTION_TIMED_OUTRanked Causes:
1. CS Pin Collision: You forgot to set the SD card CS pin (D4) HIGH. The SD card is pulling the MISO line low, corrupting W5500 SPI data. (Fixed in the provided code).
2. IP Subnet Mismatch: Your PC and the Arduino are on different VLANs or subnets.
3. Browser Caching: The browser cached a failed DNS or ARP resolution. Open an Incognito/Private window to test.
Extending and Simplifying the Build
Once the base server is verified, you will likely want to adapt it for a specific application. Here is how to scale the project up or down.
How to Simplify (Save Memory and Boot Time)
If you are deploying this in a closed network without a DHCP server (like a direct PC-to-Arduino link), strip out the DHCP negotiation. Replace the Ethernet.begin(mac) logic with a single static assignment: Ethernet.begin(mac, ip, dns, gateway, subnet);. This saves roughly 1.5KB of SRAM and cuts the boot-to-ready time from 5 seconds to under 500 milliseconds.
How to Extend (Add Mains Voltage Control)
To turn this web server into a home automation relay controller, swap the 5mm LED for a Songle SRD-05VDC-SL-C 5V Relay Module.
Wiring: Connect the relay VCC to the Uno's 5V pin, GND to GND, and the IN pin to D8.
⚠️ MAINS VOLTAGE WARNING: If you switch the relay contacts to control a 120V/240V AC lamp, you are working with lethal voltage. Never work on mains wiring while the circuit is energized. De-energize the breaker, verify dead with a CAT-III multimeter, and ensure all AC connections are enclosed in a grounded, fire-rated junction box. If you are not comfortable with mains wiring, stick to controlling 12V DC LED strips via a logic-level MOSFET (like the IRLZ44N) instead of a mechanical relay.
By choosing the hardwired W5500 route and leveraging the Uno R4's expanded memory, you eliminate the 'flaky Wi-Fi' tax that plagues most IoT projects. The server will boot, grab an IP, and serve your dashboard for years without a single RF dropout.






