Software Development

AWS

Amazon Web Services - IAM, S3, Amplify, and how this site is deployed

AWS Overview

AWS

Amazon Web Services (AWS) is a cloud platform offering compute, storage, networking, and managed services. This page covers the core services used to run this site, plus key steps to replicate the setup.

Services

ServiceCategoryAnalogyBest For...
EC2ComputeA rented PCFull control over the environment.
LambdaComputeA light switchRunning code only when triggered.
S3StorageA bottomless warehouse"Files, images, and backups."
RDSDatabaseA managed libraryStructured data (SQL).
DynamoDBDatabaseA high-speed post-it wall"Fast, simple key-value data (NoSQL)."
Amazon VPC (Virtual Private Cloud)NetworkingYour own private section of the internetCreating a private network for your resources.
Route 53NetworkingA phone book for the internetManaging domain names and routing traffic.
CloudFrontNetworkingA global CDNSpeeding up delivery of your website content.
Elastic Load Balancing (ELB)NetworkingA traffic copDistributing incoming traffic across multiple instances.
Elastic Container Service (ECS)ComputeA container managerRunning and managing Docker containers at scale.
Elastic Kubernetes Service (EKS)ComputeA Kubernetes managerRunning and managing Kubernetes clusters.

IAM

IAM (Identity and Access Management) controls who can do what inside your AWS account.

Root Account  ← master key, use only for initial setup
    ↓ creates
IAM Admin User  ← your daily driver
    ↓ creates
Roles / Policies for services (Amplify, Lambda, S3, etc.)

Account structure:

IAM Account
├── Users     → people (you, teammates)
├── Groups    → collections of users ("developers", "admins")
├── Roles     → worn by AWS services (Amplify, Lambda, EC2)
└── Policies  → permission rules attached to any of the above

Key rules:

  • Never use the root account for day-to-day work
  • Grant least privilege — only the permissions actually needed
  • Use roles for service-to-service access, not user credentials
  • Keep all resources in the same region

Setup steps:

  1. Sign in as root → IAM → Create admin user with AdministratorAccess
  2. Enable MFA on both root and admin user
  3. Create a dedicated IAM user for programmatic access (S3 writes, CLI)
  4. Attach only the policies that user needs — no AdministratorAccess
  5. Store the access key ID and secret in a password manager, never in code

S3

S3

S3 (Simple Storage Service) stores files as objects inside buckets. It's used here to host all images for this site.

Bucket structure for this site:

mynote-storage/
└── public/
    └── images/
        ├── cs/
        └── web/

Setup steps:

  1. S3 → Create bucket → choose region → uncheck "Block all public access"
  2. Bucket → Permissions → Bucket policy → paste the public read policy below
  3. Create an IAM user with write-only policy → generate access keys
  4. Store keys as environment variables (never hardcode)

Public read policy — allows anyone to fetch objects:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::your-bucket-name/*"
  }]
}

IAM policy for programmatic write access (used by Nuxt Studio to upload images):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
    "Resource": [
      "arn:aws:s3:::your-bucket-name",
      "arn:aws:s3:::your-bucket-name/*"
    ]
  }]
}

Images are referenced in markdown as /images/web/example.svg. A custom ProseImg component resolves these to the full S3 URL at render time:

/images/web/aws.svg
  → https://your-bucket.s3.region.amazonaws.com/public/images/web/aws.svg

AWS Amplify

Amplify

Amplify Hosting is a managed CI/CD and hosting platform. Push to GitHub → Amplify builds and deploys automatically.

How it works:

GitHub / GitLab push
    ↓
Amplify detects change
    ↓
CodeBuild: npm ci → nuxt build
    ↓
Static files → Amplify CDN (CloudFront)
SSR routes  → Lambda function (Node.js)
    ↓
Custom domain via Route 53 / DNS

Setting up Amplify for a Nuxt SSR app

1. Connect your repository

Go to AWS Amplify Console → New app → Host web app → Connect GitHub or GitLab.

2. Build settings

Amplify auto-detects Nuxt. Verify or set the build spec:

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: .amplify-hosting
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

3. Environment variables

Set these in Amplify Console → App settings → Environment variables:

VariablePurpose
S3_ACCESS_KEY_IDIAM user key for S3 writes
S3_SECRET_ACCESS_KEYIAM user secret
S3_BUCKETBucket name
S3_REGIONe.g. ap-northeast-1
S3_ENDPOINTe.g. https://s3.ap-northeast-1.amazonaws.com
AI_GATEWAY_API_KEYVercel AI Gateway key for the assistant

4. Node.js version

Nuxt Content v3 requires Node 22 for node:sqlite. Set this in Amplify Console → Build settings → Live package updates → Node.js version = 22.

Alternatively, set it in nuxt.config.ts:

nitro: {
  preset: 'aws-amplify',
  awsAmplify: {
    runtime: 'nodejs22.x',
  },
}

5. Service role

Amplify needs an IAM service role to deploy Lambda and CloudFront resources. Create a role with the AdministratorAccess-Amplify managed policy, then attach it in App settings → General → Service role.

6. Custom domain

App settings → Domain management → Add domain. Amplify provisions an SSL certificate automatically via ACM. Point your DNS CNAME to the Amplify domain.

Monitoring builds

Build logs are in Amplify Console → your app → the build job. You can also fetch them via CLI:

# List recent builds
aws amplify list-jobs --app-id <app-id> --branch-name main

# Get a specific build's log URL
aws amplify get-job --app-id <app-id> --branch-name main --job-id <id>

Lambda runtime logs go to CloudWatch → Log groups → /aws/lambda/amplify-<app-id>-<branch>-<function>.

CloudFront

CloudFront

CloudFront is AWS's CDN. Amplify uses it automatically to serve static assets globally with low latency. You don't configure it directly — Amplify manages it — but it's useful to know it's there when debugging cache issues.

To force a cache invalidation after a deploy:

aws cloudfront create-invalidation --distribution-id <id> --paths "/*"

How This Site Is Set Up

This site is a Docus documentation site deployed on AWS Amplify.

Stack:

Nuxt 4 + Docus theme
    ├── @nuxt/content v3  ← markdown files in content/
    ├── @nuxtjs/i18n      ← English + French
    └── motion-v          ← animations
    ↓ builds with
Nitro (aws-amplify preset)
    ↓ deploys to
Amplify Hosting
    ├── Static HTML (prerendered pages) → CloudFront CDN
    └── Lambda (Node 22) → SSR + content queries

Image serving: Markdown images use /images/... paths. A custom ProseImg.vue component maps these to absolute S3 URLs at render time, bypassing Amplify's image optimizer (which runs at CDN level and can't reach Lambda proxy routes).

AI assistant: Docus's built-in assistant is enabled. It uses an MCP server at /mcp to search the documentation, and routes AI calls through Vercel AI Gateway (AI_GATEWAY_API_KEY). Model: google/gemini-2.5-flash-preview.

Dev-only modules (not loaded in production Lambda):

  • @nuxthub/core — NuxtHub blob driver, lets Nuxt Studio upload images to S3
  • nuxt-studio — connects to studio.nuxt.com for visual editing

Key config:

// nuxt.config.ts
const isProd = process.env.NODE_ENV === 'production'

export default defineNuxtConfig({
  modules: [
    ...(isProd ? [] : ['@nuxthub/core', 'nuxt-studio']),
    '@nuxt/content',
    // ...
  ],
  nitro: {
    preset: 'aws-amplify',
    awsAmplify: { runtime: 'nodejs22.x' },
  },
})

Repositories:

  • GitHub: NutNut17/mynotemynote.nut17.com
  • GitLab: backup/main branch → mynote2.nut17.com (mirror)

Copyright © 2026 Nut17. All rights reserved.