Jak hostuję statyczną stronę MkDocs na AWS

I czego uczę się przy okazji o architekturze, bezpieczeństwie i odpowiedzialności za koszty

Probowałem z Amazon Lightsail i Wordpress - koszty były zbyt wysokie. Chciałem prostej przestrzeni — lekkiej, statycznej strony, którą zbuduję sam.
Inspiracja przyszła z dokumentacji FastAPI oparta o MKDocs i hostowana w pełni w AWS.

Ale to nie tylko publikacja.
To sposób na naukę.
Na zrozumienie chmury od środka - przez praktykę, decyzje, błędy i poprawki.


Co wybrałem i dlaczego?

Komponent Opis
MkDocs Generator statycznych stron — szybki, lekki, idealny do bloga
AWS S3 Przechowuje wygenerowane pliki HTML, CSS, JS
Amazon CloudFront Dostarcza stronę globalnie, obsługuje HTTPS + cache
AWS Route 53 DNS dla mojej domeny andrzejoblong.pl
ACM (SSL) Certyfikat SSL dla bezpieczeństwa HTTPS
AWS WAF Zabezpieczenie przed nadużyciami i botami
AWS Budgets Alerty kosztowe — by nie zaskoczył mnie rachunek

Jak to zabezpieczyłem?

S3 bucket

  • Publiczny dostęp do S3: ZABLOKOWANY !
  • Bucket policy z warunkiem AWS:SourceArn == CloudFront
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<BUCKET_ID>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "<CLOUDFRONT_DISTRIBUTION_ARN>"
                }
            }
        }
    ]
}

CloudFront

  • OAC (Origin Access Control): tylko CloudFront może czytać pliki
  • Kompresja objektów
  • Redirect HTTP to HTTPS
  • Dla mojej strony dopuszczam tylko GET, HEAD
  • Cache Key and origin request a) CachingOptimized b) CORS-S3Origin
  • TTL 24h w cache policy
  • Certyfikat SSL (ACM) + domena w Route 53
  • Uproszczona nawigacja dzięki CloudFront Function, która automatycznie dopisuje "index.html" do adresów bez roszerzenia.
function handler(event) {
    var request = event.request;
    var uri = request.uri;

    // Check whether the URI is missing a file name.
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    } 
    // Check whether the URI is missing a file extension.
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }

    return request;
}

Dzięki niemu mogę pisać linki /about, /docs, /blog/, a CloudFront sam znajdzie odpowiednie pliki w S3 - bez błędów.

  • WAF + Rate-based rule

Szacunkowe miesięczne koszty

Usługa Koszt (USD) Uwagi
S3 (storage) 0.01–0.10 Pliki statyczne
S3 (GET requests) 0.01–0.50 W zależności od liczby odwiedzin
CloudFront 1–3 Transfer + cache
Route 53 0.50 DNS + domena
ACM SSL 0.00 Darmowy
WAF 5 + 1 USD/reguła/ miesięcznie
RAZEM ~8 USD Przy lekkiej stronie

Czego się uczę dzięki temu projektowi?

  • Projektowanie CDN + cache + dostępów
  • Świadome zarządzanie kosztami
  • Rozdzielenie infrastruktury i treści
  • Świadomość architektury chmurowej

Moja osobista checklista

  • S3: brak publicznego dostępu
  • CloudFront: aktywne cache, SSL
  • OAC: tylko CloudFront do S3
  • Route 53: domena
  • WAF: rate limit, bot protection
  • Budgets: alert kosztowy przy 5 USD

Obsary do usprawnień

Wdrożenie automatyzacji

mkdocs build

Wygenerowane pliki trafiają do site/

Wrzucenie strony na S3:

aws s3 sync site/ s3://<BUCKET_ID>/ --delete

Inwalidacja cache w CloudFront:

aws cloudfront create-invalidation \
  --distribution-id <MY_ID> \
  --paths "/index.html" "/"
  • skrypt do automatyzacji
  • automatyzacja deploy z GitHub Actions
  • Terraform do zarządzania infrastrukturą

Podsumowanie

Nie buduję najtaniej. Buduję świadomie. Dla siebie.
Aby się uczyć, testować, rozwijać. To projekt, w którym dane i decyzje spotykają się z odpowiedzialnością.

Żródła

Amazon CloudFront

Amazon Simple Storage Service

Amazon Route 53

AWS Certificate Manager

AWS Budgets

AWS WAF