Skip to content

Commit

Permalink
🐝
Browse files Browse the repository at this point in the history
  • Loading branch information
webees committed Feb 17, 2024
0 parents commit 2e869d4
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 0 deletions.
75 changes: 75 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Your domain name without protocol
# If you don't have your own domain (highly recommended)
# comment this out for first deployment, add your fly.dev domain here
# then reset your secrets and redeploy your app (untested)
DOMAIN_NAME=domain.name.com

###################
# E-mail settings #
###################

# the e-mail address used to send e-mails from both vaultwarden and restic
SMTP_FROM=[email protected]

# the e-mail address to notify on case of restic backup failure
SMTP_TO=[email protected]

# https://github.com/dani-garcia/vaultwarden/wiki/SMTP-Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=[email protected]
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


########################
# Vaultwarden settings #
########################

# You can read more about vaultwarden environment variables here
# https://github.com/dani-garcia/vaultwarden/wiki/Configuration-overview#configuration-options

# Check https://github.com/dani-garcia/vaultwarden/wiki/Configuration-overview#setting-the-domain-url
# If you don't have your own domain (highly recommended)
# comment this out for first deployment, add your fly.dev domain here
# then reset your secrets and redeploy your app (untested)
DOMAIN=https://{$DOMAIN_NAME}

# Check https://github.com/dani-garcia/vaultwarden/wiki/Disable-registration-of-new-users
SIGNUPS_ALLOWED=false

# Check https://github.com/dani-garcia/vaultwarden/wiki/Disable-registration-of-new-users#restricting-registrations-to-certain-email-domains
# SIGNUPS_DOMAINS_WHITELIST=example.com

# Check https://github.com/dani-garcia/vaultwarden/wiki/Disable-registration-of-new-users#restricting-registrations-to-certain-email-domains
# SIGNUPS_VERIFY=true

# Check https://github.com/dani-garcia/vaultwarden/wiki/Disable-invitations
# INVITATIONS_ALLOWED=false

# This is commented by default, because I strongly advise setting this only when needed
# Make sure you read the link below to understand the consequences and to secure the token
# https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page
# ADMIN_TOKEN=secure-token

# Check https://github.com/dani-garcia/vaultwarden/blob/e7f083dee9743bfe4937f5c8149fa9d8383edb96/.env.template#L261-L267
ORG_CREATION_USERS=[email protected]

# Check https://github.com/dani-garcia/vaultwarden/wiki/Hardening-Guide#disable-password-hint-display
SHOW_PASSWORD_HINT=false

# Check https://github.com/dani-garcia/vaultwarden/wiki/Enabling-WebSocket-notifications
# You don't need to do any additional configuration, as the template
# already uses Caddy to configure the websocket proxy
WEBSOCKET_ENABLED=true
55 changes: 55 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Docker

on:
workflow_dispatch: {}
schedule:
- cron: '25 2 * * *'
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@v4

- 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 }}
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
FROM vaultwarden/server:1.30.3-alpine

WORKDIR /

ARG SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 \
OVERMIND_URL=https://github.com/DarthSim/overmind/releases/download/v2.4.0/overmind-v2.4.0-linux-amd64.gz

ENV OVERMIND_CAN_DIE=setup-msmtp \
ROCKET_PORT=8080

COPY config/crontab \
config/Procfile \
config/Caddyfile \
scripts/restic-backup.sh \
scripts/setup-msmtp.sh \
./

RUN apk add --no-cache \
curl \
caddy \
restic \
ca-certificates \
openssl \
tzdata \
iptables \
ip6tables \
iputils-ping \
tmux \
sqlite \
msmtp && \
curl -fsSL "$SUPERCRONIC_URL" -o /usr/local/bin/supercronic && \
curl -fsSL "$OVERMIND_URL" | gunzip -c - > /usr/local/bin/overmind && \
ln -sf /usr/bin/msmtp /usr/bin/sendmail && \
ln -sf /usr/bin/msmtp /usr/sbin/sendmail && \
chmod +x /usr/local/bin/supercronic && \
chmod +x /usr/local/bin/overmind && \
chmod +x restic-backup.sh && \
chmod +x setup-msmtp.sh

CMD ["overmind", "start"]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```
fly auth login
fly apps create vaultwarden
cat .env | fly secrets import
fly volumes create app_data --size 1
fly deploy
fly ssh console
```
46 changes: 46 additions & 0 deletions config/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
# HTTPS/TLS is handled by Fly or on your domain (eg: Cloudflare)
auto_https off
admin off
persist_config off

log {
output stdout
format json
}
}

{$DOMAIN_NAME}:80 {
encode gzip

header / {
# Enable HTTP Strict Transport Security (HSTS)
Strict-Transport-Security "max-age=31536000;"
# Enable cross-site filter (XSS) and tell browser to block detected attacks
X-XSS-Protection "1; mode=block"
# Disallow the site to be rendered within a frame (clickjacking protection)
X-Frame-Options "DENY"
# Prevent search engines from indexing
X-Robots-Tag "noindex, nofollow"
# Disallow sniffing of X-Content-Type-Options
X-Content-Type-Options "nosniff"
# Server name removing
-Server
# Remove X-Powered-By though this shouldn't be an issue, better opsec to remove
-X-Powered-By
# Remove Last-Modified because etag is the same and is as effective
-Last-Modified
}

# The negotiation endpoint is also proxied to Rocket
reverse_proxy /notifications/hub/negotiate localhost:8080

# Notifications redirected to the websockets server
reverse_proxy /notifications/hub localhost:3012

# Proxy everything else to Rocket
reverse_proxy localhost:8080 {
# Send the true remote IP to Rocket, so that vaultwarden can put this in the log
header_up X-Real-IP {remote_host}
}
}
4 changes: 4 additions & 0 deletions config/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
vaultwarden: /start.sh
caddy: caddy run --config /Caddyfile
restic-backup: supercronic /crontab
setup-msmtp: /setup-msmtp.sh
2 changes: 2 additions & 0 deletions config/crontab
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@hourly /restic-backup.sh
@hourly /usr/bin/find /var/log/restic/ -name "*.log" -type f -mmin +600 -exec rm -f {} \;
26 changes: 26 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
app = "vaultwarden"
primary_region = "hkg"
kill_signal = "SIGINT"
kill_timeout = 5

[build]
image = "ghcr.io/webees/vaultwarden"

[mounts]
source = "app_data"
destination = "/data"

[http_service]
internal_port = 80
force_https = true
min_machines_running = 1

[checks]
[checks.health]
grace_period = "30s"
interval = "15s"
method = "get"
path = "/alive"
port = 80
timeout = "10s"
type = "http"
96 changes: 96 additions & 0 deletions scripts/restic-backup.sh
Original file line number Diff line number Diff line change
@@ -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 /data/db.sqlite3 '.backup /data/backup.bak'" "SQLite backup failed"
ok

running "restic backup"
notify_and_exit_on_error "restic backup --verbose --exclude='db.*' /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
23 changes: 23 additions & 0 deletions scripts/setup-msmtp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh

SMTP_HOST=${SMTP_HOST:-smtp.gmail.com}
SMTP_PORT=${SMTP_PORT:-587}
SMTP_USERNAME=${SMTP_USERNAME:-88888888@gmail.com}
SMTP_PASSWORD=${SMTP_PASSWORD:-88888888}
SMTP_FROM=${SMTP_FROM:-88888888@gmail.com}
SMTP_TO=${SMTP_TO:-88888888@gmail.com}

cat << EOF > /etc/msmtprc
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log
account default
host $SMTP_HOST
port $SMTP_PORT
from $SMTP_FROM
user $SMTP_USERNAME
password $SMTP_PASSWORD
EOF

0 comments on commit 2e869d4

Please sign in to comment.