From da984edc2d3186bb12ef79504256b8d0bee68a7a Mon Sep 17 00:00:00 2001 From: webees <5155291+webees@users.noreply.github.com> Date: Fri, 16 Feb 2024 15:52:32 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 27 ++++++++++ .github/workflows/publish.yaml | 54 +++++++++++++++++++ Dockerfile | 35 +++++++++++++ README.md | 7 +++ config/Procfile | 2 + config/crontab | 2 + fly.toml | 16 ++++++ scripts/msmtp.sh | 14 +++++ scripts/restic.sh | 96 ++++++++++++++++++++++++++++++++++ 9 files changed, 253 insertions(+) create mode 100644 .env create mode 100644 .github/workflows/publish.yaml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 config/Procfile create mode 100644 config/crontab create mode 100644 fly.toml create mode 100644 scripts/msmtp.sh create mode 100644 scripts/restic.sh diff --git a/.env b/.env new file mode 100644 index 0000000..b97da0a --- /dev/null +++ b/.env @@ -0,0 +1,27 @@ +################### +# E-mail settings # +################### + +# the e-mail address used to send e-mails from both vaultwarden and restic +SMTP_FROM=from@mail.com + +# the e-mail address to notify on case of restic backup failure +SMTP_TO=to@mail.com + +# https://github.com/dani-garcia/vaultwarden/wiki/SMTP-Configuration +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=88888888@gmail.com +SMTP_PASSWORD=88888888 + +################### +# Restic settings # +################### + +# You don't need to initialize this repo beforehand +RESTIC_REPOSITORY=s3://88888888.r2.cloudflarestorage.com/uptime-kuma +RESTIC_PASSWORD=88888888 + +# If using S3 (or B2, wasabi, Minio) you'll need those +AWS_ACCESS_KEY_ID=88888888 +AWS_SECRET_ACCESS_KEY=88888888 \ No newline at end of file diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..0ef39da --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,54 @@ +name: Docker + +on: + schedule: + - cron: '43 7 * * *' + push: + branches: [ "main" ] + tags: [ '*' ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw, value=latest, enable={{is_default_branch}} + type=semver, pattern={{version}} + type=ref, event=branch + type=ref, event=tag + type=ref, event=pr + + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..05bc8fa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM louislam/uptime-kuma:1-alpine + +ARG SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 +ARG OVERMIND_URL=https://github.com/DarthSim/overmind/releases/download/v2.4.0/overmind-v2.4.0-linux-amd64.gz + +RUN apk add --no-cache \ + ca-certificates \ + curl \ + openssl \ + tzdata \ + iptables \ + ip6tables \ + tmux \ + sqlite \ + restic \ + msmtp \ + mailx + + +RUN wget "$SUPERCRONIC_URL" -O /usr/local/bin/supercronic && chmod +x /usr/local/bin/supercronic +RUN wget "$OVERMIND_URL" -O- | gunzip -c - > /usr/local/bin/overmind && chmod +x /usr/local/bin/overmind + +WORKDIR /app + +COPY config/crontab . +COPY config/Procfile . +COPY scripts/restic.sh . +COPY scripts/msmtp.sh . + +RUN chmod +x restic.sh +RUN chmod +x msmtp.sh + +EXPOSE 3001 + +CMD ["overmind", "start"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b3302ae --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +``` +fly auth login +fly apps create uptime-kuma +cat .env | fly secrets import +fly volumes create app_data --size 1 +fly deploy +``` \ No newline at end of file diff --git a/config/Procfile b/config/Procfile new file mode 100644 index 0000000..628accf --- /dev/null +++ b/config/Procfile @@ -0,0 +1,2 @@ +uptime-kuma: node /app/server/server.js +msmtp: /app/msmtp.sh diff --git a/config/crontab b/config/crontab new file mode 100644 index 0000000..b9f17d8 --- /dev/null +++ b/config/crontab @@ -0,0 +1,2 @@ +@hourly /app/restic.sh +@hourly /usr/bin/find /var/log/restic/ -name "*.log" -type f -mmin +600 -exec rm -f {} \; \ No newline at end of file diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..fe906fe --- /dev/null +++ b/fly.toml @@ -0,0 +1,16 @@ +app = "uptime-kuma" +primary_region = "hkg" +kill_signal = "SIGINT" +kill_timeout = 5 + +[build] + image = "ghcr.io/webees/uptime-kuma" + +[mounts] + source = "app_data" + destination = "/app/data" + +[http_service] + internal_port = 3001 + force_https = true + min_machines_running = 1 \ No newline at end of file diff --git a/scripts/msmtp.sh b/scripts/msmtp.sh new file mode 100644 index 0000000..c1622f2 --- /dev/null +++ b/scripts/msmtp.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +cat << EOF > /etc/msmtprc +defaults +auth on +tls on +tls_trust_file /etc/ssl/certs/ca-certificates.crt +logfile /var/log/msmtp.log +host $SMTP_HOST +port $SMTP_PORT +from $SMTP_FROM +user $SMTP_USERNAME +password $SMTP_PASSWORD +EOF \ No newline at end of file diff --git a/scripts/restic.sh b/scripts/restic.sh new file mode 100644 index 0000000..bb967c7 --- /dev/null +++ b/scripts/restic.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +# catch the error in case first pipe command fails (but second succeeds) +set -o pipefail +# turn on traces, useful while debugging but commented out by default +# set -o xtrace + +EMAIL_SUBJECT_PREFIX="[Restic]" +LOG="/var/log/restic/$(date +\%Y\%m\%d_\%H\%M\%S).log" + +# create log dir +mkdir -p /var/log/restic/ + +# e-mail notification +function notify() { + sed -e 's/\x1b\[[0-9;]*m//g' "${LOG}" | mail -s "${EMAIL_SUBJECT_PREFIX} ${1}" ${SMTP_TO} +} + +function log() { + "$@" 2>&1 | tee -a "$LOG" +} + +function run_silently() { + "$@" >/dev/null 2>&1 +} + +# ############################################################################### +# colorized echo helpers # +# taken from: https://github.com/atomantic/dotfiles/blob/master/lib_sh/echos.sh # +# ############################################################################### + +ESC_SEQ="\x1b[" +COL_RED=$ESC_SEQ"31;01m" +COL_BLUE=$ESC_SEQ"34;01m" +COL_GREEN=$ESC_SEQ"32;01m" +COL_YELLOW=$ESC_SEQ"33;01m" +COL_RESET=$ESC_SEQ"39;49;00m" + +function ok() { + log echo -e "$COL_GREEN[ok]$COL_RESET $1" +} + +function running() { + log echo -en "$COL_BLUE ⇒ $COL_RESET $1..." +} + +function warn() { + log echo -e "$COL_YELLOW[warning]$COL_RESET $1" +} + +function error() { + log echo -e "$COL_RED[error]$COL_RESET $1" + log echo -e "$2" +} + +function notify_and_exit_on_error() { + output=$(eval $1 2>&1) + + if [ $? -ne 0 ]; then + error "$2" "$output" + notify "$2" + exit 2 + fi +} + +# ############## +# backup steps # +# ############## + +running "checking restic config" + +run_silently restic cat config + +if [ $? -ne 0 ]; then + warn "restic repo either not initialized or erroring out" + running "trying to initialize it" + notify_and_exit_on_error "restic init" "Repo init failed" +fi + +ok + +running "backing up sqlite database" +notify_and_exit_on_error "sqlite3 /app/data/db.sqlite3 '.backup /app/data/backup.bak'" "SQLite backup failed" +ok + +running "restic backup" +notify_and_exit_on_error "restic backup --verbose --exclude='db.*' /app/data" "Restic backup failed" +ok + +running "checking consistency of restic repository" +notify_and_exit_on_error "restic check" "Restic check failed" +ok + +running "removing outdated snapshots" +notify_and_exit_on_error "restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 3 --keep-yearly 3 --prune" "Restic forget failed" +ok