Go to Properties tab of bucket and turn on server web hosting set both index and error to index.html
You need index.html in EACH subfolder and path requests will route to that index.html
You will get a http url
To setup https, you use Cloudfront look at Cloudfront.md
? You might be able to just use cloudfront and skip step 2?
Extra: Look at codebuild.md to get a built react app or github updates into the S3, use the AWS cli to get the artifact in the root
Advanced
MultiPart Upload
Can upload a file part by part and even in parallel, then it will be constructed when you signal completion
import AWS from"aws-sdk";import bytes from"bytes";constdebug=require("debug")("app:Folder:AWSUploader");constREGION="us-west-2";constPOOL_ID="us-west-2:banabnbanabnbanbfnabnabnabnabna";constBUCKET_NAME="sigma-direct";exportdefaultclassAWSUploader {constructor(filename, type) {this.bucketName =BUCKET_NAME; //audio file storethis.etag = []; // etag is used to save the parts of the single upload filethis.partNumber =0; // multipart requires incremetal so that they can merge all parts by ascending orderthis.filename = filename; //unique filenamethis.type = type;this.uploadId =""; // upload id is required in multipartthis.uploadPromises = [];this.curBlob =null;AWS.config.region =REGION;AWS.config.credentials =newAWS.CognitoIdentityCredentials({ IdentityPoolId:POOL_ID });this.s3 =newAWS.S3();//make start request now, but don't blockthis.initalizedP =this.startMultiUpload(); }upload(blob) {constprevUploads= [...this.uploadPromises]; //needs to be copy of array in prev stateconstf=async () => {awaitthis.initalizedP; //make sure start request happened, I assume multiple blobs should never be waiting hereawaitPromise.all(prevUploads); //ensure all prevUploads are doneif (this.curBlob ===null) {this.curBlob = blob; } else {this.curBlob =newBlob([this.curBlob, blob], { type:this.type }); }debug("Currently",bytes(this.curBlob.size),"sends at 5mb");if (this.curBlob.size >bytes("5mb")) {constcb=this.curBlob;this.curBlob =null;awaitthis.continueMultiUpload(cb); } };constuploadP=f();this.uploadPromises.push(uploadP);return uploadP; }/* Initiates a multipart upload and returns an upload ID. Upload id is used to upload the other parts of the stream */startMultiUpload() {debug("STARTING MULTIUPLOAD");conststartParams= { Bucket:this.bucketName, Key:this.filename, ContentType:this.type, ACL:"private" };returnnewPromise(async (resolve, reject) => {this.s3.createMultipartUpload(startParams, (err, data) => {if (err) {reject(err); } else {debug("Created", data);this.uploadId =data.UploadId;resolve(data); } }); }); }/* Uploads a part in a multipart upload. The following code uploads part of a multipart upload. it specifies a file name for the part data. The Upload ID is same that is returned by the initiate multipart upload. */continueMultiUpload(blob) {this.partNumber +=1;constcurPartNumber=this.partNumber;constparams= { Body: blob, Bucket:this.bucketName, Key:this.filename, PartNumber: curPartNumber, UploadId:this.uploadId };debug("Continuing upload with", params);returnnewPromise((resolve, reject) => {this.s3.uploadPart(params, (err, data) => {if (err) {reject(err); } // an error occurredelse {/* Once the part of data is uploaded we get an Entity tag for the uploaded object(ETag). which is used later when we complete our multipart upload. */debug("Uploaded part", curPartNumber);this.etag.push({ ETag:data.ETag, PartNumber: curPartNumber });resolve(data); } }); }); }// Completes a multipart upload by assembling previously uploaded parts.asynccompleteMultiUpload() {//wait for all current uploads, then check if any blobs left overawaitPromise.all(this.uploadPromises);debug("Leftover blobs",this.curBlob);if (this.curBlob) {awaitthis.continueMultiUpload(this.curBlob); }debug("Finalizing parts",this.etag);this.etag =this.etag.sort((a, b) =>a.PartNumber -b.PartNumber);constparams= { Bucket:this.bucketName,// required Key:this.filename,// required UploadId:this.uploadId,// required MultipartUpload: { Parts:this.etag } };returnnewPromise((resolve, reject) => {this.s3.completeMultipartUpload(params, (err, data) => {if (err) {reject(err); } else {resolve(data); } }); }); }asyncabortMultiUpload() {//wait for current uploads just to be sureawaitPromise.all(this.uploadPromises);//s3 error if you try to abort an invalid uploadID or an uploadID with no parts uploaded yetif (!this.uploadId ||this.partNumber ===0) {debug("Nothing to abort");return; }debug("Aborting");constparams= { Bucket:this.bucketName,// required Key:this.filename,// required UploadId:this.uploadId // required };returnnewPromise((resolve, reject) => {this.s3.completeMultipartUpload(params, (err, data) => {if (err) {debug("Err had", err);reject(err); } else {debug("Aborted");resolve(data); } }); }); }}
You are charged for incomplete multipart uploads, but you can add a lifecycle policy detailed here