Skip to content

LeanerCloud/terraform-aws-umami

Repository files navigation

Umami Analytics - Terraform Module

Self-hosted Umami analytics on AWS EC2 with automatic TLS via Let's Encrypt.

Architecture

                                    ┌─────────────────────────────────────────────────────┐
                                    │              Auto Scaling Group (min=max=1)         │
                                    │  ┌───────────────────────────────────────────────┐  │
                                    │  │         EC2 t4g.nano (Amazon Linux 2023)      │  │
      Internet                      │  │                                               │  │
          │                         │  │  ┌─────────────────────────────────────────┐  │  │
          │    HTTPS (443)          │  │  │              Docker Compose             │  │  │
          ▼                         │  │  │                                         │  │  │
    ┌───────────┐                   │  │  │  ┌─────────┐   ┌─────────┐   ┌───────┐  │  │  │
    │  Elastic  │───────────────────┼──┼──┼─▶│  Caddy  │──▶│  Umami  │──▶│ Postgres│ │  │  │
    │    IP     │                   │  │  │  │  (TLS)  │   │  (app)  │   │  (db)  │  │  │  │
    └───────────┘                   │  │  │  └─────────┘   └─────────┘   └───┬────┘  │  │  │
                                    │  │  │                                  │       │  │  │
                                    │  │  └──────────────────────────────────┼───────┘  │  │
                                    │  │                                     │          │  │
                                    │  └─────────────────────────────────────┼──────────┘  │
                                    │                                        │             │
                                    └────────────────────────────────────────┼─────────────┘
                                                                             │
                                                                             │ mount
                                                                             ▼
                                                                    ┌───────────────┐
                                                                    │   EBS Volume  │
                                                                    │   (gp3 10GB)  │
                                                                    │               │
                                                                    │  /data/       │
                                                                    │  ├── postgres │
                                                                    │  └── caddy    │
                                                                    └───────────────┘

Features

  • Minimal footprint: t4g.nano instance (~$3/month) with ARM64 architecture
  • Persistent data: External EBS volume survives instance recycling
  • Auto-recovery: ASG automatically replaces unhealthy instances
  • Automatic TLS: Caddy handles Let's Encrypt certificate provisioning
  • Ad-blocker bypass: Configurable tracker script name
  • SSM access: No SSH keys needed, use AWS Systems Manager for access
  • 2GB swap: Configured swap file to handle memory pressure on t4g.nano
  • CloudWatch monitoring: Optional email alerts for CPU, memory, disk, and Docker container health
  • Route 53 integration: Optional automatic DNS record creation

Cost Estimate

Resource Monthly Cost
t4g.nano (eu-west-1) ~$3.07
EBS gp3 10GB (data) ~$0.80
EBS gp3 8GB (root) ~$0.64
Elastic IP (attached) $0.00
CloudWatch Alarms (5x, optional) ~$0.50
Total ~$4-5/month

Prerequisites

  • AWS account with appropriate permissions
  • Terraform >= 1.0
  • Domain name with DNS you can configure

State Backend (Optional)

By default, Terraform stores state locally. For team collaboration or CI/CD, configure an S3 backend:

  1. Create an S3 bucket for state:

    aws s3 mb s3://your-terraform-state-bucket --region us-east-1
    aws s3api put-bucket-versioning --bucket your-terraform-state-bucket \
      --versioning-configuration Status=Enabled
  2. Copy and configure the backend:

    cp backend.tf.example backend.tf
    # Edit backend.tf with your bucket name
  3. Initialize with the new backend:

    terraform init

Usage

  1. Copy the example tfvars file:

    cp terraform.tfvars.example terraform.tfvars
  2. Generate an app secret:

    openssl rand -hex 32
  3. Edit terraform.tfvars:

    domain            = "stats.example.com"
    letsencrypt_email = "[email protected]"
    app_secret        = "your-generated-secret"
  4. Initialize and apply:

    terraform init
    terraform apply
  5. Create DNS record: Point your domain to the Elastic IP shown in the outputs.

  6. Access Umami:

    • URL: https://your-domain.com
    • Default credentials: admin / umami
    • Change the password immediately!

Variables

Name Description Default
domain Domain for Umami (required)
letsencrypt_email Email for Let's Encrypt (required)
app_secret Secret for Umami sessions (required)
instance_type EC2 instance type t4g.nano
region AWS region eu-west-1
root_volume_size Root volume size (GB) 8
data_volume_size Data volume size (GB) 10
tracker_script_name Custom script name data
vpc_id VPC ID (optional) default VPC
subnet_id Subnet ID (optional) first subnet
allowed_ssh_cidr CIDR for SSH access null
route53_zone_name Route 53 zone for DNS record null
alert_email Email for CloudWatch alerts null
cpu_threshold_percent CPU alert threshold 80
memory_threshold_percent Memory alert threshold 80
disk_threshold_percent Disk alert threshold 80

Outputs

Name Description
elastic_ip The Elastic IP address
url Full Umami URL
dns_record DNS record to create
asg_name ASG name for management
recycle_instance_command Command to recycle the instance

Operations

Recycle the instance

To apply updates or recover from issues:

aws autoscaling terminate-instance-in-auto-scaling-group \
  --instance-id $(aws autoscaling describe-auto-scaling-groups \
    --auto-scaling-group-names umami \
    --query 'AutoScalingGroups[0].Instances[0].InstanceId' \
    --output text) \
  --no-should-decrement-desired-capacity

Access via SSM

aws ssm start-session --target <instance-id>

View user-data logs

aws ssm start-session --target <instance-id>
# Then on the instance:
sudo cat /var/log/user-data.log

Check Docker services

aws ssm start-session --target <instance-id>
# Then on the instance:
cd /opt/umami && docker-compose ps
docker-compose logs -f

Troubleshooting

Instance not coming up healthy

  1. Check ASG activity:

    aws autoscaling describe-scaling-activities --auto-scaling-group-name umami
  2. Check user-data log via SSM

Let's Encrypt not working

  • Ensure DNS is pointing to the Elastic IP
  • Check Caddy logs: docker-compose logs caddy
  • Let's Encrypt rate limits: wait 1 hour if you've made too many requests

Database issues

  • Data is stored on external EBS volume at /data/postgres
  • Volume survives instance termination
  • Check PostgreSQL logs: docker-compose logs db

Monitoring

When alert_email is provided, the module creates CloudWatch alarms that send email notifications via SNS:

Alarm Trigger
CPU High CPU > 80% for 10 minutes
Memory High Memory > 80% for 10 minutes
Disk High (root) Root disk > 80%
Disk High (data) Data disk > 80%
Docker Unhealthy < 3 containers running

Important: You must confirm the SNS email subscription by clicking the link in the confirmation email.

View CloudWatch metrics

aws cloudwatch list-metrics --namespace CWAgent --region eu-west-1

Check alarm states

aws cloudwatch describe-alarms --alarm-name-prefix umami --region eu-west-1 \
  --query 'MetricAlarms[*].[AlarmName,StateValue]' --output table

Shameless Plug

This module is brought to you by LeanerCloud. We help companies reduce their cloud costs using a mix of services and tools such as AutoSpotting.

If your company is operating at scale on AWS and would like to reduce your cloud costs, please get in touch using our contact form.

License

MIT License - see LICENSE file.

About

Terraform module for self-hosted Umami analytics on AWS EC2 with automatic TLS

Resources

License

Stars

Watchers

Forks

Packages

No packages published