Networking AWS

UpSnap 5.7.3 on AWS User Guide

| Product: UpSnap 5.7.3 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the UpSnap 5.7.3 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg network monitoring listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

UpSnap is a web dashboard for powering machines on and off. You add your devices (name, IP address, MAC address); UpSnap shows on one page whether each one is up, by ping and by checking the TCP ports you choose, and updates the page live. From the dashboard, or on a cron schedule, it can wake a device (with a Wake-on-LAN magic packet or your own wake command), shut it down with your own shell command (for example over SSH), or put it to sleep with Sleep-On-LAN. A network scan with nmap finds the devices on a subnet so you can add them in one go. Users, per-device permissions and device groups are built in, and the data lives in PocketBase (an embedded SQLite database with its own admin UI).

Wake-on-LAN and AWS. A Wake-on-LAN magic packet is a Layer 2 broadcast, and an AWS VPC does not forward broadcasts: a magic packet sent from this instance reaches no other host in the VPC, and EC2 instances are not started that way anyway. On AWS, UpSnap's ping and port status, network scans and scheduled commands work as they do anywhere. To wake machines on your own office or home network, connect the instance to that network (a site-to-site VPN plus a small always-on relay on the LAN, or a Layer 2 bridge); Step 7 explains both.

The cloudimg image makes UpSnap safe to run on EC2:

  • Your own administrator, no default account. Each instance creates its own UpSnap administrator with a random password on its first boot. The image contains no database, no account and no password. Self-registration is closed: only the administrator adds users.
  • HTTPS from the first boot. nginx serves UpSnap and the PocketBase admin UI (/_/) on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS. Requests for a host name the instance does not serve get no answer.
  • UpSnap listens on localhost only. It is fixed to 127.0.0.1:8090 by its service unit, so nginx is its only client.
  • Other web sites cannot act with your login. nginx refuses a wake, sleep, reboot, shutdown or network scan request that another web site's page sends in your browser, refuses any change through the API whose browser Origin is not this instance, and rate limits sign-in attempts per address. PocketBase logs each request with the real client address.
  • The scanner is not root. UpSnap and the nmap scans and commands it starts run as the unprivileged upsnap user with exactly one Linux capability, CAP_NET_RAW (raw sockets for ping and the ARP scan), in a systemd sandbox, and cannot gain more. nmap itself carries no setuid bit and no file capabilities.
  • No access to the instance metadata service. nginx and UpSnap, and every scan and command UpSnap starts, are blocked at the kernel level from the EC2 instance metadata service (IPv4 and IPv6). On top of that, the nmap that UpSnap runs always skips the metadata address, so a scan never probes it.
  • The official release, checked. UpSnap 5.7.3 is installed from its official release archive (checksum pinned; built with Go 1.27.3 and PocketBase 0.41.1), with no known reachable vulnerabilities at build time. There is no compiler on the image.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: UpSnap 5.7.3 (/usr/local/bin/upsnap, data in /var/lib/upsnap/pb_data), nmap 7.94, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair, and a VPC subnet that can reach the machines you want to manage.
  • A security group that allows TCP 22 (SSH), TCP 443 (UpSnap) and TCP 80 (redirects to HTTPS) from the networks your administrators work from. UpSnap needs no other inbound port.
  • For ping status of other EC2 instances, their security groups must allow inbound ICMP echo from this instance; otherwise watch a TCP port instead (Step 5).

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick UpSnap 5.7.3 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (UpSnap itself needs very little, so a smaller instance also works), your key pair, the subnet and a security group as above.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=upsnap}]'

Step 2: Connect to your instance

Version SSH user
UpSnap 5.7.3 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot sets the host name, generates the certificate, creates this instance's UpSnap database and administrator, and then starts UpSnap and nginx:

systemctl is-active upsnap-firstboot upsnap nginx
sudo test -f /var/lib/cloudimg/upsnap-firstboot.done && echo FIRSTBOOT_DONE

All three units are active and the first boot marker is present:

active
active
active
FIRSTBOOT_DONE

Only SSH and nginx listen on the network. UpSnap listens on localhost only:

sudo ss -lntpH | awk '{print $4, $6}' | sed -E 's/users:\(\("([^"]+)".*/\1/' | grep -v '127.0.0.5' | sort -u
0.0.0.0:22 sshd
0.0.0.0:443 nginx
0.0.0.0:80 nginx
127.0.0.1:8090 upsnap
[::]:22 sshd
[::]:443 nginx
[::]:80 nginx

Step 4: Get your URL and password

sudo cat /var/lib/cloudimg/upsnap-credentials.txt

The file is readable by root only and holds the URL and the administrator's e-mail and password for this instance:

# UpSnap 5.7.3 - generated on first boot by upsnap-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.

UPSNAP_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
UPSNAP_ADMIN_EMAIL=admin@upsnap.local
UPSNAP_ADMIN_PASSWORD=<UPSNAP_ADMIN_PASSWORD>
UPSNAP_ADMIN_UI=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/_/
#
# Open UPSNAP_URL in a browser (self-signed certificate minted on this instance's first boot; port 80 redirects to https)
# and sign in with UPSNAP_ADMIN_EMAIL / UPSNAP_ADMIN_PASSWORD. The same account opens the PocketBase admin UI
# (UPSNAP_ADMIN_UI). Change the password from the account page after the first sign-in.
# Nothing is preloaded: no device, scan range, command or schedule. Wake-on-LAN broadcasts do not cross an AWS VPC:
# see the user guide for what works here (status, scheduled commands, a VPN or bridge to your own LAN).
# Self-test:  sudo upsnap-selftest      Change the served name:  sudo upsnap-set-hostname <your-domain>
# User guide: https://www.cloudimg.co.uk/guides/upsnap-5-7-3-on-ubuntu-24-04-aws/

The URL uses the instance's public DNS name from EC2 instance metadata. Opening https://<public-ip>/ sends you on to that name.

The image includes a self test. Through nginx it signs in as the administrator, checks the pages, the closed registration, the request guards, UpSnap's privileges and the metadata block:

sudo upsnap-selftest
SELFTEST-OK https 301 + healthz + UI + admin UI /_/ + anonymous: 0 devices, scan/wake/settings/superusers/logs refused, registration refused + administrator sign-in 200 / wrong password 400 + exactly 1 superuser (installer gone) + users.createRule null + trusted proxy X-Real-IP, rate limits on, appURL https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com + upsnap uid upsnap, CapEff/Bnd/Amb = CAP_NET_RAW only, NoNewPrivs, listening 127.0.0.1:8090 only + 403 cross-site scan + 403 cross-origin POST + 444 unknown host + metadata 000 inside upsnap and nginx (control 200) + nmap wrapper excludes metadata

Step 5: Sign in and add your devices

Open the UPSNAP_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own certificate, Step 10). Sign in with UPSNAP_ADMIN_EMAIL and UPSNAP_ADMIN_PASSWORD:

The UpSnap sign-in page on cloudimg with the Email or Username and Password fields and the Login button

Then change the password: open the account menu (top right), choose Edit account and set a new one. The credentials file keeps the first-boot password; put the new one in it (as root) if you want upsnap-selftest to keep signing in.

The dashboard starts empty. Choose New to add a device: a name, its IP address or DNS name, its MAC address and its netmask, and under Ports the TCP ports UpSnap should check. The dashboard then shows each device's card: the power button is green while the device answers ping and grey while it does not, and each port has a green (open) or red (closed) dot. Here UpSnap watches itself and the subnet's router, which answers ping but has no DNS service on that address:

The UpSnap dashboard with two device cards: the UpSnap instance itself with its IP and MAC address and green SSH (22) and HTTPS (443) port dots, and the VPC router with a green power button and a red DNS (53) dot

Click the pencil on a card to edit the device. Its page has the general settings, the ports to check, a link for the device name (for example the device's own web page), a custom ping command, the wake and shutdown settings (Step 7), Sleep-On-LAN, the magic-packet password and groups:

A device's page in UpSnap with its name, IP address, MAC address, netmask and description, the Track IP address switch and two ports, SSH 22 and HTTPS 443

UpSnap pings with raw ICMP packets (the reason it has CAP_NET_RAW). An EC2 instance answers only if its security group allows inbound ICMP echo from this instance; for devices that do not answer ping, a port check (for example SSH on 22) shows the same thing.

Step 6: Find devices with a network scan

Choose New, then Network Scan. Enter the range to scan (for example your subnet, 172.31.80.0/24), choose Save, then Scan. UpSnap runs an nmap ping scan of the range and lists every device that answers with its name, IP address, MAC address and vendor; Add adds one, Add all devices adds them all:

UpSnap's Network Scan with the IP range 172.31.80.0/24 saved and three devices found, ip-172-31-80-1.ec2.internal expanded to show its IP, MAC address, vendor and netmask with an Add button, and the Add all devices (3) button

The scan range is stored in UpSnap's settings and only administrators can change it. In a VPC, the scan sees the network interfaces of the instance's own subnet (with their MAC addresses) and, through the router, hosts in other subnets that answer ping or TCP. Only scan networks you own or are authorised to scan. Whatever range you enter, the nmap that UpSnap runs skips the instance metadata address:

cat /usr/local/lib/upsnap/bin/nmap
#!/bin/sh
# cloudimg: UpSnap runs nmap (device scan, IP tracking) by looking it up on PATH; this wrapper is first on the PATH of
# upsnap.service. It never lets a scan probe the instance metadata service (AWS 169.254.169.254, Azure wire server
# 168.63.129.16): nmap skips excluded targets entirely. The unit's IPAddressDeny additionally drops any IP packet to them.
exec /usr/bin/nmap --exclude 169.254.169.254,168.63.129.16 "$@"

Step 7: Waking and shutting down machines

Each device has a Wake and a Shutdown section. Both can run on a cron schedule (Enable wake cron, Enable shutdown cron), and Require Confirmation asks before a button press acts:

The Wake and Shutdown sections of a device in UpSnap: a wake timeout and a custom wake command field, the wake cron and confirmation switches, then the shutdown timeout and shutdown command field with UpSnap's example commands

What works in a VPC. Without a custom wake command, UpSnap wakes a device by sending a Wake-on-LAN magic packet to the broadcast address of the device's network. An AWS VPC does not deliver broadcasts, so that packet reaches no machine from an EC2 instance. Everything else does work: status by ping and ports, scans, and shutdown or wake commands. A command is a shell command (/bin/sh -c) that UpSnap runs on this instance as the upsnap user, in its sandbox and without metadata access; {{ DEVICE_IP }} and {{ DEVICE_MAC }} are replaced with the device's addresses. The image has ssh and curl for this (not sshpass or Samba's net, which UpSnap's examples mention).

Waking machines on your own network. Connect the VPC to that network first (an AWS Site-to-Site VPN, or a VPN you run yourself), then use one of these:

  • A relay on the LAN (the usual choice). Keep a small always-on machine on the LAN (for example a Raspberry Pi) that has a Wake-on-LAN tool such as wakeonlan or etherwake, and give UpSnap a custom wake command that asks it to send the magic packet on the LAN, for example ssh -i /var/lib/upsnap/.ssh/id_ed25519 wol@<relay-ip> wakeonlan {{ DEVICE_MAC }}. Status then comes from ping or a port across the VPN as usual.
  • A Layer 2 bridge. If the instance has a network interface on the LAN itself (a VPN in bridged, Layer 2 mode, such as OpenVPN with a tap device bridged into the LAN), UpSnap's own magic packet reaches that LAN. Set the device's netmask to the LAN's.

For SSH commands (a relay, or a shutdown such as ssh -i /var/lib/upsnap/.ssh/id_ed25519 admin@{{ DEVICE_IP }} sudo poweroff), create a key for the upsnap user and add its public key to the target account:

sudo install -d -m 700 -o upsnap -g upsnap /var/lib/upsnap/.ssh
sudo -u upsnap ssh-keygen -t ed25519 -N '' -f /var/lib/upsnap/.ssh/id_ed25519
sudo cat /var/lib/upsnap/.ssh/id_ed25519.pub

Accept each target's host key once (sudo -u upsnap ssh -i /var/lib/upsnap/.ssh/id_ed25519 <user>@<host> true), so commands do not stop at the prompt.

Step 8: Settings, users and the PocketBase admin

Settings sets how often UpSnap pings the devices (a cron expression, every 3 seconds by default), the IP address tracking interval (UpSnap rescans the subnets of devices with Track IP address switched on and follows a device whose IP address changes), Lazy ping (ping only while someone has the dashboard open), the site title and the icon:

The UpSnap Settings page with the ping interval cron field set to every 3 seconds and its syntax help, the IP address tracking interval and the Lazy ping switch

Users adds people and sets, for each user, which devices they can see, power on and off, edit and delete, and whether they can create devices. A user who may edit a device can also set its wake, shutdown and ping commands, which run on this instance, so give edit rights only to people you trust as much as an administrator.

The administrator from Step 4 is a PocketBase superuser, so the same e-mail and password also open the PocketBase admin UI at UPSNAP_ADMIN_UI (/_/), with the raw collections, the request logs and PocketBase's own backups. The admin UI is served only through nginx's HTTPS front.

The API. UpSnap's actions are on /api/upsnap/ (wake, sleep, reboot, shutdown, scan and the group variants) and its data on PocketBase's API (/api/collections/...). Sign in to get a token; the power and scan actions also need the header Sec-Fetch-Site: same-origin, which a browser sends on UpSnap's own pages and which the cross-site guard requires. For example, the number of devices, and the guard refusing a scan request without that header:

H=$(sudo sed -n 's#^UPSNAP_URL=https://\([^/]*\)/$#\1#p' /var/lib/cloudimg/upsnap-credentials.txt)
TOKEN=$(sudo python3 -c 'import json; d={k.rsplit("_",1)[1]: v for k, v in (l.rstrip("\n").split("=", 1) for l in open("/var/lib/cloudimg/upsnap-credentials.txt") if l.startswith("UPSNAP_ADMIN_"))}; print(json.dumps({"identity": d["EMAIL"], "password": d["PASSWORD"]}))' \
  | curl -sk --resolve "$H:443:127.0.0.1" -H 'Content-Type: application/json' --data-binary @- "https://$H/api/collections/_superusers/auth-with-password" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])')
curl -sk --resolve "$H:443:127.0.0.1" -H @- "https://$H/api/collections/devices/records" <<<"Authorization: $TOKEN" | python3 -c 'import json,sys; print(json.load(sys.stdin)["totalItems"], "devices")'
curl -sk -o /dev/null -w 'scan without Sec-Fetch-Site: %{http_code}\n' --resolve "$H:443:127.0.0.1" -H @- "https://$H/api/upsnap/scan" <<<"Authorization: $TOKEN"
0 devices
scan without Sec-Fetch-Site: 403

(The password goes to curl on standard input and the token as a header from standard input, so neither appears in the process list.)

Step 9: Data and backups

Everything UpSnap keeps is in /var/lib/upsnap/pb_data (PocketBase's data.db and auxiliary.db, SQLite). To back it up, stop UpSnap for a moment:

sudo systemctl stop upsnap
sudo tar -C /var/lib/upsnap -czf /root/upsnap-backup.tgz pb_data
sudo systemctl start upsnap

To restore on a new instance, stop UpSnap, replace /var/lib/upsnap/pb_data with the archive's (owner upsnap, mode 700) and start it again; then sign in with the administrator of the instance you backed up. PocketBase's admin UI (/_/, Settings, Backups) can also make and download backups while UpSnap runs.

Step 10: Use your own domain and certificate

  1. In your DNS, point <your-domain> (an A record) at the instance's public IP address. An Elastic IP keeps that address stable.
  2. Tell the instance to use it. This sets the name nginx accepts, the request guards and UpSnap's application URL, and generates a new self signed certificate for it:
sudo upsnap-set-hostname <your-domain>
  1. For a certificate your browser trusts, put the certificate chain for <your-domain> in /etc/ssl/upsnap/upsnap.crt and its private key in /etc/ssl/upsnap/upsnap.key (root only, mode 600), and run sudo systemctl reload nginx. Alternatively put the instance behind an Application Load Balancer with an AWS Certificate Manager certificate that forwards to port 443 on the instance.

Step 11: Security checks

nginx and UpSnap are blocked from the instance metadata service:

for u in nginx upsnap; do printf '%s ' "$u"; systemctl show -p IPAddressDeny --value "$u" | tr ' ' '\n' | sort | tr '\n' ' '; echo; done
nginx 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 
upsnap 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 

The block applies to UpSnap's whole service, so the nmap scans and commands it starts are blocked too. UpSnap runs as upsnap with only CAP_NET_RAW (bit 13, 0x2000) and cannot gain other privileges:

P=$(systemctl show -p MainPID --value upsnap)
ps -o user= -p "$P"
grep -E '^(CapEff|CapBnd|CapAmb|NoNewPrivs)' /proc/"$P"/status
upsnap
CapEff: 0000000000002000
CapBnd: 0000000000002000
CapAmb: 0000000000002000
NoNewPrivs: 1

Anonymous callers get nothing, nginx refuses a power action or scan that another web site's page sends and an API change from a foreign Origin, and a request for a host name the instance does not serve gets no answer at all:

H=$(sudo sed -n 's#^UPSNAP_URL=https://\([^/]*\)/$#\1#p' /var/lib/cloudimg/upsnap-credentials.txt)
curl -sk -o /dev/null -w 'anonymous device list: %{http_code} ' --resolve "$H:443:127.0.0.1" "https://$H/api/collections/devices/records"; curl -sk --resolve "$H:443:127.0.0.1" "https://$H/api/collections/devices/records" | python3 -c 'import json,sys; print(json.load(sys.stdin)["totalItems"], "devices")'
curl -sk -o /dev/null -w 'cross-site wake: %{http_code}\n' --resolve "$H:443:127.0.0.1" -H 'Sec-Fetch-Site: cross-site' "https://$H/api/upsnap/wake/x"
curl -sk -o /dev/null -w 'cross-origin POST: %{http_code}\n' --resolve "$H:443:127.0.0.1" -X POST -H 'Origin: https://evil.example' -H 'Content-Type: application/json' --data '{}' "https://$H/api/collections/devices/records"
curl -sk -o /dev/null -w 'unknown host name: %{http_code}\n' --resolve evil.example:443:127.0.0.1 https://evil.example/ || true
anonymous device list: 200 0 devices
cross-site wake: 403
cross-origin POST: 403
unknown host name: 000

The credentials, the TLS key and UpSnap's data are readable by root (and the data by the upsnap service user) only:

sudo stat -c '%a %U:%G %n' /var/lib/cloudimg/upsnap-credentials.txt /etc/ssl/upsnap/upsnap.key /var/lib/upsnap /var/lib/upsnap/pb_data
600 root:root /var/lib/cloudimg/upsnap-credentials.txt
600 root:root /etc/ssl/upsnap/upsnap.key
700 upsnap:upsnap /var/lib/upsnap
700 upsnap:upsnap /var/lib/upsnap/pb_data

Other notes:

  • Sign-in limits. nginx allows about 10 sign-in attempts a minute per address and answers more with 429; PocketBase's own rate limiter is on as well.
  • Who can reach it. Anyone who can sign in can see the devices they are allowed to see and power them on and off. Open ports 80 and 443 in the security group only to the networks your administrators and users work from.
  • The build. /usr/share/doc/cloudimg-upsnap/BUILD-INFO.txt records the release, its checksums and the Go toolchain; go-version-m.txt next to it lists every library in the program.
  • Logs. nginx logs are in /var/log/nginx; UpSnap logs to the journal (journalctl -u upsnap); PocketBase's request log is in the admin UI under Logs.

Step 12: Keep it up to date

Ubuntu security updates install automatically. To apply all updates now:

sudo apt-get update && sudo apt-get upgrade -y

New UpSnap releases arrive as new versions of this listing, built and checked the same way. To move to one, back up /var/lib/upsnap/pb_data (Step 9), launch the new version and restore it. Read the UpSnap release notes before you move.

Support and licensing

UpSnap is open source under the MIT licence (seriousm4x and contributors); the licence text is in /usr/share/doc/cloudimg-upsnap/, and the source code is at github.com/seriousm4x/UpSnap. PocketBase and the Go libraries UpSnap is built with are open source under permissive licences (MIT, BSD and Apache 2.0). nmap is the Ubuntu package, under the Nmap licence (a GPL 2 variant). There is no per user licence fee. The AMI price covers cloudimg's build, hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA

The other versions on this listing are on the network monitoring guide.