Operating Systems AWS

Grafana Loki on AWS User Guide

| Product: Grafana Loki on AWS

Overview

This image runs Grafana Loki, the open source log aggregation system from Grafana Labs, fully installed and configured. Loki runs in single binary single tenant mode with a filesystem chunk store, and an nginx reverse proxy on port 80 fronts the Loki HTTP API and protects the push and query endpoints with HTTP basic authentication. The companion logcli command line query tool is preinstalled.

Loki chunks, rules and the write ahead log live on a separate, independently resizable EBS volume mounted at /var/lib/loki, so the log storage tier is kept off the operating system disk and can be grown without disturbing the rest of the instance.

On the first boot of every deployed instance, a one shot service generates a fresh HTTP basic authentication password, unique to that instance, writes the bcrypt hash into the nginx htpasswd file, and stores the plain text value in a root only file at /root/loki-credentials.txt. No shared or default credentials ship in the image.

Prerequisites

Before you deploy this image you need:

  • An Amazon Web Services account where you can launch EC2 instances
  • IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
  • An EC2 key pair in the target Region for SSH access to the instance
  • A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound port 80 from whichever clients will push or query logs
  • The AWS CLI version 2 installed locally if you plan to deploy from the command line

Step 1: Launch the Instance from the AWS Marketplace

Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for Grafana Loki. Select the cloudimg listing and choose Select, then Continue on the subscription summary.

Pick an instance type of m5.large or larger as a balanced default; size the instance to the log ingest rate and retention you intend to keep. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network and inbound port 80 from the networks that will send logs to Loki. Leave the root volume at the default size. The image attaches a dedicated 30 GiB log storage volume automatically.

Select Launch instance. First boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg Grafana Loki Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens port 22 from your management network and port 80 from your log producers.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --block-device-mappings '{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":20,"VolumeType":"gp3"}}' \
  --metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=grafana-loki}]'

The image attaches its dedicated 30 GiB log storage volume automatically. To start with more log storage, enlarge that volume on the Storage step in the console, or add a second block device mapping on the CLI.

Step 3: Connect to the Instance over SSH

Connect to the instance with SSH as the default login user for the operating system variant you launched. The login user differs by variant:

Operating system variant SSH login user
Ubuntu 24.04 ubuntu

Replace <key-file> with the path to your private key file and <instance-public-ip> with the public IP address or DNS name of the instance.

ssh -i <key-file> ubuntu@<instance-public-ip>

Step 4: Confirm the Loki and nginx Services Are Running

Check that the Loki daemon, the nginx reverse proxy and the first boot service are all active. All three return active:

systemctl is-active loki.service nginx.service loki-firstboot.service

Check the installed Loki version and the bundled logcli companion tool. The version banner shows version 3.x.y, the Go toolchain and the platform:

/usr/local/bin/loki -version
/usr/local/bin/logcli --version

Step 5: Retrieve the Per Instance Basic Auth Password

The first boot service generated a fresh HTTP basic authentication password for the cloudimg user on this instance. Read it back from the root only credentials file:

sudo cat /root/loki-credentials.txt

The file looks like this, with the rotated password unique to your instance and the public URLs filled in from the EC2 instance metadata service:

# Grafana Loki — Per-VM Credentials
# Generated: Sun May 24 11:11:17 UTC 2026
# Used by the nginx reverse proxy in front of the Loki HTTP API.

loki.basicauth.user=cloudimg
loki.basicauth.pass=<LOKI_BASIC_AUTH_PASSWORD>

# Public endpoints (port 80, basic auth required):
LOKI_PUSH_URL=http://<instance-public-ip>/loki/api/v1/push
LOKI_QUERY_URL=http://<instance-public-ip>/loki/api/v1/query
LOKI_READY_URL=http://<instance-public-ip>/ready
LOKI_METRICS_URL=http://<instance-public-ip>/metrics

# Direct loopback (no auth, localhost only):
LOKI_LOCAL_URL=http://127.0.0.1:3100/

Treat the password as sensitive. The file is readable only by the root user (0600 root:root).

Step 6: Confirm the nginx Basic Auth Gate

Hitting the public endpoint without credentials returns HTTP 401, proving the basic auth gate is in place. Run this from the instance or any client with port 80 reachable:

curl -s -o /dev/null -w 'http_code=%{http_code}\n' http://127.0.0.1/
http_code=401

With the rotated credentials, the same request hits Loki's /ready endpoint behind the proxy and returns HTTP 200. Replace <LOKI_BASIC_AUTH_PASSWORD> with the password you read from /root/loki-credentials.txt:

curl -s -o /dev/null -u cloudimg:<LOKI_BASIC_AUTH_PASSWORD> -w 'http_code=%{http_code}\n' http://127.0.0.1/ready
http_code=200

Step 7: Push a Log Line and Query It Back

Push a single log line through the nginx reverse proxy into Loki. The Loki push API expects a JSON document with a stream label set and a list of nanosecond timestamped values, and returns HTTP 204 on success. The block below builds a fresh nanosecond timestamp, posts the line, and prints the HTTP status:

TS=$(date +%s)000000000
curl -s -o /dev/null -u cloudimg:<LOKI_BASIC_AUTH_PASSWORD> -w 'http_code=%{http_code}\n' \
  -X POST -H 'Content-Type: application/json' \
  -d "{\"streams\":[{\"stream\":{\"job\":\"docs\",\"host\":\"build\"},\"values\":[[\"$TS\",\"hello world from cloudimg loki\"]]}]}" \
  http://127.0.0.1/loki/api/v1/push
http_code=204

Query the line back through the Loki query API. Loki returns a JSON envelope with the matched stream labels and the timestamped values:

curl -s -G -u cloudimg:<LOKI_BASIC_AUTH_PASSWORD> \
  --data-urlencode 'query={job="docs"}' \
  --data-urlencode 'limit=5' \
  http://127.0.0.1/loki/api/v1/query_range
{"status":"success","data":{"resultType":"streams","result":[{"stream":{"detected_level":"unknown","host":"build","job":"docs","service_name":"docs"},"values":[["1779621125000000000","hello world from cloudimg loki"]]}],"stats":{"summary":{"bytesProcessedPerSecond":3035,"linesProcessedPerSecond":79,"totalBytesProcessed":38,"totalLinesProcessed":1,"execTime":0.012517,"queueTime":0.000708,"subqueries":1

Step 8: Query Logs with logcli

The cloudimg image ships the official Grafana logcli command line client at /usr/local/bin/logcli. Point it at the local Loki endpoint with the basic auth credentials and run the same query:

LOKI_ADDR=http://127.0.0.1 \
LOKI_USERNAME=cloudimg \
LOKI_PASSWORD=<LOKI_BASIC_AUTH_PASSWORD> \
  /usr/local/bin/logcli query '{job="docs"}' --limit=5

logcli renders one log line per row with the stream labels and the original message. Use it for ad hoc log exploration from the instance itself.

Step 9: Inspect the Loki Data Directory

The cloudimg image mounts a dedicated 30 GiB EBS volume at /var/lib/loki for Loki's chunks, rules and write ahead log. Confirm that the path is on its own filesystem:

df -h /var/lib/loki
ls -lh /var/lib/loki

The Loki user owns chunks/, rules/ and wal/. Grow this volume in the EC2 console under Volumes when retention demands more storage; the filesystem can be expanded online with sudo resize2fs after the EBS modification completes.

Step 10: Scrape Loki's Prometheus Metrics

Loki exposes Prometheus formatted metrics at /metrics through the same nginx basic auth gate. The output begins with # HELP and # TYPE lines and a long list of loki_* counters and gauges. Point any Prometheus or Grafana Alloy scraper at this endpoint with the basic auth credentials:

curl -s -u cloudimg:<LOKI_BASIC_AUTH_PASSWORD> http://127.0.0.1/metrics | head -20

Step 11: Connect a Log Shipper

Most production deployments push logs to Loki from a shipper such as Promtail, Grafana Alloy, Vector or Fluent Bit. Configure your shipper with:

  • url: http://<instance-public-ip>/loki/api/v1/push
  • basic_auth.username: cloudimg
  • basic_auth.password: the password from /root/loki-credentials.txt

For Promtail, the relevant section of clients: looks like:

clients:
  - url: http://<instance-public-ip>/loki/api/v1/push
    basic_auth:
      username: cloudimg
      password: <LOKI_BASIC_AUTH_PASSWORD>

Step 12: Connect Grafana

In Grafana, add a Loki data source under ConnectionsData sourcesAdd data sourceLoki. Set:

  • URL: http://<instance-public-ip>
  • Auth: enable Basic auth and supply username cloudimg and the rotated password.

Save and test the data source. Grafana confirms the connection and you can switch to the Explore view to run LogQL queries such as {job="docs"}.

Maintenance

Restart Loki and the reverse proxy after a configuration change:

sudo systemctl restart loki.service
sudo systemctl reload nginx.service

Tail the Loki journal to see ingestion, query and compaction activity:

sudo journalctl -u loki.service -f

The cloudimg image leaves unattended-upgrades enabled, so security updates for nginx, the kernel and the rest of the base operating system flow in automatically. Apply Loki upgrades by replacing the /usr/local/bin/loki binary with a newer release from the upstream grafana/loki GitHub releases page and restarting the service.

Support

24/7 cloudimg technical support is included with this image. Contact cloudimg through the AWS Marketplace listing or at https://www.cloudimg.co.uk/contact/ for help with Loki deployment, label design, retention tuning, multi tenant migration and log client integration.