Bitwarden Secret Sync with Prefix Logic & Notifications (Homelab)

1. The Strategy: "The Prefix Bridge"

To use one Bitwarden project for all your Docker stacks, we use folder-based prefixes.

  • Bitwarden Key Format: STACKNAME_VARIABLE (e.g., PAPRA_AUTH_SECRET)

  • Local Result: The script strips PAPRA_ and writes AUTH_SECRET=value to /opt/stacks/papra/stack.env.


 

2. The Final Script

File: /root/sync-secrets.sh (Make sure to chmod +x /root/sync-secrets.sh)

Bash

#!/bin/bash

# Load environment (Token + Notify command)

. $HOME/.bashrc


# --- CONFIGURATION ---

STACKS_ROOT="/opt/stacks"

USER_ID=1000

GROUP_ID=1000

DRY_RUN=false


# 1. Check for Dry-Run flag

if [ "$1" = "-d" ] || [ "$1" = "--dry-run" ]; then

    DRY_RUN=true

    echo "--- 🔍 DRY RUN MODE: No files will be modified ---"

fi


# 2. Global Error Handler

on_error() {

    if [ "$DRY_RUN" = "false" ]; then

        local exit_code=$?

        echo "❌ Bitwarden Sync Failed on $(hostname). Exit Code: $exit_code" | notify "Bitwarden Sync Error"

    fi

}

trap 'on_error' ERR


# 3. Sync Logic

if [ -z "$BWS_ACCESS_TOKEN" ]; then

    echo "Error: BWS_ACCESS_TOKEN not found."

    exit 1

fi


SECRETS_JSON=$(bws secret list)


for dir in "$STACKS_ROOT"/*/; do

    FOLDER_NAME=$(basename "$dir")

    PREFIX=$(echo "$FOLDER_NAME" | tr '[:lower:]' '[:upper:]')

    

    # CHANGED: Now targeting .env instead of stack.env

    TARGET_FILE="${dir}.env"


    MATCHING_SECRETS=$(echo "$SECRETS_JSON" | jq -r --arg P "${PREFIX}_" '.[] | select(.key | startswith($P)) | "\(.key | sub($P; ""))=\(.value)"')


    if [ -n "$MATCHING_SECRETS" ]; then

        if [ "$DRY_RUN" = "true" ]; then

            echo "MATCH FOUND for $FOLDER_NAME (Prefix: ${PREFIX}_)"

            echo "$MATCHING_SECRETS" | sed 's/=.*/=********/'

        else

            echo "Updating $TARGET_FILE..."

            echo "$MATCHING_SECRETS" > "$TARGET_FILE"

            chown $USER_ID:$GROUP_ID "$TARGET_FILE"

            chmod 644 "$TARGET_FILE"

        fi

    fi

done


echo "--- Sync Complete ---


 

 

3. Usage & Testing

How to use the Dry-Run option

Use this to see what secrets the script found without actually changing any files. It is the safest way to verify your Bitwarden prefixes are correct.

Bash

/root/sync-secrets.sh -d

 

How to send a Test Notification

To verify that your notify function and Mailrise/Pushover connection are working correctly:

Bash

echo "This is a test notification from the Bitwarden Sync logic." | notify "Test Notification"


 

 


 

4. Automation (The Cron Job)

This runs the sync every 30 minutes. It logs output to sync.log so you can review history if needed.

  1. Run crontab -e

  2. Add this line:

Bash

*/30 * * * * . $HOME/.bashrc; /bin/bash /root/sync-secrets.sh >> /root/sync.log 2>&1


 

 


 

5. Dockge Integration

To make your Docker containers use these secrets, update your docker-compose.yaml in Dockge:

  1. Add env_file: stack.env under your service.

  2. Map the variables using ${VARIABLE_NAME}.

Example:

YAML

services:

  papra:

    image: ghcr.io/papra-hq/papra:latest

    env_file:

      - stack.env

    environment:

      - AUTH_SECRET=${AUTH_SECRET}


 

 


 

Troubleshooting Tips

  • Permission Denied: Ensure the script is executable with chmod +x /root/sync-secrets.sh.

  • Missing Token: If the cron job fails with "Missing Token," ensure export BWS_ACCESS_TOKEN="..." is at the very bottom of your /root/.bashrc.

  • Prefix Miss: Remember that the folder name must match the Bitwarden prefix exactly (e.g., folder uptime matches secret UPTIME_KEY).