wolweb

command module
v0.0.0-...-4d68874 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2026 License: GPL-3.0 Imports: 24 Imported by: 0

README

made-with-Go proc-arch os

Web interface for sending Wake-on-LAN (Magic Packet)

Fork from https://github.com/sameerdhoot/wolweb. I wanted to have a json response with the status of device. WOL is a L2 broadcast. To test the L2 connectivity, a arping is send directly after the WOL package.

MACHINE1 MACHINE2 | +------------+ | |>>>>>>>>-+ TCP Data +->>>>>>>>| | +------------+ | | | | +------------+ | |<<<<<<<<-+ TCP ACK +-<<<<<<<<| | +------------+ | | | |->>>>--------------+ | | ARP ENTRY MACHINE2| | |-<<<<--------------+ | | |

This application is intended do be used in conjunction with a reverse proxy and secured with an SSL certificate. As the intended use case was with home networks, the application has no in-built authentication. While this could pose a slight security risk even if this was hacked to application is intended to be containerised so the attack surface if limited.

I have bookmarked direct link to device(s) on my browsers to wake them using single HTTP call for ease of access.

Use cases:

  • Wake-up my home computers remotely, for access remotely over RDP.
  • Integration with automated routines to allow parts of a home lab to sleep instead of running 24x7 to save energy.

Bootstrap UI with JS Grid for editing data

Screenshot

The UI features CRUD operation implemented using js-grid.com plugin.

Wake-up directly using HTTP Request

/wolweb/wake/<hostname> - Returns a JSON object

{
    "error": "",
    "message": "Device 'Server' with IP '10.1.60.60' is awake. Packet arp ping time '213.903µs'",
    "success": true
}

Configure the app

The application will use the following default values if they are not explicitly configured as explained in sections below.

Config Description Default
Host Define the host address on which the webserver will listen 0.0.0.0
Port Define the port on which the webserver will listen 8089
Virtual Directory A virtual directory to mount this application under /wolweb
Broadcast IP and Port This is broadcast IP address and port for the local network. Please include the port :9 10.10.10.255:9

You can override the default application configuration by using a config file or by setting environment variables. The application will first load values from config file and look for environment variables and overwrites values from the file with the values which were found in the environment.

Using config.json:

{
    "host": "0.0.0.0",
    "port": 8089,
    "vdir": "/",
    "bcastip": "10.10.10.255:9"
}

Using Environment Variables:

Environment variables takes precedence over values in config.json file.

Variable Name Description
WOLWEBHOST Override for default HTTP host
WOLWEBPORT Override for default HTTP port
WOLWEBVDIR Override for default virtual directory
WOLWEBBCASTIP Override for broadcast IP address and port

Devices (targets) - devices.json format

{
    "devices": [
        {
            "name": "Server",
            "mac": "34:E6:D7:33:12:71",
            "ip": "10.10.10.255:9"
        },
        {
            "name": "NAS",
            "mac": "28:C6:8E:36:DC:38",
            "ip": "10.10.10.255:9"
        },
        {
            "name": "Laptop",
            "mac": "18:1D:EA:70:A0:21",
            "ip": "10.10.10.255:9"
        }
    ]
}

Usage with Docker

This project includes Dockerfile (based on Alpine) and docker-compose.yml.

I could not get this to run using Docker's bridged network. The only way I was able to make it work was to use host network for the docker container. See this https://github.com/docker/for-linux/issues/637 for details.

With docker-compose
docker-compose up -d
Build and run manually
docker build -t wolweb .
docker run --network host -it wolweb
Extract the compiled application from an image
docker cp wolweb:/wolweb - > wolweb.gz

Build

You need Go 1.20 to build binary for any OS.

# Linux/macOS
go build -o wolweb .
User permission sending arp package
setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
getpcaps 9562
sudo setcap cap_net_raw,cap_net_admin=eip wolweb
sudo getcap wolweb
cat /proc/net/arp
Cache Timeout
cat /proc/sys/net/ipv4/neigh/eth1/base_reachable_time_ms
30000
gratuitous ARP's and WOL using tcpdump
tcpdump -vXAnn -i enp3s0 port 9
tcpdump -i eth0 arp and arp[6:2]==2

To see detailed instructions on how to run this application as service on ASUS router with custom firmware asuswrt-merlin see this Wiki guide

NGiNX Config

I am already using NGiNX as web-proxy

worker_processes  1;
error_log /dev/stdout warn;

events {
    worker_connections  1024;
}

http {
    server_tokens off;
    include       mime.types;
    default_type  application/octet-stream;
    #access_log    /dev/stdout;

    sendfile           on;
    keepalive_timeout  65;

    upstream backend {
        server wol:8089;
    }

    server {
        server_name wol.eftasgmbh.local;
        listen 8090 ssl;
        ssl_certificate /etc/nginx/wol.eftasgmbh.local.pem;
        ssl_certificate_key /etc/nginx/wol.eftasgmbh.local.pem;
        ssl_verify_client off;
        ssl_protocols TLSv1.2 TLSv1.3;
        # Some security headers...
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options nosniff;
        # Disable strict transport security for now. You can uncomment the following
        # line if you understand the implications.
        #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";

        location / {
            limit_except GET HEAD POST { deny all; }
            add_header X-Frame-Options SAMEORIGIN;
            add_header X-XSS-Protection "1; mode=block";
            proxy_pass  http://backend/;
            proxy_set_header Host $http_host;
            proxy_set_header X_FORWARDED_PROTO https;
        }
    }
}

docker compose

services:
  wolweb:
    container_name: wolweb_app
    #image: "ghcr.io/sameerdhoot/wolweb"
    image: registry.dev.eftas.com/eftas/wolweb:latest

    # Make sure that the file exists in local directory from where you are running the compose file;
    # or initialize empty json file by running command "echo '{}' > devices.json".
    volumes:
      - ./devices.json:/app/devices.json
      #- "/srv/docker/git/wolweb/wolweb:/app/wolweb"

    # Have to use host mode as bridge network has issues with UDP broadcast
    # https://github.com/docker/for-linux/issues/637
    ports:
      - 8089:8089
    network_mode: host
    #expose:
    #  - 8089
    #labels:
    #  traefik.enable: true
    #  traefik.http.routers.wol-websecure.middlewares: wol-chain
    #  traefik.http.middlewares.wol-chain.chain.middlewares: secHeaders@file
    #
    #  traefik.http.routers.wol-websecure.rule: Host(`wol.eftas.services`) # && PathPrefix(`/wolweb/`)
    #  traefik.http.routers.wol-websecure.entrypoints: websecure
    #  traefik.http.routers.wol-websecure.tls: true
    #  traefik.http.routers.wol-websecure.tls.certresolver: httpResolver
    #  traefik.http.routers.wol-websecure.service: wol-app
    #
    #  traefik.http.routers.wol-internal.rule: Host(`wol.eftasgmbh.local`)
    #  traefik.http.routers.wol-internal.entrypoints: websecure
    #  traefik.http.routers.wol-internal.tls: true
    #  traefik.http.routers.wol-internal.service: wol-app
    #
    #  traefik.http.services.wol-app.loadbalancer.server.port: 8089
    #  traefik.docker.network: frontend
    #cap_add:
    #  - NET_ADMIN
    #  - SYS_MODULE
    # sysctls:
      # - net.ipv4.icmp_echo_ignore_broadcasts=0
      # - net.ipv4.icmp_echo_ignore_broadcasts
      # - net.ipv6.conf.all.disable_ipv6=0
      # - net.ipv4.ip_forward=1
      # - net.ipv6.conf.all.forwarding=1
    #networks:
    #  frontend:
    #    ipv4_address: 172.19.0.101
    #    ipv6_address: fcff:3990:3990::99
    #  backend:
    # Use environment variable below to change port or virtual directory.
    environment:
      WOLWEBHOST: "0.0.0.0"
      WOLWEBPORT: "8089"
      WOLWEBVDIR: "/" #"/wolweb"
      WOLWEBBCASTIP: "10.10.10.255:9"
    restart: unless-stopped

  nginx:
    image: nginx:latest
    hostname: nginx
    container_name: "webwol_frontend"
    ports:
      - "8090:8090"
    networks:
     frontend:
       ipv4_address: 172.19.0.101
      #  ipv6_address: fcff:3990:3990::99
    # expose:
      # - 8090
    # labels:
      # traefik.enable: true
      # traefik.http.routers.wol-websecure.middlewares: wol-chain
      # traefik.http.middlewares.wol-chain.chain.middlewares: secHeaders@file
      #
      # traefik.http.routers.wol.rule: Host(`wol.eftasgmbh.local`) && Path(`/wol`)
      # traefik.http.routers.wol.entrypoints: websecure
      # traefik.http.routers.wol.tls: true
      # traefik.http.routers.wol.service: wol-app
      #
      # traefik.http.services.wol-app.loadbalancer.server.port: 8090
      # traefik.docker.network: frontend
    volumes:
      - ./conf/:/etc/nginx/
      - /var/www/html:/usr/share/nginx/html
    restart: unless-stopped


networks:
  frontend:
    external: true
    driver: bridge
    # enable_ipv6: true
    ipam:
      config:
        - subnet: 172.19.0.0/24
        # - subnet: fcff:3990:3990::/64
        #   gateway: fcff:3990:3990::1
  backend:
    name: backend
    external: true
    driver: bridge

Firewall

To deny access to unsecure http web interface, a firewall rule has to be added.

ufw example

ufw allow from 172.19.0.101 to any port 8089 proto tcp

I still have to build and test it op FreeBSD, it should work.

Credits

This project is based on a couple of framworks and provided below:

License

Distributed with GNU General Public License (c) 2023

Documentation

Overview

package ping

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL