From 2f344ac7c05360b0a2f58efd7060fb85489ccd4f Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Mon, 11 May 2026 18:26:26 -0400 Subject: [PATCH] Add nightly S3 backups with Glacier lifecycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S3 bucket for Forgejo dumps (Standard 30d → Glacier, expire 365d). Cron runs forgejo dump at 5 AM UTC and uploads to S3. --- lib/forgejo-stack.ts | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/forgejo-stack.ts b/lib/forgejo-stack.ts index 33385d6..3996c1f 100644 --- a/lib/forgejo-stack.ts +++ b/lib/forgejo-stack.ts @@ -1,6 +1,7 @@ import * as cdk from "aws-cdk-lib"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as iam from "aws-cdk-lib/aws-iam"; +import * as s3 from "aws-cdk-lib/aws-s3"; import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; import * as elbv2_targets from "aws-cdk-lib/aws-elasticloadbalancingv2-targets"; import * as route53 from "aws-cdk-lib/aws-route53"; @@ -51,13 +52,29 @@ export class ForgejoStack extends cdk.Stack { ], }); + const backupBucket = new s3.Bucket(this, "BackupBucket", { + bucketName: "forgejo-backups-328440206208", + encryption: s3.BucketEncryption.S3_MANAGED, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + lifecycleRules: [{ + transitions: [ + { storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(30) }, + ], + expiration: cdk.Duration.days(365), + }], + removalPolicy: cdk.RemovalPolicy.RETAIN, + }); + + backupBucket.grantReadWrite(role); + const userData = ec2.UserData.forLinux(); userData.addCommands( "set -euxo pipefail", "", `FORGEJO_VERSION="${FORGEJO_VERSION}"`, "", - "dnf install -y git", + "dnf install -y git cronie", + "systemctl enable --now crond", "", "useradd --system --shell /bin/bash --home-dir /home/forgejo --create-home forgejo", "", @@ -128,6 +145,22 @@ export class ForgejoStack extends cdk.Stack { "", "systemctl daemon-reload", "systemctl enable --now forgejo", + "", + "cat > /usr/local/bin/forgejo-backup.sh << 'BAKEOF'", + "#!/bin/bash", + "set -euo pipefail", + "TIMESTAMP=$(date +%Y-%m-%d)", + "DUMP_DIR=$(mktemp -d)", + "chown forgejo:forgejo \"$DUMP_DIR\"", + "cd \"$DUMP_DIR\"", + "sudo -u forgejo /usr/local/bin/forgejo dump --config /etc/forgejo/app.ini --type tar.gz --file \"$DUMP_DIR/forgejo-${TIMESTAMP}.tar.gz\"", + "aws s3 cp \"$DUMP_DIR/forgejo-${TIMESTAMP}.tar.gz\" s3://forgejo-backups-328440206208/${TIMESTAMP}/forgejo-${TIMESTAMP}.tar.gz", + "rm -rf \"$DUMP_DIR\"", + "BAKEOF", + "chmod +x /usr/local/bin/forgejo-backup.sh", + "", + "echo '0 5 * * * root /usr/local/bin/forgejo-backup.sh >> /var/log/forgejo-backup.log 2>&1' > /etc/cron.d/forgejo-backup", + "chmod 644 /etc/cron.d/forgejo-backup", ); const instance = new ec2.Instance(this, "Instance", {