375 lines
11 KiB
Bash
Executable File
375 lines
11 KiB
Bash
Executable File
#!/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 <<EOF
|
|
CREATE DATABASE ${DB_NAME};
|
|
CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
|
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
|
|
FLUSH PRIVILEGES;
|
|
EOF
|
|
|
|
echo "Verifying MariaDB connection..."
|
|
mysql -u "$DB_USER" -p"$DB_PASS" -e "USE $DB_NAME;" >/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 <<EOF > /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 <<EOF > /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
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Password Management Appliance</title>
|
|
<style>
|
|
body { font-family: sans-serif; background: #111; color: #eee; padding: 2rem; text-align: center; }
|
|
h1 { color: #6cf; }
|
|
a { color: #9cf; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Password Management Appliance</h1>
|
|
<p>This server is running <strong>Vaultwarden</strong> on a Password Management Appliance.</p>
|
|
<p>✓ Installation Complete</p>
|
|
<p><?php if (file_exists('/var/lib/vaultwarden/.setup-complete')) { echo '✓ Activated'; } else { echo '✗ Activated'; } ?></p>
|
|
<?php if (file_exists('/var/lib/vaultwarden/.setup-complete')) { echo '<p>Access the admin panel at: <a href="/admin">/admin</a></p>'; } else { echo '<p>Continue to <a href="/setup/">activation</a>.</p>'; } ?>
|
|
<p style="font-size: 0.9em; color: #666;">An Open Source Appliance from Robbie Ferguson</p>
|
|
</body>
|
|
</html>
|
|
EOF
|
|
|
|
echo "Setup system ready. Visit http://<appliance-ip>/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://<your-appliance-ip>/setup to begin configuration."
|
|
|