GoAlert On-Call Alerting on AWS User Guide
Overview
This AMI runs GoAlert 0.34.1, the open source on-call scheduling and alerting platform maintained by Target. GoAlert routes incidents to the right responder at the right time through on-call schedules, rotations and escalation policies, and delivers notifications by SMS, voice call, email and Slack once you connect a delivery provider. It ships as a single self-contained Go binary, run by an unprivileged goalert system account under a systemd service that starts it on boot and restarts it on failure, backed by a local PostgreSQL 16 database on a dedicated data volume.
GoAlert listens on the loopback address 127.0.0.1:8081 by design and is never exposed directly. nginx is installed as a reverse proxy on port 80 that forwards every request to GoAlert, including the WebSocket connections the UI uses for live updates. PostgreSQL is bound to loopback only.
What is included:
- GoAlert 0.34.1 (official upstream release binary, sha256 pinned), run by systemd as the unprivileged
goalertuser - The GoAlert web UI and API on
:80(nginx reverse proxy to127.0.0.1:8081) - A per-instance
adminaccount created on first boot and recorded in a root-only file - A per-instance data encryption key and a per-instance PostgreSQL password, both generated on first boot
- PostgreSQL 16 on a dedicated EBS data volume, bound to loopback, holding schedules, escalation policies, services and users
postgresql.service,goalert.serviceandnginx.serviceas systemd units, enabled and active- An unauthenticated
/healthzendpoint for Elastic Load Balancing health checks - 24/7 cloudimg support
Connecting to your instance
Connect over SSH as the default login user for the operating system variant you launched. The security group must allow inbound 22/tcp from your management network and 80/tcp for the web UI.
| OS variant | SSH login user | Connect |
|---|---|---|
| Ubuntu 24.04 | ubuntu |
ssh ubuntu@<instance-public-ip> |
Prerequisites
An AWS account, an EC2 key pair, and a VPC subnet in the target region. m5.large (2 vCPU / 8 GiB RAM) is a sensible starting point; size up for larger teams. Security group inbound: allow 22/tcp from your management network and 80/tcp for the web UI. GoAlert serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain and set the Public URL accordingly (see Step 6).
Step 1 - Launch the instance
Subscribe to the listing in AWS Marketplace and launch it through the EC2 console or the AWS CLI, selecting your key pair, an m5.large (or larger) instance type, and a security group that allows 22/tcp and 80/tcp inbound. The dedicated PostgreSQL data volume is attached and mounted automatically.
Step 2 - Connect and confirm the services are running
GoAlert is served by nginx on port 80, which reverse-proxies to the Go binary on 127.0.0.1:8081, which in turn talks to PostgreSQL on 127.0.0.1:5432. Connect over SSH, then confirm all three services are active and note that only nginx listens on a public address - GoAlert and PostgreSQL are bound to loopback:
systemctl is-active postgresql goalert nginx goalert-firstboot
sudo ss -tlnp | grep -E ':80 |:8081 |:5432 '
Expected output:
active
active
active
active
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 200 127.0.0.1:5432 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8081 0.0.0.0:*
LISTEN 0 511 [::]:80 [::]:*
Step 3 - Retrieve your admin password
On the first boot of every instance, goalert-firstboot.service generates a unique administrator password, a PostgreSQL password and a data encryption key, runs the database migrations, then creates the single admin account with goalert add-user. It writes the admin username, password and dashboard URL into a root-only file. Read it with:
sudo cat /root/goalert-credentials.txt
There is no default or shared credential in the image: the admin account does not exist until first boot creates it with a password unique to this instance. Store the password somewhere safe.
Step 4 - Confirm the version and health endpoint
nginx serves an unauthenticated /healthz endpoint for load balancer health checks. Confirm the GoAlert and PostgreSQL versions and that the UI responds:
goalert version | head -4
psql --version
curl -sI http://127.0.0.1/healthz | head -1
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
Expected output:
Version: v0.34.1
GitCommit: 0918387e38650aaddd6a923d445ee992f64d6ab6 (clean)
BuildDate: 2025-10-06T20:20:57Z
GoVersion: go1.25.1 (gc)
psql (PostgreSQL) 16.14 (Ubuntu 16.14-0ubuntu0.24.04.1)
HTTP/1.1 200 OK
200
Step 5 - The local PostgreSQL backend on a dedicated volume
Everything GoAlert stores - schedules, rotations, escalation policies, services, users and alerts - lives in the local goalert PostgreSQL database, owned by the goalert role and reachable only over loopback. The database lives on a dedicated EBS data volume mounted at /var/lib/postgresql, separate from the OS disk and independently resizable and snapshottable. The image ships with the schema migrated and exactly one account (the per-instance admin):
findmnt /var/lib/postgresql
sudo -u postgres psql -tAc "SHOW data_directory"
sudo -u postgres psql -l | grep goalert
sudo -u postgres psql -d goalert -tAc "SELECT count(*) FROM users"
Expected output:
TARGET SOURCE FSTYPE OPTIONS
/var/lib/postgresql /dev/nvme1n1 ext4 rw,relatime
/var/lib/postgresql/16/main
goalert | goalert | UTF8 | libc | C.UTF-8 | C.UTF-8 |
1
Step 6 - Sign in to the web UI
Browse to http://<instance-public-ip>/. Enter admin and the password from Step 3.

GoAlert validates that your browser's address matches its configured Public URL when you sign in. On this image goalert-configure.service sets the Public URL to the instance's detected public IP on every boot (resolved through EC2 IMDSv2), so signing in over the instance public IP works out of the box. If you reach GoAlert through a different hostname (a DNS name, a load balancer or your own TLS proxy), set the correct URL once: edit GOALERT_PUBLIC_URL in /etc/goalert/goalert.env and run sudo systemctl restart goalert, or set it from the Admin page after signing in.
Step 7 - Build your on-call schedules
Open Schedules from the navigation and click Create Schedule. Give the schedule a name and time zone, then add rotations and assign users to define who is on call and when. Schedules are the foundation of GoAlert: escalation policies notify whoever a schedule says is on call at the moment an alert fires.

Step 8 - Define escalation policies
Open Escalation Policies and click Create Escalation Policy. An escalation policy is an ordered set of steps - notify this schedule, wait N minutes, then notify the next - with an optional repeat count, so an unacknowledged alert is escalated automatically until someone responds.

Step 9 - Register your services and receive alerts
Open Services and click Create Service, attaching it to an escalation policy. A service represents something you want alerts for (an API, a website, a job). Each service gets integration keys - a generic API endpoint, plus Grafana, Prometheus Alertmanager, email and other formats - that your monitoring tools call to raise an alert, which GoAlert then routes through the service's escalation policy. Active alerts appear in the UI where responders acknowledge and close them.

Step 10 - Enable alert delivery (SMS, voice, email, Slack)
The image ships the fully functional UI, schedules, escalation policies and services. To actually deliver notifications you connect a provider from the Admin -> Config page after signing in:
- Twilio for SMS and voice calls (Account SID, Auth Token, From Number)
- SMTP for email notifications to responders
- Slack to notify channels as part of an escalation policy
- Mailgun or the built-in SMTP ingress to create alerts from inbound email
Each provider is toggled on and configured in its own section of the Admin Config page. See the GoAlert documentation for provider-specific setup.
Maintenance
- Back up your data: everything GoAlert stores lives in the local
goalertPostgreSQL database on the dedicated data volume. Snapshot the volume with EBS snapshots or AWS Backup, or usepg_dump goalertfor logical backups. - Resize storage: the database volume is independent of the OS disk - grow it with an EBS volume modification and
resize2fsas your alert history grows. - Public URL: the Public URL is set to the detected public IP on each boot. For a stable hostname or HTTPS, set
GOALERT_PUBLIC_URLin/etc/goalert/goalert.envandsudo systemctl restart goalert. - Security updates: keep the OS patched with
sudo apt-get update && sudo apt-get upgrade, and reboot when a new kernel is installed. - TLS: for production, front GoAlert with your own domain and a TLS-terminating reverse proxy or an Application Load Balancer, and set the Public URL to the
https://address. - Add responders: open Users to manage accounts, and enable GitHub or OIDC single sign-on from Admin -> Config for larger teams.
Support
cloudimg provides 24/7/365 expert technical support for this image. Contact support@cloudimg.co.uk. GoAlert is licensed under the Apache License 2.0. This image is provided by cloudimg; additional charges apply for build, maintenance and 24/7 support.