majorwiki/02-selfhosting/cloud/aws-s3-cost-management.md
majorlinux 52ca8a0413 wiki: batch update — 4 new articles + 4 updates
New articles:
- Postfix SendGrid TLS handshake failure (port 465 vs 587)
- Plex transcoding troubleshooting
- Ansible Ubuntu reboot detection kernel mismatch
- WSL2 PyTorch checkpoint Windows filesystem deadlock

Updated:
- AWS S3 cost management (expanded)
- Network overview (IP updates)
- HEVC VAAPI batch encode (progress + fixes)
- SUMMARY.md (new entries)
2026-05-25 13:55:10 -04:00

6.9 KiB
Raw Blame History

title domain category tags status created updated
AWS S3 Cost Management selfhosting cloud
aws
s3
cost
billing
mastodon
glacier
published 2026-04-19 2026-05-23

AWS S3 Cost Management

The majorlinux AWS account is used exclusively for S3 object storage. This covers how to monitor costs, what's driving the bill, and how to reduce it.

Account Overview

  • Account ID: 408469496267
  • Account name: majorlinux
  • Services in use: S3 (Standard + Glacier Deep Archive), AWS Config, Cost Explorer
  • Monthly spend: ~$24/mo (May 2026, post-media-prune, post-STANDARD_IA revert)

Buckets and Cost Drivers

Bucket Size Storage Class Cost/mo Purpose
majortoot ~7 GB (after weekly prune running) S3 Standard ~$0.16/mo Mastodon media
majorhomebackup 16 TiB Glacier Deep Archive ~$1112/mo MLS stream archives (sole copy)
config-bucket-* ~185 KB S3 Standard ~$0.00 AWS Config snapshots

CLI Setup

AWS CLI installed on MajorMac via Homebrew. Credentials for MajorCLI user at ~/.aws/credentials.

brew install awscli
# Credentials: MajorCLI IAM user (S3 + Billing read access)
# Key ID: AKIAV6GVN4HF4Y6EV4NM — created 2026-05-23

Useful commands

# Check current month spend by service
aws ce get-cost-and-usage \
  --time-period Start=2026-05-01,End=2026-05-31 \
  --granularity MONTHLY \
  --metrics "UnblendedCost" \
  --group-by Type=DIMENSION,Key=SERVICE

# Daily cost breakdown with top usage types
aws ce get-cost-and-usage \
  --time-period Start=2026-05-01,End=2026-05-23 \
  --granularity DAILY \
  --metrics "UnblendedCost" \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Simple Storage Service"]}}' \
  --group-by Type=DIMENSION,Key=USAGE_TYPE

# View anomaly alerts
aws ce get-anomalies \
  --date-interval StartDate=2026-05-01,EndDate=2026-05-31

# List budgets
aws budgets describe-budgets --account-id 408469496267

Budget Alert

MajorS3MonthlyAlert configured 2026-04-19:

  • 80% threshold → email at $24 actual spend
  • 100% threshold → email at $30 actual spend
  • Recipient: maj.linux@gmail.com

[!note] Thresholds updated 2026-05-23 to reflect actual ~$24/mo steady-state spend (was $20/$25, set when spend was higher due to large majortoot bucket before prune took effect).

Cost Reduction Options

majortoot — S3 Standard-IA (⚠️ DO NOT USE — tried and reverted)

Attempted 2026-05 — reverted 2026-05-17. Do not retry without careful planning.

The theory: switching S3_STORAGE_CLASS=STANDARD_IA saves ~$45/mo on storage. In practice, the bulk avatar restore operation (restore-avatars.sh, May 910) ran while STANDARD_IA was active. The ~5,223 account refreshes across 1,095 domains generated ~470,000 SIA Tier 1 PUT requests ($4.72) plus early-deletion fees ($1.21) when the objects were replaced after reverting to STANDARD on May 17.

STANDARD_IA is only economical if:

  • The bucket has no large bulk-write operations (media cache rebuilds, avatar restores)
  • Objects are written and left for >30 days (early deletion incurs minimum 30-day fee)
  • The per-request cost ($0.01/1,000 for SIA vs $0.005/1,000 for Standard) doesn't offset storage savings

With the weekly prune now running correctly and the bucket shrinking toward 7 GB, the storage savings of SIA are negligible ($0.05/mo). Leave at STANDARD.

majortoot — Weekly media prune

Weekly cron deployed (0 3 * * 0) via configure_mastodon_media_prune.yml. Removes remote federated cache older than 7 days. Bucket shrinking from 648 GB toward ~7 GB over time. This is the real cost driver — let it run.

majorhomebackup — Self-host consideration

Deep Archive at $0.00099/GB is the cheapest cloud tier — no cloud alternative is cheaper. If the MLS archives are no longer needed, deletion would save $1112/mo. A 20TB HDD ($300400) would break even in ~2.5 years vs. continued cloud storage. These are the sole copy — do not delete without a separate backup.

IAM Users

User Scope Credentials location Notes
MajorToot S3 full (MajorsHouse group) ~/.aws/credentials on majortoot Key rotated 2026-05-23
MajorHome S3 full (MajorsHouse group) ~/.aws/credentials on majorhome Key pending rotation (see below)
MajorCLI S3 full + Billing read (MajorsHouse group + AWSBillingReadOnlyAccess) ~/.aws/credentials on MajorMac Created 2026-05-23, replaces root key

[!warning] Root access keys deleted 2026-05-23. Do NOT create new root access keys. Use MajorCLI for CLI work on MajorMac. The root account password (in Vaultwarden) is sufficient for console access.

[!warning] MajorHome key (AKIAV6GVN4HF7POCNW6D) exposed in shell session 2026-05-23. Rotate via AWS Console → IAM → Users → MajorHome → Security credentials. Update ~/.aws/credentials on majorhome afterward.

[!note] MajorCLI does not have IAM permissions. Future key rotation requires AWS Console login or temporary IAM policy attachment. Consider adding a SelfManageKeys inline policy to MajorCLI via console.

Conformance Pack

MajorConformance (created 2024-12-20) monitors S3 buckets for:

  • Public read/write access (majortoot is intentionally public — Mastodon media)
  • Account-level public access blocks (off by design, same reason)
  • S3 default object lock (not enabled — expected)
  • S3 event notifications (not enabled — expected)

Evaluations cost $0.001 each and run on a periodic schedule. Safe to ignore; at current scale costs pennies per month.

CloudTrail Audit Logging

MajorTrail configured 2026-05-23:

  • S3 bucket: majorcloudtrail-408469496267
  • Multi-region: yes — captures API calls across all regions
  • Global service events: yes — includes IAM, STS, S3 control plane
  • Log file validation: enabled — tamper detection via digest files
  • Retention: logs accumulate in S3; no automatic expiry configured

Use CloudTrail to investigate unexpected cost spikes, IAM key usage, and bucket write activity. Without it, historical API calls are unrecoverable (learned the hard way from the May 2026 SIA spike investigation).

# List recent CloudTrail events (last 1h, S3 writes only)
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=PutObject \
  --start-time $(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
  --query 'Events[].{Time:EventTime,User:Username,Resource:Resources[0].ResourceName}' \
  --output table

# Look up events by specific access key
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAV6GVN4HF3BWAIAGC \
  --output table