vaultwarden-install.sh 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env bash
  2. YW=$(echo "\033[33m")
  3. RD=$(echo "\033[01;31m")
  4. BL=$(echo "\033[36m")
  5. GN=$(echo "\033[1;92m")
  6. CL=$(echo "\033[m")
  7. RETRY_NUM=10
  8. RETRY_EVERY=3
  9. NUM=$RETRY_NUM
  10. CM="${GN}✓${CL}"
  11. CROSS="${RD}✗${CL}"
  12. BFR="\\r\\033[K"
  13. HOLD="-"
  14. set -o errexit
  15. set -o errtrace
  16. set -o nounset
  17. set -o pipefail
  18. shopt -s expand_aliases
  19. alias die='EXIT=$? LINE=$LINENO error_exit'
  20. trap die ERR
  21. function error_exit() {
  22. trap - ERR
  23. local reason="Unknown failure occurred."
  24. local msg="${1:-$reason}"
  25. local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE"
  26. echo -e "$flag $msg" 1>&2
  27. exit $EXIT
  28. }
  29. function msg_info() {
  30. local msg="$1"
  31. echo -ne " ${HOLD} ${YW}${msg}..."
  32. }
  33. function msg_ok() {
  34. local msg="$1"
  35. echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
  36. }
  37. function msg_error() {
  38. local msg="$1"
  39. echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
  40. }
  41. msg_info "Setting up Container OS "
  42. sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
  43. locale-gen >/dev/null
  44. while [ "$(hostname -I)" = "" ]; do
  45. echo 1>&2 -en "${CROSS}${RD} No Network! "
  46. sleep $RETRY_EVERY
  47. ((NUM--))
  48. if [ $NUM -eq 0 ]; then
  49. echo 1>&2 -e "${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
  50. exit 1
  51. fi
  52. done
  53. msg_ok "Set up Container OS"
  54. msg_ok "Network Connected: ${BL}$(hostname -I)"
  55. set +e
  56. alias die=''
  57. if nc -zw1 8.8.8.8 443; then msg_ok "Internet Connected"; else
  58. msg_error "Internet NOT Connected"
  59. read -r -p "Would you like to continue anyway? <y/N> " prompt
  60. if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]; then
  61. echo -e " ⚠️ ${RD}Expect Issues Without Internet${CL}"
  62. else
  63. echo -e " 🖧 Check Network Settings"
  64. exit 1
  65. fi
  66. fi
  67. RESOLVEDIP=$(nslookup "github.com" | awk -F':' '/^Address: / { matched = 1 } matched { print $2}' | xargs)
  68. if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
  69. alias die='EXIT=$? LINE=$LINENO error_exit'
  70. set -e
  71. msg_info "Updating Container OS"
  72. apt-get update &>/dev/null
  73. apt-get -y upgrade &>/dev/null
  74. msg_ok "Updated Container OS"
  75. msg_info "Installing Dependencies"
  76. apt-get update &>/dev/null
  77. apt-get -qqy install \
  78. git \
  79. build-essential \
  80. pkgconf \
  81. libssl-dev \
  82. libmariadb-dev-compat \
  83. libpq-dev \
  84. curl \
  85. sudo &>/dev/null
  86. msg_ok "Installed Dependencies"
  87. WEBVAULT=$(curl -s https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest |
  88. grep "tag_name" |
  89. awk '{print substr($2, 2, length($2)-3) }')
  90. VAULT=$(curl -s https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest |
  91. grep "tag_name" |
  92. awk '{print substr($2, 2, length($2)-3) }')
  93. msg_info "Installing Rust"
  94. curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal &>/dev/null
  95. echo 'export PATH=~/.cargo/bin:$PATH' >>~/.bashrc &>/dev/null
  96. export PATH=~/.cargo/bin:$PATH &>/dev/null
  97. which rustc &>/dev/null
  98. msg_ok "Installed Rust"
  99. msg_info "Building Vaultwarden ${VAULT} (Patience)"
  100. git clone https://github.com/dani-garcia/vaultwarden &>/dev/null
  101. cd vaultwarden
  102. cargo build --features "sqlite,mysql,postgresql" --release &>/dev/null
  103. msg_ok "Built Vaultwarden ${VAULT}"
  104. addgroup --system vaultwarden &>/dev/null
  105. adduser --system --home /opt/vaultwarden --shell /usr/sbin/nologin --no-create-home --gecos 'vaultwarden' --ingroup vaultwarden --disabled-login --disabled-password vaultwarden &>/dev/null
  106. mkdir -p /opt/vaultwarden/bin
  107. mkdir -p /opt/vaultwarden/data
  108. cp target/release/vaultwarden /opt/vaultwarden/bin/
  109. msg_info "Downloading Web-Vault ${WEBVAULT}"
  110. curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/$WEBVAULT/bw_web_$WEBVAULT.tar.gz &>/dev/null
  111. tar -xzf bw_web_$WEBVAULT.tar.gz -C /opt/vaultwarden/ &>/dev/null
  112. msg_ok "Downloaded Web-Vault ${WEBVAULT}"
  113. cat <<EOF >/opt/vaultwarden/.env
  114. ADMIN_TOKEN=$(openssl rand -base64 48)
  115. ROCKET_ADDRESS=0.0.0.0
  116. DATA_FOLDER=/opt/vaultwarden/data
  117. DATABASE_MAX_CONNS=10
  118. WEB_VAULT_FOLDER=/opt/vaultwarden/web-vault
  119. WEB_VAULT_ENABLED=true
  120. EOF
  121. msg_info "Creating Service"
  122. chown -R vaultwarden:vaultwarden /opt/vaultwarden/
  123. chown root:root /opt/vaultwarden/bin/vaultwarden
  124. chmod +x /opt/vaultwarden/bin/vaultwarden
  125. chown -R root:root /opt/vaultwarden/web-vault/
  126. chmod +r /opt/vaultwarden/.env
  127. service_path="/etc/systemd/system/vaultwarden.service" &>/dev/null
  128. echo "[Unit]
  129. Description=Bitwarden Server (Powered by Vaultwarden)
  130. Documentation=https://github.com/dani-garcia/vaultwarden
  131. After=network.target
  132. [Service]
  133. User=vaultwarden
  134. Group=vaultwarden
  135. EnvironmentFile=-/opt/vaultwarden/.env
  136. ExecStart=/opt/vaultwarden/bin/vaultwarden
  137. LimitNOFILE=65535
  138. LimitNPROC=4096
  139. PrivateTmp=true
  140. PrivateDevices=true
  141. ProtectHome=true
  142. ProtectSystem=strict
  143. DevicePolicy=closed
  144. ProtectControlGroups=yes
  145. ProtectKernelModules=yes
  146. ProtectKernelTunables=yes
  147. RestrictNamespaces=yes
  148. RestrictRealtime=yes
  149. MemoryDenyWriteExecute=yes
  150. LockPersonality=yes
  151. WorkingDirectory=/opt/vaultwarden
  152. ReadWriteDirectories=/opt/vaultwarden/data
  153. AmbientCapabilities=CAP_NET_BIND_SERVICE
  154. [Install]
  155. WantedBy=multi-user.target" >$service_path
  156. systemctl daemon-reload
  157. systemctl enable --now vaultwarden.service &>/dev/null
  158. msg_ok "Created Service"
  159. PASS=$(grep -w "root" /etc/shadow | cut -b6)
  160. if [[ $PASS != $ ]]; then
  161. msg_info "Customizing Container"
  162. rm /etc/motd
  163. rm /etc/update-motd.d/10-uname
  164. touch ~/.hushlogin
  165. GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
  166. mkdir -p $(dirname $GETTY_OVERRIDE)
  167. cat <<EOF >$GETTY_OVERRIDE
  168. [Service]
  169. ExecStart=
  170. ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
  171. EOF
  172. systemctl daemon-reload
  173. systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
  174. msg_ok "Customized Container"
  175. fi
  176. if [[ "${SSH_ROOT}" == "yes" ]]; then
  177. sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
  178. systemctl restart sshd
  179. fi
  180. msg_info "Cleaning up"
  181. apt-get autoremove >/dev/null
  182. apt-get autoclean >/dev/null
  183. msg_ok "Cleaned"