Skip to main content

Windows

Windows may seem like an "easy button". For Eth Docker, it is anything but, and even running native Windows clients presents multiple challenges. They can all be overcome.

If you wish to run Eth Docker on Windows regardless, this is what's required.

  • Windows 11 Pro 24H2 or later, ideally with 64 GiB RAM so that WSL defaults to 30 GiB
  • WSL 2, the "Windows Subsystem for Linux", which runs a Linux kernel in a lightweight VM
  • WSL networking that is reachable from the LAN
  • Functioning time sync

I previously suggested Docker Desktop, and no longer do

These are the configuration steps:

Windows

  • Verify you are running Windows 11 Pro 24H2 or later and have sufficient RAM
  • To keep the system secure, configure Windows Update to download and apply patches automatically, and to update WSL. Settings -> Windows Update -> Advanced, enable "Receive updates for other Microsoft products" and "Get me up to date".

WSL Settings

  • Configure WSL for mirrored networking. Edit .wslconfig in your Windows home directory and add
[wsl2]
networkingMode=mirrored
  • Mirrored networking shares the MAC address, IPv4 address and IPv6 address of the Windows host machine. On your router, set a DHCP reservation for this machine so WSL always has the same local IP; or configure Windows with a static IP. This makes port forwarding of the P2P ports possible, and makes remote access easier. Sharing the addresses is not by itself enough to be reachable: see "Inbound P2P connections" below.
  • Check memory assigned to WSL with free -h. If it's too low for your chosen client mix, edit .wslconfig in your Windows home directory and add a memory section and disable swap, for example
[wsl2]
memory=32GB
swap=0
  • Set the default disk size to 2TB. Alternatively you could increase size after installation. In .wslconfig again
[wsl2]
defaultVhdSize=2199023255552

Inbound P2P connections

Your node needs inbound connections to attract peers. Outbound works out of the box; inbound does not.

  • Inbound IPv6 does not work for Docker containers on WSL 2. As of September 2026, tested with WSL 2.9.12 on Windows build 26200, inbound IPv6 connections to a published container port never arrive. A listener running directly in WSL, outside Docker, is reachable over IPv6, and inbound IPv4 to the very same published port works at the same moment, so the restriction is specific to Docker's published ports under WSL's mirrored networking. Docker publishes a port by rewriting the destination address to the container's, and it is that path which fails. This is not a firewall issue: it persists with the Hyper-V firewall set to allow all inbound and with matching Windows Defender Firewall rules in place. Since Eth Docker runs its clients in containers, leave IPV6=false in your .env. If you want an IPv6-reachable node, run it on native Linux.
  • Inbound IPv4 needs Hyper-V firewall rules. The Hyper-V firewall is a separate layer from Windows Defender Firewall, it governs traffic into the WSL VM, and it blocks inbound by default. This is the layer that matters; you do not normally need Windows Defender Firewall rules as well.

Adjust the ports below to match CL_P2P_PORT, CL_QUIC_PORT and EL_P2P_PORT in your .env, then run this from an Administrator PowerShell. The VMCreatorId shown is WSL's and is the same on every machine.

$wsl = '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}'
New-NetFirewallHyperVRule -Name 'ethd-el-tcp' -DisplayName 'Eth Docker EL P2P TCP' -Direction Inbound -VMCreatorId $wsl -Protocol TCP -LocalPorts 30303 -Action Allow
New-NetFirewallHyperVRule -Name 'ethd-el-udp' -DisplayName 'Eth Docker EL P2P UDP' -Direction Inbound -VMCreatorId $wsl -Protocol UDP -LocalPorts 30303 -Action Allow
New-NetFirewallHyperVRule -Name 'ethd-cl-tcp' -DisplayName 'Eth Docker CL P2P TCP' -Direction Inbound -VMCreatorId $wsl -Protocol TCP -LocalPorts 9000 -Action Allow
New-NetFirewallHyperVRule -Name 'ethd-cl-udp' -DisplayName 'Eth Docker CL discv5 UDP' -Direction Inbound -VMCreatorId $wsl -Protocol UDP -LocalPorts 9000 -Action Allow
New-NetFirewallHyperVRule -Name 'ethd-cl-quic' -DisplayName 'Eth Docker CL QUIC UDP' -Direction Inbound -VMCreatorId $wsl -Protocol UDP -LocalPorts 9001 -Action Allow
  • Verify the rules exist with Get-NetFirewallHyperVRule -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' | Format-Table DisplayName,Protocol,LocalPorts,Action
  • Forward the same TCP and UDP ports on your router to this machine, to the reserved IP you set earlier.
  • Test from outside your LAN, not from another machine on it. A service such as ifconfig.co will do: curl -4 https://ifconfig.co/port/30303 reports whether that TCP port is reachable. Give your clients a few minutes first, and expect the inbound peer count to climb over the following hour.

Microsoft is building wslc, WSL's own container CLI, and its exposed ports already support IPv6 as of WSL 2.9.8. If it gains Compose support (WSL#40948), running Eth Docker on it may avoid this IPv6 restriction. That issue is an open feature request with no commitment, so this is a direction to watch, not something usable today.

WSL

  • From Windows Store, install WSL and Ubuntu current LTS. Debian is also an option, it is however quite bare-bones without even man-db out of the box.
  • This defaults to WSL 2, but if you have an older WSL 1 install, find it with wsl --list -v and change it with wsl --set-version DISTRO-NAME 2 as well as wsl --set-default-version 2.
  • If this was installed before setting a defaultVhdSize, increase the disk space available to WSL from 1TB to 2TB.
  • Create a scheduled task in Task Scheduler to keep Ubuntu/Debian in WSL updated.
    • Call it WSLUpdate
    • Run every day at a time you like
    • Run only if any network is connected
    • Run as soon as possible if a start was missed
    • Stop task if it runs longer than 1 hour
    • Create two "Start Program" actions
      • The first is wsl.exe -u root -e apt-get update
      • The second is wsl.exe -u root DEBIAN_FRONTEND=noninteractive apt-get -y --autoremove dist-upgrade
  • Enable systemd inside the WSL installation. nano /etc/wsl.conf and set it to
[boot]
systemd=true
command=mount --make-rshared /

Close your WSL windows and in Powershell, run wsl --shutdown. When it launches again, systemd should be running.

  • If on Ubuntu 24.04 or earlier, install chrony with sudo apt install -y chrony. From 26.04, chrony is the default.

Time sync

  • Fix Windows time sync if your machine is not domain-joined

    • Change w32time to start automatically. In Administrator cmd, but not PowerShell, sc triggerinfo w32time start/networkon stop/networkoff. Verify with sc qtriggerinfo w32time. To get into cmd that way, you can start Admin PowerShell and then just type cmd.
    • In Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Config, set MaxPollInterval to hex c, decimal 12.
    • Check Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Parameters\NtpServer. If it ends in 0x9 you are done. If it ends in 0x1 you need to adjust SpecialPollInterval in Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\TimeProviders\NtpClient to read 3600
    • Reboot, then from Powershell run w32tm /query /status /verbose to verify that w32time service did start. If it didn't, check triggers again. If all else fails, set it to Automatic Delayed startup
  • If despite chrony, you still see clock skew in WSL, set a scheduled task to keep WSL in sync with your Windows clock. From non-admin Powershell, run schtasks /Create /TN WSLTimeSync /TR "wsl -u root hwclock -s" /SC ONEVENT /EC System /MO "*[System[Provider[@Name='Microsoft-Windows-Kernel-Power'] and (EventID=107 or EventID=507) or Provider[@Name='Microsoft-Windows-Kernel-General'] and (EventID=1)]]" /F.

Docker

  • Use the QuickStart instructions to install Eth Docker and get Docker-CE installed in Ubuntu. Log out and back in so your user can run Docker commands.

Start on boot

  • Your node needs to run after Windows reboot for 24/7 uptime. WSL only starts well with a logged-in user. To solve this, use Windows ARSO.
    • Start group policy editor, find "Computer Configuration > Administrative Templates > Windows Components > Windows sign in Options" and enable "Sign-in and lock last interactive user automatically after a restart"
    • If you are not using Bitlocker, you may also need "Configure the mode of automatically signing in and locking last interactive user after a restart or cold boot". I was unable to configure this from the GUI and ended up using RegEdit. Navigate to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System and create a new DWORD called AutomaticRestartSignOnConfig. Set it to 0 if you use BitLocker, and to 1 if you are not.

QoL

  • Optional: Improve your WSL experience with Windows Terminal and oh-my-zsh
  • Optional: Use sparse VHD for WSL, wsl.exe --list and then wsl.exe --manage DISTRO-NAME --set-sparse true. The performance impact is severe, only do this on a testnet.
  • Optional: Configure your Windows drive to be encrypted with Bitlocker. Be very careful to print out the recovery key and keep it safe. Always suspend Bitlocker before doing a UEFI/BIOS upgrade.