diff --git a/README.md b/README.md index 47a7994..5566976 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,120 @@ -# password-manager +# Password Management Appliance + +**An Open Source Appliance from Robbie Ferguson** + +A hardened, self-hosted password manager appliance based on Vaultwarden. Designed for secure deployment in business or personal environments. + +--- + +## ✅ Features + +- 🛡️ Fully self-hosted on Debian 12 +- 🔐 Vaultwarden (Bitwarden-compatible) +- 💾 MariaDB backend +- 🧠 Supports .env override system via web-based setup +- 🌐 NGINX reverse proxy + PHP-based first-time setup wizard +- 🔑 Multi-user access, browser extensions, mobile app compatibility + +--- + +## 📂 Important File Paths + +| Path | Purpose | +|------|---------| +| `/opt/vaultwarden/.env` | Core Vaultwarden environment settings | +| `/var/lib/vaultwarden/.env.user` | User-defined config written via the setup wizard | +| `/var/lib/vaultwarden/.setup-complete` | Flag file that disables the setup wizard after first-time config | +| `/opt/vaultwarden/.env.merged` | Combined environment used by the wrapper | +| `/usr/local/bin/vaultwarden` | Vaultwarden binary | +| `/usr/local/bin/vaultwarden-wrapper` | Wrapper that merges .env and .env.user | +| `/etc/systemd/system/vaultwarden.service` | Systemd unit to manage Vaultwarden as a service | +| `/var/www/html/setup/` | First-time setup wizard served via PHP | +| `/var/www/html/vaultinfo/index.html` | Installer-complete welcome page served on `/` | + +--- + +## 🚀 Installation + +On a fresh Debian 12 system, clone the password-manager repository and then run: + +```bash +./installer.sh +``` + +After installation: +- Access the appliance at `http:///` +- Go to `/setup` to complete first-time configuration +- After submitting the form, Vaultwarden will use your custom settings + +--- + +## 🧠 Configuration Flow + +1. Installer creates `/opt/vaultwarden/.env` (default config) +2. User config is stored via `/setup` in `/var/lib/vaultwarden/.env.user` +3. `vaultwarden-wrapper` merges both files into `.env.merged` +4. Systemd launches Vaultwarden using the wrapper + +--- + +## 🔁 To Re-run Setup + +To prevent a bad actor from modifying your configuration by re-running the /setup tool, a file `.setup-complete` is created to tell the system to no longer allow the configuration to be saved. You can, if needed, delete the `.setup-complete` file to re-run the configuration: + +```bash +rm /var/lib/vaultwarden/.setup-complete +``` + +Then visit `/setup` in your browser again. + +--- + +## 🖥️ System Requirements + +To successfully build and run the Password Management Appliance, your system must meet the following minimum requirements: + +### Minimum Requirements (suitable for testing and light use) + +* **Operating System**: Debian 12 (Bookworm) x86\_64 +* **CPU**: Dual-core processor (2 vCPUs) +* **RAM**: 4 GB +* **Disk Space**: 5 GB free disk space +* **Network**: Internet access for package installation and updates +* **Privileges**: Root access required to run the installer + +### Recommended Requirements (for smoother experience and production use) + +* **CPU**: Quad-core processor (4 vCPUs) +* **RAM**: 8 GB or more +* **Disk Space**: 10 GB+ free disk space +* **Swap**: At least 2 GB swap space to prevent build crashes +* **Persistent Hostname/IP**: Recommended for SSL setup and accessibility + +> ⚠️ Note: The Vaultwarden build process is **resource-intensive** and may fail on underpowered systems or single-core CPUs. Be sure to allocate enough CPU and RAM, or use the `--purge` option to clean up failed attempts before retrying. + +--- + +### 🔁 `--purge` Option + +If you need to reset your environment to retry installing after a failed installation, run the installer with the `--purge` flag: + +```bash +./installer.sh --purge +``` + +This will: + +* Remove Vaultwarden and its related system user +* Delete configuration files and setup data +* Uninstall MariaDB and clear its databases +* Remove any sudo rules added by the installer + +Use this to clean the system before running a fresh install. **Note:** This does not perform a complete system rollback - only what's necessary to allow a successful reinstallation. + +--- + +## 📜 License + +This project is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). +© Robbie Ferguson – Open Source Appliance Project diff --git a/installer.sh b/installer.sh new file mode 100755 index 0000000..608392a --- /dev/null +++ b/installer.sh @@ -0,0 +1,374 @@ +#!/bin/bash +# +# Password Management Appliance Installer +# An Open Source Appliance from Robbie Ferguson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 + +set -e + +if [[ "$EUID" -ne 0 ]]; then + echo "Please run as root." + exit 1 +fi + +generate_token() { + local length=${1:-64} + head -c $((length / 2)) /dev/urandom | xxd -p | tr -d '\n' +} + +# Save the directory where the script was started +INSTALLER_DIR="$(pwd)" + +echo "=== Password Management Appliance Installer ===" +echo "An Open Source Appliance from Robbie Ferguson" +echo + + +if [[ "$1" == "--purge" ]]; then + echo "PURGE command passed on the command line." + echo + echo "WARNING: This will permanently remove Vaultwarden and all its data." + read -r -p "Are you sure you want to delete everything? [y/N]: " confirm + + # Default to "No" if input is empty or not 'y' or 'Y' + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Purge aborted." + exit 0 + fi + + echo "Purging previous Vaultwarden installation..." + + set +e + echo "Removing MariaDB (server + client + common)..." + systemctl stop mariadb 2>/dev/null + apt purge -y mariadb-server mariadb-client mariadb-common mariadb-backup + apt autoremove -y + rm -rf /var/lib/mysql /etc/mysql + + if id "vaultwarden" &>/dev/null; then + echo "Attempting to stop and remove vaultwarden user..." + + echo "Killing any processes owned by vaultwarden..." + pkill -u vaultwarden 2>/dev/null || true + + echo "Stopping Vaultwarden service if running..." + systemctl stop vaultwarden 2>/dev/null || true + systemctl disable vaultwarden 2>/dev/null || true + rm -f /etc/systemd/system/vaultwarden.service + + echo "Unmounting or clearing home directory if needed..." + umount /opt/vaultwarden 2>/dev/null || true + rm -rf /opt/vaultwarden /var/lib/vaultwarden + + rm -f /usr/local/bin/vaultwarden-wrapper + + echo "Deleting vaultwarden user..." + userdel vaultwarden && echo "vaultwarden user removed." || echo "Failed to remove vaultwarden user." + else + echo "vaultwarden user does not exist. Skipping." + fi + + echo "Purging the vaultgroup gruop" + groupdel vaultgroup + getent group vaultgroup + + echo "Cleaning www-data writable config and setup..." + rm -f /var/lib/vaultwarden/.env.user + rm -f /var/lib/vaultwarden/.setup-complete + rm -rf /var/www/html/setup/ + + echo "Removing sudoers config for www-data..." + rm -f /etc/sudoers.d/vaultwarden-www-restart + + echo "Purge complete. You can now re-run installer.sh safely." + exit 0 +fi + + +# Update system and install dependencies +echo "Installing dependencies..." +apt update && apt upgrade -y +apt install -y curl gnupg2 software-properties-common apt-transport-https lsb-release mariadb-server mariadb-client nginx unzip ufw git build-essential pkg-config libssl-dev libmariadb-dev libmariadb-dev-compat sudo xxd + +ufw allow OpenSSH +ufw allow 'Nginx Full' +ufw --force enable + +DB_NAME="vaultwarden" +DB_USER="vaultuser" +#DB_PASS=$(openssl rand -base64 24) +DB_PASS=$(generate_token 64) + +echo "Creating MariaDB database and user..." +mysql -u root </dev/null 2>&1 || { + echo "ERROR: Cannot verify MariaDB access." + exit 1 +} +echo "MariaDB credentials verified." + +echo "Installing Rust and Vaultwarden..." +curl https://sh.rustup.rs -sSf | sh -s -- -y +export PATH="$HOME/.cargo/bin:$PATH" + +useradd -r -d /opt/vaultwarden -s /usr/sbin/nologin vaultwarden || true +mkdir -p /opt/vaultwarden +chown vaultwarden:vaultwarden /opt/vaultwarden + +cd /opt +git clone https://github.com/dani-garcia/vaultwarden.git +cd vaultwarden + +echo "Building Vaultwarden with MySQL support..." +if ! cargo build --release --locked --features mysql; then + echo "Cargo build failed." + exit 1 +fi + +echo "Verifying that Vaultwarden binary was built..." +if [[ ! -x target/release/vaultwarden ]]; then + echo "Vaultwarden binary not found after build." + exit 1 +fi + +echo "Checking for MySQL support in the built binary..." +if ldd target/release/vaultwarden | grep -qE 'libmysqlclient|libmariadb'; then + echo "Vaultwarden binary is linked with MySQL/MariaDB support." + if [[ -e /usr/local/bin/vaultwarden ]]; then + rm -f /usr/local/bin/vaultwarden + fi + echo "Placing binary in /usr/local/bin" + cp target/release/vaultwarden /usr/local/bin/ + chown vaultwarden:vaultwarden /usr/local/bin/vaultwarden +else + echo "Built Vaultwarden binary does not link MySQL/MariaDB. Something went wrong." + exit 1 +fi + +# Ensure vaultwarden data directory exists +if [ ! -d /var/lib/vaultwarden ]; then + echo "Creating /var/lib/vaultwarden directory..." + mkdir -p /var/lib/vaultwarden + chown www-data:www-data /var/lib/vaultwarden +fi + +# Ensure .env.user file exists +if [ ! -f /var/lib/vaultwarden/.env.user ]; then + echo "Creating .env.user file..." + touch /var/lib/vaultwarden/.env.user + chown www-data:www-data /var/lib/vaultwarden/.env.user +fi + +mkdir -p /opt/vaultwarden/data +chown -R vaultwarden:vaultwarden /opt/vaultwarden + +cat < /opt/vaultwarden/.env +DATABASE_URL=mysql://${DB_USER}:${DB_PASS}@localhost:3306/${DB_NAME} +DATA_FOLDER=/opt/vaultwarden/data +DOMAIN=https://localhost +ROCKET_PORT=8080 +ROCKET_ADDRESS=0.0.0.0 +WEBSOCKET_ENABLED=true +WEB_VAULT_FOLDER=/opt/vaultwarden/web-vault +EOF + +chown vaultwarden:vaultwarden /opt/vaultwarden/.env +chmod 600 /opt/vaultwarden/.env + +# Create vaultwarden-wrapper to support layered .env config +cat <<"EOF" > /usr/local/bin/vaultwarden-wrapper +#!/bin/bash +ENV_MAIN="/opt/vaultwarden/.env" +ENV_USER="/var/lib/vaultwarden/.env.user" +ENV_MERGED="/opt/vaultwarden/.env.merged" + +cat "$ENV_MAIN" > "$ENV_MERGED" +[ -f "$ENV_USER" ] && cat "$ENV_USER" >> "$ENV_MERGED" + +# Load environment variables from merged file +set -a +source "$ENV_MERGED" +set +a + +exec /usr/local/bin/vaultwarden +EOF + +chmod +x /usr/local/bin/vaultwarden-wrapper + +cat < /etc/systemd/system/vaultwarden.service +[Unit] +Description=Vaultwarden Password Server +After=network.target mariadb.service + +[Service] +User=vaultwarden +Group=vaultwarden +WorkingDirectory=/opt/vaultwarden +ExecStart=/usr/local/bin/vaultwarden-wrapper +Restart=always +RestartSec=5s + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reexec +systemctl enable --now vaultwarden + +echo "Checking Vaultwarden service..." +systemctl is-active --quiet vaultwarden || { + echo "Vaultwarden service failed to start." + journalctl -u vaultwarden --no-pager | tail -n 10 + exit 1 +} +echo "Vaultwarden service is active." + +# Remove default nginx site if it exists to avoid duplicate default_server errors +if [ -f /etc/nginx/sites-enabled/default ]; then + echo "Removing default Nginx site to avoid conflict..." + rm -f /etc/nginx/sites-enabled/default +fi + +# Basic NGINX placeholder config +cat <<"EOF" > /etc/nginx/sites-available/vaultwarden +server { + listen 80 default_server; + server_name _; + + root /var/www/html/vaultinfo; + index index.php; + + # Main landing page + location / { + try_files $uri $uri/ /index.php?$args; + } + + # Serve PHP files + location ~ \.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/run/php/php8.2-fpm.sock; + } + + # Setup interface + location /setup { + root /var/www/html; + index index.php; + + location ~ ^/setup/.*\.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/run/php/php8.2-fpm.sock; + } + } + + # Vaultwarden Admin Panel + location ^~ /admin/ { + proxy_pass http://127.0.0.1:8080/admin/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Vaultwarden static files (referenced from root!) + location ~ ^/(bootstrap|admin|vaultwarden|.*\.(css|js|png|ico|woff2?)$) { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + + # WebSocket + location /notifications/hub { + proxy_pass http://127.0.0.1:3012; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} +EOF + +ln -sf /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/vaultwarden + +echo "Testing Nginx configuration..." +if nginx -t; then + echo "Reloading Nginx..." + systemctl reload nginx +else + echo "Nginx config test failed. Please check manually." +fi + + +mkdir -p /var/www/html/vaultinfo +chown -R www-data:www-data /var/www/html/vaultinfo + +# Setup a group that allows Vaultwarden and www-data to share configs +groupadd vaultgroup +usermod -aG vaultgroup vaultwarden +usermod -aG vaultgroup www-data + +# Allow web interface to save initial config +touch /var/lib/vaultwarden/.env.user +chown www-data:vaultgroup /var/lib/vaultwarden/.env.user +chmod 640 /var/lib/vaultwarden/.env.user + +# Download and deploy setup wizard +echo "Installing PHP and deploying setup page..." +apt install -y php php-fpm php-cli php-common php-mbstring php-json php-curl php-xml php-zip php-gd +cd "$INSTALLER_DIR" +cp -R ./setup /var/www/html/ +chown -R www-data:www-data /var/www/html/setup + +# Welcome page with /setup condition check +cat <<"EOF" > /var/www/html/vaultinfo/index.php + + + + + Password Management Appliance + + + +

Password Management Appliance

+

This server is running Vaultwarden on a Password Management Appliance.

+

✓ Installation Complete

+

+ Access the admin panel at: /admin

'; } else { echo '

Continue to activation.

'; } ?> +

An Open Source Appliance from Robbie Ferguson

+ + +EOF + +echo "Setup system ready. Visit http:///setup to begin configuration." + +# Allow www-data to restart Vaultwarden without password +echo "www-data ALL=NOPASSWD: /bin/systemctl restart vaultwarden" > /etc/sudoers.d/vaultwarden-www-restart +chmod 440 /etc/sudoers.d/vaultwarden-www-restart + +echo "Configuring default web-vault." +cd /opt/vaultwarden +curl -L https://github.com/dani-garcia/bw_web_builds/releases/download/v2025.6.0/bw_web_v2025.6.0.tar.gz | tar xz +chown -R vaultwarden:vaultwarden web-vault +chmod -R 755 web-vault +systemctl restart vaultwarden + +echo +echo "Installation complete!" +echo "Visit http:///setup to begin configuration." + diff --git a/setup/index.php b/setup/index.php new file mode 100644 index 0000000..1ec9a60 --- /dev/null +++ b/setup/index.php @@ -0,0 +1,54 @@ + + + + + + Vaultwarden Setup Complete + + + +
+

Vaultwarden Setup Complete

+ +

Your admin token has been generated and securely hashed. Please copy and store this token:

+

+

To access the Vaultwarden admin interface, click below:

+

Open Admin Panel

+

Note: If you ever need to reset this setup, delete /opt/vaultwarden/.setup-complete and reload this page.

+ +

Error: Unable to generate or save the admin token. Please check permissions or disk space.

+ +
+ +