Deployment guide

Logdy

Overview

Logdy is an open-source, self-hosted, real-time log viewer. It follows a log file on the VM and streams every new line to a browser. Structured JSON logs are parsed into sortable columns with faceted filters, full-text search and a detail drawer for each line.

Logdy is a single Go binary that keeps the lines it shows in an in-memory buffer, so there is no database to run or back up. An upstream Logdy binary serves its interface with no login. The SecureAnyCloud image changes that.

What you get:

  • HTTPS from the first boot. nginx is the only network entry point and serves Logdy on port 443 with a certificate generated on your VM's first boot. Port 80 only redirects to HTTPS.
  • A password unique to your VM. The whole interface, including the WebSocket that streams the log lines and every /api path, needs HTTP Basic Auth as the user admin. The password is generated on first boot and written to the root-only file /root/logdy-info.txt, and nginx stores only its bcrypt hash. No password is baked into the image and no two VMs share one. Only a static /health endpoint answers without a login.
  • Logdy on loopback only, no network ingest. Logdy listens on 127.0.0.1:8080 and only follows files on the VM. Its socket, forward and HTTP ingest modes are not enabled, so nothing on the network can push lines into your viewer.
  • Fail closed. nginx refuses to start until first boot has written the certificate and the password, so the interface is never served without a login.
  • Built from source with a current toolchain. The newest upstream release binary was built with an old Go toolchain that carries known Go security advisories. SecureAnyCloud compiles the unmodified Logdy 0.17.1 source with Go 1.27.3 instead (details in Step 9).
  • A hardened service. Logdy and the demo generator run as an unprivileged logdy user in a systemd sandbox. Requests for a host name the VM does not serve are dropped, cross-site WebSocket connections are refused, and nginx logs the real client address rather than any X-Forwarded-For header a client sends.
  • A fully patched base. Ubuntu 24.04 LTS is fully patched at build time, with unattended security upgrades switched on.
  • A demo log. A generator appends structured JSON lines every couple of seconds, so the columns, facets and search are populated the moment you sign in. This is demo data only. Step 8 shows you how to point Logdy at your own logs.
  • On the image: Logdy 0.17.1 (/usr/local/bin/logdy, Apache License 2.0), a column and facet layout for the demo log (/etc/logdy/logdy.config.json), a small demo log generator, nginx, Ubuntu 24.04 LTS and the Azure Linux agent.
  • Defaults: user azureuser (or the name you choose) and recommended VM size Standard_B2s.

Prerequisites

  • An active Azure subscription, an SSH key (or a password) and a VNet with a subnet
  • A network security group that allows TCP 22 (SSH), TCP 443 (the Logdy interface) and TCP 80 (redirects to HTTPS) from your own networks only. Never open port 8080, because Logdy listens on loopback.
1

Deploy from the Azure Portal

Search the Azure Marketplace for Logdy, choose the plan and create the VM. Pick Standard_B2s (Logdy itself is very light) and your SSH key or password.

In the networking step, attach a network security group that allows inbound 22, 443 and 80 from your client networks only.

2

Deploy from the Azure CLI

Replace the values in angle brackets:

RG="logdy-prod"; LOCATION="eastus"; VM_NAME="logdy-01" IMAGE_URN="sac1647283583153:logdy-ubuntu-24-04:default:latest" az group create --name "$RG" --location "$LOCATION" az network nsg create -g "$RG" --name logdy-nsg az network nsg rule create -g "$RG" --nsg-name logdy-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name logdy-nsg --name allow-web --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 443 80 --access Allow --protocol Tcp az vm image terms accept --urn "$IMAGE_URN" az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" --size Standard_B2s \
  --admin-username azureuser --ssh-key-values ~/.ssh/id_rsa.pub \
  --nsg logdy-nsg --public-ip-sku Standard
3

Connect and check the services

ssh azureuser@<vm-ip>

The login message shows the web address and where to find the password. First boot takes a few seconds. It generates the password and the certificate, then nginx starts in front of Logdy:

systemctl is-active logdy-firstboot logdy logdy-demo nginx
sudo test -f /var/lib/sac/data/logdy-firstboot.done && echo FIRSTBOOT_DONE /usr/local/bin/logdy --version
active active active active FIRSTBOOT_DONE logdy version 0.17.1

Only SSH and nginx listen on public addresses. Logdy listens on loopback:

sudo ss -Hlntp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | grep -E ':(22|80|443|8080) ' | sort
0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:8080 users:(("logdy")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))

SSH root logins, empty passwords and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf. Whether SSH accepts a password is the choice you made when you created the VM (SSH key or password); the image does not override it.

4

Get your address and password

The address and user name are in the root only file /root/logdy-info.txt:

sudo grep -E '^LOGDY_(URL|UI_USERNAME)=' /root/logdy-info.txt
LOGDY_UI_USERNAME=admin LOGDY_URL=https://<vm-public-ip>/

The password is the LOGDY_UI_PASSWORD line of the same file: sudo grep '^LOGDY_UI_PASSWORD=' /root/logdy-info.txt. Store it in your password manager. It is unique to this VM.

The address is the VM's public IP address from Azure instance metadata, or its private IP address when it has no public IP. The certificate names that host plus the VM's private address:

openssl x509 -in /etc/ssl/logdy/logdy.crt -noout -subject -ext subjectAltName
subject=CN = <vm-public-ip>, O = sac X509v3 Subject Alternative Name: IP Address:<vm-public-ip>, IP Address:<vm-private-ip>, IP Address:127.0.0.1, DNS:localhost
5

Check the login

These checks confirm four things. Port 80 redirects to HTTPS, and /health answers without a login. The interface refuses a missing or wrong password and accepts yours. A request for a host name the VM does not serve is dropped.

The commands read the password into a shell variable and hand it to curl through a file descriptor, so it never appears in the process list or your shell history:

H=$(sudo sed -n 's#^LOGDY_URL=https://\([^/]*\)/.*#\1#p' /root/logdy-info.txt)
PW=$(sudo sed -n 's/^LOGDY_UI_PASSWORD=//p' /root/logdy-info.txt) CA=/etc/ssl/logdy/logdy.crt curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/" curl -s -w ' <- health, HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/health" curl -s -o /dev/null -w 'no login -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/" curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -u admin:not-the-password "https://$H/" curl -s -o /dev/null -w 'your password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") "https://$H/" curl -sk -o /dev/null -w 'other host -> HTTP %{http_code} (000 = connection dropped)\n' -H 'Host: evil.example' https://127.0.0.1/ || true
http:// -> 301 https://<vm-public-ip>/ OK <- health, HTTP 200 no login -> HTTP 401 wrong password -> HTTP 401 your password -> HTTP 200 other host -> HTTP 000 (000 = connection dropped)

--resolve sends the request to this VM while keeping the real host name, so the certificate check passes. From another machine, drop --resolve and use the address directly.

The image also carries a self test. It runs the same checks, then opens the live WebSocket stream through nginx with your password. It confirms that new lines arrive while it is connected and that Logdy's HTTP ingest endpoint stays closed:

sudo /usr/local/sbin/logdy-selftest.sh
OK logdy round-trip over https: health-200 public, UI 401-without / 200-with per-VM creds, wrong-401, api/log ingest off, demo log streaming via WebSocket [demo_lines=26 streamed_live_after_5s=3 seq_range=1-27]
6

Sign in to the web interface

Open the LOGDY_URL address from Step 4 in your browser. The certificate is self-signed (made on your VM), so your browser asks you to accept it once. Step 10 shows how to use your own name and certificate. When the browser asks for a login, enter admin and your password.

Logdy opens on the demo log and keeps streaming. Each JSON line is split into columns for time, level, service, method, path, status, duration and message. The left rail shows each column's values with live counts.

7

Filter, search and inspect

Click a value in the left rail to filter the stream. For example, ERROR under level narrows it to the error lines, with every count updating as new lines arrive. Select Reset all filters to clear them. The search box at the top takes free text and field queries across the parsed columns.

Click a row to open the detail drawer. It lists every field of that line and steps to the next or previous line. Select Show/hide raw message to see the original JSON.

Facets compose, so you can drill into a single service just as easily. For example, choose auth under service.

8

Point Logdy at your own logs

The demo generator only exists to fill the interface on first boot. It writes a structured JSON line every two seconds to /var/log/logdy-demo/app.log:

tail -n 1 /var/log/logdy-demo/app.log
{"time":"2026-10-21T16:13:18Z","level":"INFO","service":"gateway","source":"sac-demo","host":"vm-01","method":"PATCH","path":"/api/v1/search","status":404,"duration_ms":605,"seq":19,"message":"user authenticated"}

When you are ready to view your own logs, stop the demo and repoint Logdy. These commands change the service, so run them yourself.

sudo systemctl disable --now logdy-demo.service
sudo systemctl edit --full logdy.service

In the editor, change the file in the ExecStart line from /var/log/logdy-demo/app.log to your own log. Keep the other options, which keep Logdy on loopback with analytics and update checks off. For example:

ExecStart=/usr/local/bin/logdy follow /var/log/myapp/app.log --full-read --config /etc/logdy/logdy.config.json --port 8080 --ui-ip 127.0.0.1 -n -u

The logdy user must be able to read the file. For system logs in /var/log, add it to the adm group with sudo usermod -aG adm logdy. Then apply the change:

sudo systemctl daemon-reload
sudo systemctl restart logdy.service

/etc/logdy/logdy.config.json defines the columns and facets for the demo log's fields. For your own format, adjust the columns in the interface (the gear icon) and export the layout over that file. Alternatively, remove --config to start from Logdy's defaults.

The Logdy documentation at https://logdy.dev/docs covers columns, parsers and the other input modes. If you enable a network input (socket, forward or the HTTP ingest API with --api-key), keep its port closed in your network security group except to the hosts that send logs.

9

How the Logdy binary was built

The newest upstream release, 0.17.1, publishes a binary built with Go 1.23.2 and older WebSocket and networking libraries, which carry known Go security advisories.

SecureAnyCloud compiles the unmodified 0.17.1 source instead. The build uses the official Go 1.27.3 toolchain, gorilla/websocket raised from 1.5.1 to 1.5.3 (a patch release with a security fix) and the module set to current Go defaults. The build is reproducible, and Go's own vulnerability scanner reports nothing for the shipped binary. The build record ships on the image:

grep -E '^(toolchain |dependency |module language|binary sha256|govulncheck )' /usr/share/doc/logdy/BUILD-PROVENANCE.txt sha256sum /usr/local/bin/logdy
toolchain go1.27.3 linux/amd64, official tarball https://go.dev/dl/go1.27.3.linux-amd64.tar.gz dependency github.com/gorilla/websocket v1.5.1 -> v1.5.3 (GO-2026-6278; go get via the module proxy + sum.golang.org) module language go 1.23.2 -> go 1.27.0 (no DefaultGODEBUG compatibility overrides: every current Go security default applies) binary sha256 96b857fc429cc196b6eeff8d29d55e1a4dbfddece3faa2d261817a5486f8942d (reproducible build) govulncheck v1.9.0 -mode=binary on the compiled binary: no vulnerabilities found 96b857fc429cc196b6eeff8d29d55e1a4dbfddece3faa2d261817a5486f8942d /usr/local/bin/logdy
10

Use your own DNS name, certificate or password

The served host name comes from configuration, never from a request. To serve Logdy under your own DNS name (or after you change the VM's public IP), point the name at the VM and run the helper. The helper records the name, makes a new self-signed certificate for it, updates /root/logdy-info.txt and reloads nginx:

sudo logdy-set-hostname logs.example.com

To use a certificate from your own certificate authority instead, put the full chain in /etc/ssl/logdy/logdy.crt and the private key in /etc/ssl/logdy/logdy.key (owner root, mode 0600), then run sudo nginx -t && sudo systemctl reload nginx. Running logdy-set-hostname again replaces them with a self-signed pair.

To change the password, let htpasswd prompt for it. Never put a password on the command line. Then reload nginx and update your note in /root/logdy-info.txt:

sudo htpasswd -B /etc/nginx/logdy.htpasswd admin
sudo systemctl reload nginx
11

Server components

  • Logdy binary (compiled from source): /usr/local/bin/logdy
  • Build record, licence, README: /usr/share/doc/logdy/
  • Column and facet layout: /etc/logdy/logdy.config.json
  • Demo log (demo data only): /var/log/logdy-demo/app.log
  • Systemd units: logdy.service, logdy-demo.service, logdy-firstboot.service
  • nginx site and Basic auth hash: /etc/nginx/sites-available/sac-logdy, /etc/nginx/logdy.htpasswd
  • Per-VM certificate: /etc/ssl/logdy/logdy.crt, /etc/ssl/logdy/logdy.key (0600)
  • Host name helper: /usr/local/sbin/logdy-set-hostname
  • Per-VM info note: /root/logdy-info.txt (0600)

Commands to inspect these components:

ls /usr/local/bin/logdy /etc/logdy/logdy.config.json /etc/systemd/system/logdy.service
/etc/logdy/logdy.config.json /etc/systemd/system/logdy.service /usr/local/bin/logdy
12

Security notes and operations

  • Restrict ports 443 and 80 to the networks your team uses. Port 8080 is never exposed.
  • Logdy shows whatever the followed file contains to anyone with the password. Point it only at logs your viewers may see, and give separate teams separate VMs.
  • Logdy keeps lines in memory only. A restart clears the view, and nothing is written to disk unless you add --append-to-file. There is no database to back up.
  • nginx logs the real client address of every request and ignores X-Forwarded-For headers sent by clients.
  • Manage the services with systemctl status logdy nginx and read their logs with journalctl -u logdy -u nginx. Unattended upgrades keep Ubuntu and nginx patched.
13

Support and licensing

Logdy is open source under the Apache License 2.0. The licence, README and build record are in /usr/share/doc/logdy/. There is no per-user or per-CPU licence fee. SecureAnyCloud provides the hardening, first-boot setup, the source build and commercial support.

  • Email: sales@secureanycloud.com
  • Website: secureanycloud.com
  • Support hours: 24/7, 24h response SLA

Logdy is a trademark of its respective owner. SecureAnyCloud is not affiliated with or endorsed by the Logdy project. The name is used only to identify the upstream software.

Deploy on Azure

Launch Logdy on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure