diff --git a/README.md b/README.md index 262260b5..c4dfeed7 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,42 @@ Installation - `NEXT_PUBLIC_HIDE_REPO_LINK = 1` removes footer link to repo - `NEXT_PUBLIC_HIDE_FILM_SIMULATIONS = 1` prevents Fujifilm simulations showing up in `/grid` sidebar +### Setup alternate storage + +#### AWS S3 + +1. [Create bucket](https://s3.console.aws.amazon.com/s3) with "Block all public access" turned off + - Setup CORS: + ``` + [{ + "AllowedHeaders": [], + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "http://localhost:*", + "{PRODUCTION_DOMAIN}", + "https://*${VERCEL_PROJECT}.vercel.app" + ], + "ExposeHeaders": [] + }] + ``` + - Store configuration + - `NEXT_PUBLIC_S3_BUCKET` + - `NEXT_PUBLIC_S3_REGION` +2. [Create IAM policy](https://console.aws.amazon.com/iam/home#/policies) for client uploads (JSON editor recommended) + - Action: `s3:PutObject` + - Resource: `arn:aws:s3:::{BUCKET_NAME}/uploads/*` +3. [Create IAM policy](https://console.aws.amazon.com/iam/home#/policies) for admin actions (JSON editor recommended) + - Action: `s3:PutObject`, `s3:GetObject`, `s3:ListBucket`, `s3:DeleteObject` + - Resource: `arn:aws:s3:::{BUCKET_NAME}`, `arn:aws:s3:::{BUCKET_NAME}/*` +4. [Create IAM user](https://console.aws.amazon.com/iam/home#/users) for upload policy (by choosing "Attach policies directly"), create access key under "Security credentials," choose "Application running outside AWS," and store credentials + - `NEXT_PUBLIC_S3_UPLOAD_ACCESS_KEY` + - `NEXT_PUBLIC_S3_UPLOAD_SECRET_ACCESS_KEY` +5. [Create IAM user](https://console.aws.amazon.com/iam/home#/users), for admin policy (by choosing "Attach policies directly"), , create access key under "Security credentials," choose "Application running outside AWS," and store credentials (_ensure admin environment variables are not prefixed with `NEXT_PUBLIC`_) + - `S3_ADMIN_ACCESS_KEY` + - `S3_ADMIN_SECRET_ACCESS_KEY` + FAQ - Q: My images/content have fallen out of sync with my database and/or my production site no longer matches local development. What do I do?
diff --git a/next.config.js b/next.config.js index 1b9df8e9..377b4673 100644 --- a/next.config.js +++ b/next.config.js @@ -1,24 +1,40 @@ -/** @type {import('next').NextConfig} */ - -const STORE_ID = process.env.BLOB_READ_WRITE_TOKEN?.match( +const VERCEL_BLOB_STORE_ID = process.env.BLOB_READ_WRITE_TOKEN?.match( /^vercel_blob_rw_([a-z0-9]+)_[a-z0-9]+$/i, )?.[1].toLowerCase(); +const VERCEL_BLOB_HOSTNAME = VERCEL_BLOB_STORE_ID + ? `${VERCEL_BLOB_STORE_ID}.public.blob.vercel-storage.com` + : undefined; + +const AWS_S3_HOSTNAME = + process.env.NEXT_PUBLIC_S3_BUCKET && + process.env.NEXT_PUBLIC_S3_REGION + // eslint-disable-next-line max-len + ? `${process.env.NEXT_PUBLIC_S3_BUCKET}.s3.${process.env.NEXT_PUBLIC_S3_REGION}.amazonaws.com` + : undefined; + +/** @type {import('next').NextConfig} */ +const nextConfig = { + images: { + imageSizes: [200], + remotePatterns: [] + .concat(VERCEL_BLOB_HOSTNAME ? { + protocol: 'https', + hostname: VERCEL_BLOB_HOSTNAME, + port: '', + pathname: '/**', + } : []) + .concat(AWS_S3_HOSTNAME ? { + protocol: 'https', + hostname: AWS_S3_HOSTNAME, + port: '', + pathname: '/**', + } : []), + minimumCacheTTL: 31536000, + }, +}; const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); -const nextConfig = { - images: { - imageSizes: [200], - remotePatterns: [{ - protocol: 'https', - hostname: `${STORE_ID}.public.blob.vercel-storage.com`, - port: '', - pathname: '/**', - }], - minimumCacheTTL: 31536000, - }, -}; - module.exports = withBundleAnalyzer(nextConfig); diff --git a/src/site/SiteChecklistClient.tsx b/src/site/SiteChecklistClient.tsx index 593513d5..0832e998 100644 --- a/src/site/SiteChecklistClient.tsx +++ b/src/site/SiteChecklistClient.tsx @@ -121,16 +121,30 @@ export default function SiteChecklistClient({ and connect to project - {renderLink( - 'https://vercel.com/docs/storage/vercel-blob/quickstart', - 'Create Vercel Blob store', - )} - {' '} - and connect to project +
    +
  1. + Vercel Blob: + {' '} + {renderLink( + 'https://vercel.com/docs/storage/vercel-blob/quickstart', + 'create store', + )} + {' '} + and connect to project +
  2. +
  3. + AWS S3: + {' '} + {renderLink( + 'https://github.com/sambecker/exif-photo-blog#aws-s3', + 'create/configure bucket', + )} +
  4. +
0; +const hasAwsS3Storage = + (process.env.NEXT_PUBLIC_S3_BUCKET ?? '').length > 0 && + (process.env.NEXT_PUBLIC_S3_REGION ?? '').length > 0 && + (process.env.NEXT_PUBLIC_S3_UPLOAD_ACCESS_ID ?? '').length > 0 && + (process.env.NEXT_PUBLIC_S3_UPLOAD_SECRET ?? '').length > 0 && + (process.env.S3_ADMIN_ACCESS_ID ?? '').length > 0 && + (process.env.S3_ADMIN_ACCESS_SECRET ?? '').length > 0; + + +// SETTINGS + export const PRO_MODE_ENABLED = process.env.NEXT_PUBLIC_PRO_MODE === '1'; export const PUBLIC_API_ENABLED = process.env.NEXT_PUBLIC_PUBLIC_API === '1'; export const SHOW_REPO_LINK = process.env.NEXT_PUBLIC_HIDE_REPO_LINK !== '1'; @@ -38,7 +54,7 @@ export const OG_TEXT_BOTTOM_ALIGNMENT = export const CONFIG_CHECKLIST_STATUS = { hasPostgres: (process.env.POSTGRES_HOST ?? '').length > 0, - hasBlob: (process.env.BLOB_READ_WRITE_TOKEN ?? '').length > 0, + hasBlob: hasVercelBlob || hasAwsS3Storage, hasAuth: (process.env.AUTH_SECRET ?? '').length > 0, hasAdminUser: ( (process.env.ADMIN_EMAIL ?? '').length > 0 &&