From 04d3409297e0d476761c2d75c44c7cc459313c6c Mon Sep 17 00:00:00 2001 From: jack Date: Sat, 29 Aug 2026 20:49:27 +0100 Subject: [PATCH] S3 Fix --- .env.example | 31 ++++++++++++++++++++----------- server.js | 31 ++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/.env.example b/.env.example index 3771250..cfc6df7 100644 --- a/.env.example +++ b/.env.example @@ -1,20 +1,29 @@ -# Copy to /etc/modelviewer.env on the server (chmod 600, owned by root). +# Copy to .env in this directory (chmod 600). Loaded by dotenv at startup. PORT=3000 # --- Model source ----------------------------------------------------------- -# Set S3_BUCKET to index a bucket. Leave it unset to use the local models/ -# folder, which is what development does. -S3_BUCKET=your-bucket -S3_PREFIX=skins/ -AWS_REGION=eu-west-2 +# The MODEL_S3_* names match the other projects. Plain S3_BUCKET / S3_PREFIX / +# AWS_REGION are accepted too. Leave MODEL_S3_BUCKET unset to read the local +# models/ folder instead, which is what development does. +MODEL_S3_BUCKET="static.southwest-roleplay.com" +MODEL_S3_REGION="eu-north-1" +MODEL_S3_KEY_PREFIX="samp/skins" + +# Omit both keys on a box with an instance role or an aws-cli profile; the SDK +# falls back to the default credential chain. +MODEL_S3_ACCESS_KEY_ID="" +MODEL_S3_SECRET_ACCESS_KEY="" # --- Where the browser fetches model files from ------------------------------ -# Path A: leave unset. Files are requested from /models on this origin and -# nginx proxies that to S3/CloudFront. No CORS needed. -# Path B: set to a CDN origin so the browser fetches S3 directly. Requires a -# CORS rule on the bucket. -# MODELS_BASE_URL=https://cdn.southwest-roleplay.dev/skins +# The bucket is already public at static.southwest-roleplay.com, so point the +# viewer straight at it: the browser talks to the CDN and this server never +# serves model bytes. Requires the CORS rule in deploy/bucket-cors.json. +MODELS_BASE_URL="https://static.southwest-roleplay.com/samp/skins" + +# Leave MODELS_BASE_URL unset instead to serve files from /models on this +# origin, with nginx proxying to S3. No CORS needed, but the bytes go through +# your box. See the commented block in deploy/nginx.conf. # How often to re-list the bucket, in ms. Default 15 minutes. # INDEX_REFRESH_MS=900000 diff --git a/server.js b/server.js index b4e046b..91fd887 100644 --- a/server.js +++ b/server.js @@ -9,8 +9,14 @@ const PORT = process.env.PORT || 3000; // Where the model files actually live. Set S3_BUCKET to index a bucket; // otherwise the local models/ folder is used, which is what development does. -const S3_BUCKET = process.env.S3_BUCKET || ''; -const S3_PREFIX = normalisePrefix(process.env.S3_PREFIX || 'skins/'); +// MODEL_S3_* names match the other projects; the plain names are accepted too. +const S3_BUCKET = process.env.MODEL_S3_BUCKET || process.env.S3_BUCKET || ''; +const S3_PREFIX = normalisePrefix( + process.env.MODEL_S3_KEY_PREFIX || process.env.S3_PREFIX || 'skins/' +); +const S3_REGION = process.env.MODEL_S3_REGION || process.env.AWS_REGION; +const S3_ACCESS_KEY = process.env.MODEL_S3_ACCESS_KEY_ID || ''; +const S3_SECRET_KEY = process.env.MODEL_S3_SECRET_ACCESS_KEY || ''; const MODEL_ROOT = process.env.MODEL_ROOT || path.join(__dirname, 'models'); // Where the browser fetches model files from. The default keeps them on this @@ -46,10 +52,25 @@ function buildIndex(keys, prefix) { return out; } -async function listBucketKeys() { +let s3Client = null; + +function getS3Client() { + if (s3Client) return s3Client; // Required lazily so local development needs no AWS dependency installed. - const { S3Client, ListObjectsV2Command } = require('@aws-sdk/client-s3'); - const client = new S3Client({ region: process.env.AWS_REGION }); + const { S3Client } = require('@aws-sdk/client-s3'); + // Explicit credentials only when given; otherwise fall back to the default + // chain, which picks up an EC2 instance role or ~/.aws/credentials. + const credentials = + S3_ACCESS_KEY && S3_SECRET_KEY + ? { accessKeyId: S3_ACCESS_KEY, secretAccessKey: S3_SECRET_KEY } + : undefined; + s3Client = new S3Client({ region: S3_REGION, credentials }); + return s3Client; +} + +async function listBucketKeys() { + const { ListObjectsV2Command } = require('@aws-sdk/client-s3'); + const client = getS3Client(); const keys = []; let token;