1
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#!/usr/bin/env bash
2
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
3
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# fossilrepo -- Omnibus Installer
4
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#
5
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Installs fossilrepo on any Linux box. Supports two modes:
6
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# - Docker: full stack via docker compose (recommended)
7
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# - Bare Metal: native install with systemd services
8
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#
9
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Usage:
10
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# curl -sSL https://get.fossilrepo.dev | bash
11
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# -- or --
12
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ./install.sh --docker --domain fossil.example.com --ssl
13
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#
14
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# https://github.com/ConflictHQ/fossilrepo
15
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# MIT License
16
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
17
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
18
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
set -euo pipefail
19
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
20
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ensure HOME is set (SSM/cloud-init may not set it)
21
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export HOME="${HOME:-/root}"
22
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
23
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
24
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 1: Constants + Version Pins
25
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
26
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
27
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly INSTALLER_VERSION="1.0.0"
28
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly FOSSILREPO_VERSION="0.1.0"
29
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
30
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly FOSSIL_VERSION="2.24"
31
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly LITESTREAM_VERSION="0.3.13"
32
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly CADDY_VERSION="2.9"
33
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly PYTHON_VERSION="3.12"
34
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly POSTGRES_VERSION="16"
35
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly REDIS_VERSION="7"
36
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
37
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly REPO_URL="https://github.com/ConflictHQ/fossilrepo.git"
38
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly REPO_SSH_URL="[email protected] :ConflictHQ/fossilrepo.git"
39
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly DEFAULT_PREFIX="/opt/fossilrepo"
40
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
41
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Update check sources (tried in order of preference)
42
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly UPDATE_URL_FOSSILREPO="https://fossilrepo.io/api/version/"
43
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly UPDATE_URL_GITHUB="https://api.github.com/repos/ConflictHQ/fossilrepo/releases/latest"
44
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly UPDATE_URL_PYPI="https://pypi.org/pypi/fossilrepo/json"
45
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly DATA_DIR="/data"
46
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly LOG_DIR="/var/log/fossilrepo"
47
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly CADDY_DOWNLOAD_BASE="https://caddyserver.com/api/download"
48
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
readonly LITESTREAM_DOWNLOAD_BASE="https://github.com/benbjohnson/litestream/releases/download"
49
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
50
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Globals -- set by arg parser, interactive TUI, or defaults
51
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_MODE="" # docker | bare-metal
52
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DOMAIN="localhost"
53
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_SSL="false"
54
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_PREFIX="$DEFAULT_PREFIX"
55
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_PORT="8000"
56
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DB_NAME="fossilrepo"
57
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DB_USER="dbadmin"
58
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DB_PASSWORD=""
59
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_USER="admin"
60
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_EMAIL=""
61
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_PASSWORD=""
62
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_BUCKET=""
63
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_REGION=""
64
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_ENDPOINT=""
65
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_ACCESS_KEY=""
66
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_SECRET_KEY=""
67
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_CONFIG_FILE=""
68
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_YES="false"
69
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_VERBOSE="false"
70
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
71
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Detected at runtime
72
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_ID=""
73
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_VERSION=""
74
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_ARCH=""
75
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER=""
76
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
77
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated secrets
78
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_SECRET_KEY=""
79
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_DB_PASSWORD=""
80
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_ADMIN_PASSWORD=""
81
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
82
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Color codes -- set by _color_init
83
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_RESET=""
84
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_RED=""
85
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_GREEN=""
86
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_YELLOW=""
87
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_BLUE=""
88
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_CYAN=""
89
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_BOLD=""
90
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
91
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
92
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 2: Logging
93
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
94
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
95
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_supports_color() {
96
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Check if stdout is a terminal and TERM is not dumb
97
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -t 1 ]] && [[ "${TERM:-dumb}" != "dumb" ]] && return 0
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Also support NO_COLOR convention
99
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${NO_COLOR:-}" ]] || return 1
100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 1
101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_color_init() {
104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if _supports_color; then
105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_RESET='\033[0m'
106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_RED='\033[0;31m'
107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_GREEN='\033[0;32m'
108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_YELLOW='\033[0;33m'
109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_BLUE='\033[0;34m'
110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_CYAN='\033[0;36m'
111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_C_BOLD='\033[1m'
112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info() { printf "${_C_BLUE}[INFO]${_C_RESET} %s\n" "$*"; }
116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok() { printf "${_C_GREEN}[ OK]${_C_RESET} %s\n" "$*"; }
117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn() { printf "${_C_YELLOW}[WARN]${_C_RESET} %s\n" "$*" >&2; }
118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_error() { printf "${_C_RED}[ ERR]${_C_RESET} %s\n" "$*" >&2; }
119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step() { printf "\n${_C_CYAN}${_C_BOLD}==> %s${_C_RESET}\n" "$*"; }
120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die() {
122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_error "$@"
123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
exit 1
124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose() {
127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$OPT_VERBOSE" == "true" ]] && log_info "$@"
128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 3: Utilities
133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_password() {
136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# 32-char alphanumeric password -- no special chars to avoid escaping issues
137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local length="${1:-32}"
138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command -v openssl &>/dev/null; then
139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c "$length"
140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
elif [[ -r /dev/urandom ]]; then
141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c "$length"
142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
143
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Cannot generate random password: no openssl or /dev/urandom"
144
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
145
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
146
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
147
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_secret_key() {
148
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# 50-char Django secret key
149
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command -v openssl &>/dev/null; then
150
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
openssl rand -base64 72 | tr -dc 'a-zA-Z0-9!@#$%^&*(-_=+)' | head -c 50
151
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
elif [[ -r /dev/urandom ]]; then
152
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tr -dc 'a-zA-Z0-9!@#$%^&*(-_=+)' < /dev/urandom | head -c 50
153
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
154
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Cannot generate secret key: no openssl or /dev/urandom"
155
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
156
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
157
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
158
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists() {
159
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command -v "$1" &>/dev/null
160
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
161
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
162
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
version_gte() {
163
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Returns 0 if $1 >= $2 (dot-separated version comparison)
164
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local IFS=.
165
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local i ver1=($1) ver2=($2)
166
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
for ((i = 0; i < ${#ver2[@]}; i++)); do
167
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local v1="${ver1[i]:-0}"
168
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local v2="${ver2[i]:-0}"
169
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ((v1 > v2)); then return 0; fi
170
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ((v1 < v2)); then return 1; fi
171
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
172
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
173
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
174
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
175
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
require_root() {
176
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ $EUID -ne 0 ]]; then
177
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "This installer must be run as root. Use: sudo ./install.sh"
178
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
179
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
180
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
181
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
confirm() {
182
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_YES" == "true" ]]; then
183
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
184
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
185
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local prompt="${1:-Continue?}"
186
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local reply
187
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_BOLD}%s [y/N] ${_C_RESET}" "$prompt"
188
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -r reply
189
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$reply" in
190
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[yY][eE][sS]|[yY]) return 0 ;;
191
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) die "Aborted by user." ;;
192
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
193
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
194
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
195
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
backup_file() {
196
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local file="$1"
197
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -f "$file" ]]; then
198
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local backup="${file}.bak.$(date +%Y%m%d%H%M%S)"
199
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp "$file" "$backup"
200
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Backed up $file -> $backup"
201
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
202
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
203
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
204
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file() {
205
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Write content to a file, creating parent dirs and backing up existing files.
206
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Usage: write_file <path> <content> [mode]
207
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local path="$1"
208
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local content="$2"
209
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local mode="${3:-0644}"
210
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
211
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p "$(dirname "$path")"
212
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
backup_file "$path"
213
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf '%s\n' "$content" > "$path"
214
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chmod "$mode" "$path"
215
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Wrote $path (mode $mode)"
216
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
217
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
218
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
retry_command() {
219
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Retry a command up to N times with a delay between attempts
220
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local max_attempts="${1:-3}"
221
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local delay="${2:-5}"
222
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
223
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local attempt=1
224
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while [[ $attempt -le $max_attempts ]]; do
225
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if "$@"; then
226
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
227
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
228
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "Command failed (attempt $attempt/$max_attempts): $*"
229
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
((attempt++))
230
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sleep "$delay"
231
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
232
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 1
233
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
234
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
235
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
236
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 4: OS Detection
237
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
238
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
239
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
detect_os() {
240
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Detecting operating system"
241
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
242
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ! -f /etc/os-release ]]; then
243
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Cannot detect OS: /etc/os-release not found. This installer requires a modern Linux distribution."
244
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
245
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
246
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# shellcheck source=/dev/null
247
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
. /etc/os-release
248
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
249
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_ID="${ID:-unknown}"
250
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_VERSION="${VERSION_ID:-0}"
251
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
252
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$OS_ID" in
253
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
debian)
254
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="apt"
255
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
256
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ubuntu)
257
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="apt"
258
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
259
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rhel|centos|rocky|almalinux)
260
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_ID="rhel"
261
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="dnf"
262
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
263
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
amzn)
264
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="dnf"
265
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
266
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fedora)
267
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OS_ID="rhel"
268
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="dnf"
269
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
270
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
alpine)
271
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PKG_MANAGER="apk"
272
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "Alpine Linux detected. Only Docker mode is supported on Alpine."
273
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "bare-metal" ]]; then
274
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Bare metal installation is not supported on Alpine Linux."
275
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
276
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_MODE="docker"
277
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
278
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*)
279
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Unsupported OS: $OS_ID. Supported: debian, ubuntu, rhel/centos/rocky/alma, fedora, amzn, alpine."
280
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
281
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
282
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
283
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Detect architecture
284
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local machine
285
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
machine="$(uname -m)"
286
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$machine" in
287
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
x86_64|amd64) OS_ARCH="amd64" ;;
288
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
aarch64|arm64) OS_ARCH="arm64" ;;
289
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) die "Unsupported architecture: $machine. Supported: amd64, arm64." ;;
290
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
291
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
292
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "OS: $OS_ID $OS_VERSION ($OS_ARCH), package manager: $PKG_MANAGER"
293
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
294
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
295
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
296
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 5: YAML Config Parser
297
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
298
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
299
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
parse_config_file() {
300
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local config_file="$1"
301
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
302
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ! -f "$config_file" ]]; then
303
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Config file not found: $config_file"
304
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
305
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
306
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Loading config from $config_file"
307
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
308
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local current_section=""
309
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local line key value
310
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
311
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while IFS= read -r line || [[ -n "$line" ]]; do
312
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Strip comments and trailing whitespace
313
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
line="${line%%#*}"
314
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
line="${line%"${line##*[![:space:]]}"}"
315
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
316
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Skip empty lines
317
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "$line" ]] && continue
318
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
319
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Detect section (key followed by colon, no value, next lines indented)
320
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$line" =~ ^([a-zA-Z_][a-zA-Z0-9_-]*):[[:space:]]*$ ]]; then
321
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
current_section="${BASH_REMATCH[1]}"
322
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
continue
323
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
324
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
325
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Indented key:value under a section
326
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$line" =~ ^[[:space:]]+([a-zA-Z_][a-zA-Z0-9_-]*):[[:space:]]*(.+)$ ]]; then
327
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
key="${BASH_REMATCH[1]}"
328
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${BASH_REMATCH[2]}"
329
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Strip quotes
330
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value%\"}"
331
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value#\"}"
332
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value%\'}"
333
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value#\'}"
334
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_set_config_value "${current_section}_${key}" "$value"
335
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
continue
336
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
337
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
338
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Top-level key: value
339
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$line" =~ ^([a-zA-Z_][a-zA-Z0-9_-]*):[[:space:]]*(.+)$ ]]; then
340
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
current_section=""
341
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
key="${BASH_REMATCH[1]}"
342
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${BASH_REMATCH[2]}"
343
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value%\"}"
344
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value#\"}"
345
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value%\'}"
346
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
value="${value#\'}"
347
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_set_config_value "$key" "$value"
348
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
continue
349
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
350
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done < "$config_file"
351
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
352
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
353
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_set_config_value() {
354
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local key="$1"
355
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local value="$2"
356
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
357
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Normalize key: lowercase, dashes to underscores
358
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
key="${key,,}"
359
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
key="${key//-/_}"
360
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
361
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$key" in
362
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mode) OPT_MODE="$value" ;;
363
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
domain) OPT_DOMAIN="$value" ;;
364
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ssl) OPT_SSL="$value" ;;
365
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
prefix) OPT_PREFIX="$value" ;;
366
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
port) OPT_PORT="$value" ;;
367
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
db_name) OPT_DB_NAME="$value" ;;
368
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
db_user) OPT_DB_USER="$value" ;;
369
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
db_password) OPT_DB_PASSWORD="$value" ;;
370
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
admin_user) OPT_ADMIN_USER="$value" ;;
371
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
admin_email) OPT_ADMIN_EMAIL="$value" ;;
372
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
admin_password) OPT_ADMIN_PASSWORD="$value" ;;
373
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
s3_bucket) OPT_S3_BUCKET="$value" ;;
374
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
s3_region) OPT_S3_REGION="$value" ;;
375
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
s3_endpoint) OPT_S3_ENDPOINT="$value" ;;
376
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
s3_access_key) OPT_S3_ACCESS_KEY="$value" ;;
377
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
s3_secret_key) OPT_S3_SECRET_KEY="$value" ;;
378
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) verbose "Ignoring unknown config key: $key" ;;
379
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
380
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
381
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
382
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
383
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 6: Arg Parser
384
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
385
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
386
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_help() {
387
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cat <<'HELPTEXT'
388
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fossilrepo installer -- deploy a full Fossil forge in one command.
389
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
390
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
USAGE
391
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install.sh [OPTIONS]
392
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install.sh --docker --domain fossil.example.com --ssl
393
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install.sh --bare-metal --domain fossil.example.com --config fossilrepo.yml
394
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install.sh # interactive mode
395
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
396
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
INSTALLATION MODE
397
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--docker Docker Compose deployment (recommended)
398
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--bare-metal Native install with systemd services
399
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
400
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
NETWORK
401
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--domain <fqdn> Domain name (default: localhost)
402
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--ssl Enable automatic HTTPS via Caddy/Let's Encrypt
403
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--port <port> Application port (default: 8000)
404
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
405
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DATABASE
406
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--db-password <pass> PostgreSQL password (auto-generated if omitted)
407
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
408
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ADMIN ACCOUNT
409
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-user <name> Admin username (default: admin)
410
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-email <email> Admin email address
411
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-password <pass> Admin password (auto-generated if omitted)
412
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
413
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
S3 BACKUP (LITESTREAM)
414
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-bucket <name> S3 bucket for Litestream replication
415
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-region <region> AWS region (default: us-east-1)
416
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-endpoint <url> S3-compatible endpoint (for MinIO etc.)
417
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-access-key <key> AWS access key ID
418
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-secret-key <key> AWS secret access key
419
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
420
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GENERAL
421
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--prefix <path> Install prefix (default: /opt/fossilrepo)
422
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--config <file> Load options from YAML config file
423
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--yes Skip all confirmation prompts
424
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--verbose Enable verbose output
425
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-h, --help Show this help and exit
426
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--version Show version and exit
427
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
428
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EXAMPLES
429
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Interactive guided install
430
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo ./install.sh
431
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
432
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Docker with auto-SSL
433
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo ./install.sh --docker --domain fossil.example.com --ssl --yes
434
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
435
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Bare metal with config file
436
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo ./install.sh --bare-metal --config /etc/fossilrepo/install.yml
437
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
438
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Docker on localhost for testing
439
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo ./install.sh --docker --yes
440
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
HELPTEXT
441
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
442
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
443
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
parse_args() {
444
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while [[ $# -gt 0 ]]; do
445
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$1" in
446
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--docker)
447
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_MODE="docker"
448
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift
449
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
450
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--bare-metal)
451
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_MODE="bare-metal"
452
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift
453
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
454
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--domain)
455
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--domain requires a value"
456
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DOMAIN="$2"
457
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
458
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
459
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--ssl)
460
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_SSL="true"
461
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift
462
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
463
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--prefix)
464
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--prefix requires a value"
465
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_PREFIX="$2"
466
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
467
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
468
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--port)
469
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--port requires a value"
470
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_PORT="$2"
471
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
472
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
473
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--db-password)
474
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--db-password requires a value"
475
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_DB_PASSWORD="$2"
476
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
477
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
478
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-user)
479
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--admin-user requires a value"
480
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_USER="$2"
481
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
482
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
483
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-email)
484
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--admin-email requires a value"
485
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_EMAIL="$2"
486
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
487
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
488
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--admin-password)
489
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--admin-password requires a value"
490
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_PASSWORD="$2"
491
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
492
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
493
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-bucket)
494
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--s3-bucket requires a value"
495
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_BUCKET="$2"
496
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
497
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
498
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-region)
499
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--s3-region requires a value"
500
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_REGION="$2"
501
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
502
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
503
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-endpoint)
504
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--s3-endpoint requires a value"
505
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_ENDPOINT="$2"
506
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
507
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
508
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-access-key)
509
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--s3-access-key requires a value"
510
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_ACCESS_KEY="$2"
511
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
512
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
513
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--s3-secret-key)
514
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--s3-secret-key requires a value"
515
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_SECRET_KEY="$2"
516
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
517
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
518
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--config)
519
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -z "${2:-}" ]] && die "--config requires a value"
520
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_CONFIG_FILE="$2"
521
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 2
522
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
523
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--yes|-y)
524
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_YES="true"
525
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift
526
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
527
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--verbose|-v)
528
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_VERBOSE="true"
529
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift
530
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
531
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-h|--help)
532
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_help
533
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
exit 0
534
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
535
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--version)
536
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo "fossilrepo installer v${INSTALLER_VERSION} (fossilrepo v${FOSSILREPO_VERSION})"
537
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
exit 0
538
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
539
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*)
540
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Unknown option: $1 (use --help for usage)"
541
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
542
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
543
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
544
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
545
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Load config file if specified (CLI args take precedence -- already set above)
546
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_CONFIG_FILE" ]]; then
547
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Save CLI-set values
548
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_mode="$OPT_MODE"
549
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_domain="$OPT_DOMAIN"
550
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_ssl="$OPT_SSL"
551
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_prefix="$OPT_PREFIX"
552
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_port="$OPT_PORT"
553
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_db_password="$OPT_DB_PASSWORD"
554
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_admin_user="$OPT_ADMIN_USER"
555
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_admin_email="$OPT_ADMIN_EMAIL"
556
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_admin_password="$OPT_ADMIN_PASSWORD"
557
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_s3_bucket="$OPT_S3_BUCKET"
558
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local saved_s3_region="$OPT_S3_REGION"
559
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
560
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
parse_config_file "$OPT_CONFIG_FILE"
561
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
562
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Restore CLI overrides (non-default values take precedence)
563
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_mode" ]] && OPT_MODE="$saved_mode"
564
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$saved_domain" != "localhost" ]] && OPT_DOMAIN="$saved_domain"
565
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$saved_ssl" == "true" ]] && OPT_SSL="$saved_ssl"
566
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$saved_prefix" != "$DEFAULT_PREFIX" ]] && OPT_PREFIX="$saved_prefix"
567
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$saved_port" != "8000" ]] && OPT_PORT="$saved_port"
568
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_db_password" ]] && OPT_DB_PASSWORD="$saved_db_password"
569
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$saved_admin_user" != "admin" ]] && OPT_ADMIN_USER="$saved_admin_user"
570
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_admin_email" ]] && OPT_ADMIN_EMAIL="$saved_admin_email"
571
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_admin_password" ]] && OPT_ADMIN_PASSWORD="$saved_admin_password"
572
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_s3_bucket" ]] && OPT_S3_BUCKET="$saved_s3_bucket"
573
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$saved_s3_region" ]] && OPT_S3_REGION="$saved_s3_region"
574
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
575
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
576
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
577
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
578
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 7: Interactive TUI
579
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
580
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
581
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_print_banner() {
582
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
583
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_CYAN}${_C_BOLD}"
584
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cat <<'BANNER'
585
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
__ _ __
586
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
/ _|___ ___ ___ (_) |_ __ ___ _ __ ___
587
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| |_/ _ \/ __/ __|| | | '__/ _ \ '_ \ / _ \
588
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| _| (_) \__ \__ \| | | | | __/ |_) | (_) |
589
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|_| \___/|___/___/|_|_|_| \___| .__/ \___/
590
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|_|
591
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
BANNER
592
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_RESET}"
593
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}Omnibus Installer v${INSTALLER_VERSION}${_C_RESET}\n"
594
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " Self-hosted Fossil forge -- one command, full stack.\n\n"
595
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
596
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
597
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt() {
598
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Usage: _prompt "Prompt text" "default" VARNAME
599
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local prompt="$1"
600
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local default="$2"
601
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local varname="$3"
602
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local reply
603
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
604
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$default" ]]; then
605
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%s${_C_RESET} [%s]: " "$prompt" "$default"
606
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
607
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%s${_C_RESET}: " "$prompt"
608
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
609
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -r reply
610
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reply="${reply:-$default}"
611
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
eval "$varname=\"\$reply\""
612
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
613
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
614
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_password() {
615
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local prompt="$1"
616
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local varname="$2"
617
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local reply
618
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
619
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%s${_C_RESET} (leave blank to auto-generate): " "$prompt"
620
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -rs reply
621
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
622
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
eval "$varname=\"\$reply\""
623
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
624
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
625
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_choice() {
626
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Usage: _prompt_choice "Prompt" "1" VARNAME "Option 1" "Option 2"
627
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local prompt="$1"
628
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local default="$2"
629
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local varname="$3"
630
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
shift 3
631
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local -a options=("$@")
632
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local i reply
633
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
634
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n ${_C_BOLD}%s${_C_RESET}\n" "$prompt"
635
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
for i in "${!options[@]}"; do
636
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %d) %s\n" "$((i + 1))" "${options[$i]}"
637
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
638
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " Choice [%s]: " "$default"
639
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -r reply
640
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reply="${reply:-$default}"
641
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
642
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$reply" =~ ^[0-9]+$ ]] && ((reply >= 1 && reply <= ${#options[@]})); then
643
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
eval "$varname=\"\$reply\""
644
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
645
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
eval "$varname=\"\$default\""
646
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
647
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
648
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
649
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_yesno() {
650
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local prompt="$1"
651
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local default="$2"
652
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local varname="$3"
653
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local reply hint
654
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
655
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$default" == "y" ]]; then hint="Y/n"; else hint="y/N"; fi
656
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%s${_C_RESET} [%s]: " "$prompt" "$hint"
657
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -r reply
658
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reply="${reply:-$default}"
659
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$reply" in
660
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[yY][eE][sS]|[yY]) eval "$varname=true" ;;
661
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) eval "$varname=false" ;;
662
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
663
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
664
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
665
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
run_interactive() {
666
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_print_banner
667
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
668
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BLUE}Welcome to the fossilrepo installer.${_C_RESET}\n"
669
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " This will guide you through setting up a self-hosted Fossil forge.\n\n"
670
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
671
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Mode
672
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local mode_choice
673
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_choice "Installation mode" "1" mode_choice \
674
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"Docker (recommended -- everything runs in containers)" \
675
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"Bare Metal (native install with systemd services)"
676
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$mode_choice" in
677
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1) OPT_MODE="docker" ;;
678
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2) OPT_MODE="bare-metal" ;;
679
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
680
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
681
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Domain
682
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "Domain name" "localhost" OPT_DOMAIN
683
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
684
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# SSL -- skip if localhost
685
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_DOMAIN" != "localhost" && "$OPT_DOMAIN" != "127.0.0.1" ]]; then
686
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_yesno "Enable automatic HTTPS (Let's Encrypt)" "y" OPT_SSL
687
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
688
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_SSL="false"
689
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "SSL skipped for localhost."
690
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
691
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
692
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# S3 backup
693
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local want_s3
694
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_yesno "Configure S3 backup (Litestream replication)" "n" want_s3
695
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$want_s3" == "true" ]]; then
696
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "S3 bucket name" "" OPT_S3_BUCKET
697
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "S3 region" "us-east-1" OPT_S3_REGION
698
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "S3 endpoint (leave blank for AWS)" "" OPT_S3_ENDPOINT
699
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "AWS Access Key ID" "" OPT_S3_ACCESS_KEY
700
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_password "AWS Secret Access Key" OPT_S3_SECRET_KEY
701
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
702
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
703
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Admin credentials
704
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n ${_C_BOLD}Admin Account${_C_RESET}\n"
705
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "Admin username" "admin" OPT_ADMIN_USER
706
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt "Admin email" "admin@${OPT_DOMAIN}" OPT_ADMIN_EMAIL
707
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_prompt_password "Admin password" OPT_ADMIN_PASSWORD
708
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
709
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Summary
710
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
711
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_CYAN}${_C_BOLD}Installation Summary${_C_RESET}\n"
712
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Mode:" "$OPT_MODE"
713
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Domain:" "$OPT_DOMAIN"
714
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "SSL:" "$OPT_SSL"
715
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Admin user:" "$OPT_ADMIN_USER"
716
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Admin email:" "$OPT_ADMIN_EMAIL"
717
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Admin password:" "$(if [[ -n "$OPT_ADMIN_PASSWORD" ]]; then echo '(set)'; else echo '(auto-generate)'; fi)"
718
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" ]]; then
719
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "S3 bucket:" "$OPT_S3_BUCKET"
720
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "S3 region:" "${OPT_S3_REGION:-us-east-1}"
721
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
722
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "S3 backup:" "disabled"
723
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
724
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-20s %s\n" "Install prefix:" "$OPT_PREFIX"
725
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
726
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
727
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
728
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
729
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 8: Dependency Management
730
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
731
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
732
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
check_docker_deps() {
733
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Checking Docker dependencies"
734
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
735
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local missing=()
736
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
737
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists docker; then
738
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("docker")
739
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
740
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
741
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Check for docker compose v2 (plugin)
742
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists docker; then
743
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! docker compose version &>/dev/null; then
744
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("docker-compose-plugin")
745
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
746
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
747
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
748
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ${#missing[@]} -gt 0 ]]; then
749
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "Missing Docker dependencies: ${missing[*]}"
750
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 1
751
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
752
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
753
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local compose_ver
754
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
compose_ver="$(docker compose version --short 2>/dev/null || echo "0")"
755
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Docker $(docker --version | awk '{print $3}' | tr -d ',') + Compose $compose_ver"
756
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
757
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
758
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
759
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
check_bare_metal_deps() {
760
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Checking bare metal dependencies"
761
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
762
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local missing=()
763
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
764
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists git || missing+=("git")
765
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists curl || missing+=("curl")
766
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
767
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Python 3.12+
768
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists python3; then
769
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pyver
770
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pyver="$(python3 --version 2>&1 | awk '{print $2}')"
771
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! version_gte "$pyver" "$PYTHON_VERSION"; then
772
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("python${PYTHON_VERSION}")
773
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
774
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
775
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("python${PYTHON_VERSION}")
776
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
777
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
778
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# PostgreSQL
779
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists psql; then
780
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pgver
781
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pgver="$(psql --version | awk '{print $3}' | cut -d. -f1)"
782
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! version_gte "$pgver" "$POSTGRES_VERSION"; then
783
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("postgresql-${POSTGRES_VERSION}")
784
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
785
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
786
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missing+=("postgresql-${POSTGRES_VERSION}")
787
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
788
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
789
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists redis-server || missing+=("redis")
790
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
791
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# These are installed from source/binary -- check separately
792
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists fossil || missing+=("fossil")
793
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists caddy || missing+=("caddy")
794
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
795
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ${#missing[@]} -gt 0 ]]; then
796
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "Missing dependencies: ${missing[*]}"
797
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 1
798
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
799
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
800
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "All bare metal dependencies present"
801
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
802
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
803
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
804
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_docker_engine() {
805
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Docker Engine..."
806
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
807
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$PKG_MANAGER" in
808
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt)
809
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Docker official GPG key and repo
810
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get update -qq
811
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq ca-certificates curl gnupg lsb-release
812
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
813
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install -m 0755 -d /etc/apt/keyrings
814
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
815
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL "https://download.docker.com/linux/${OS_ID}/gpg" | \
816
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
gpg --dearmor -o /etc/apt/keyrings/docker.gpg
817
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chmod a+r /etc/apt/keyrings/docker.gpg
818
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
819
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
820
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local codename
821
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
codename="$(. /etc/os-release && echo "$VERSION_CODENAME")"
822
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cat > /etc/apt/sources.list.d/docker.list <<EOF
823
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
deb [arch=${OS_ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${OS_ID} ${codename} stable
824
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EOF
825
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
826
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get update -qq
827
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
828
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
829
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf)
830
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q dnf-plugins-core
831
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf config-manager --add-repo "https://download.docker.com/linux/${OS_ID}/docker-ce.repo" 2>/dev/null || \
832
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf config-manager --add-repo "https://download.docker.com/linux/centos/docker-ce.repo"
833
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
834
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
835
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apk)
836
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apk add --no-cache docker docker-cli-compose
837
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
;;
838
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
839
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
840
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable --now docker
841
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Docker installed and running"
842
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
843
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
844
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_deps_debian() {
845
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Installing system packages (Debian/Ubuntu)"
846
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
847
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get update -qq
848
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
849
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Build tools for Fossil compilation + runtime deps
850
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq \
851
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
build-essential \
852
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ca-certificates \
853
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl \
854
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git \
855
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
gnupg \
856
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
lsb-release \
857
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
zlib1g-dev \
858
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
libssl-dev \
859
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tcl \
860
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
openssh-server \
861
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo \
862
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
logrotate
863
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
864
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Python 3.12
865
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists python3 || ! version_gte "$(python3 --version 2>&1 | awk '{print $2}')" "$PYTHON_VERSION"; then
866
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Python ${PYTHON_VERSION}..."
867
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq software-properties-common
868
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
add-apt-repository -y ppa:deadsnakes/ppa 2>/dev/null || true
869
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get update -qq
870
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq "python${PYTHON_VERSION}" "python${PYTHON_VERSION}-venv" "python${PYTHON_VERSION}-dev" || \
871
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq python3 python3-venv python3-dev
872
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
873
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
874
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# PostgreSQL 16
875
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists psql || ! version_gte "$(psql --version | awk '{print $3}' | cut -d. -f1)" "$POSTGRES_VERSION"; then
876
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing PostgreSQL ${POSTGRES_VERSION}..."
877
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ ! -f /etc/apt/sources.list.d/pgdg.list ]]; then
878
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
879
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg
880
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo "deb [signed-by=/etc/apt/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
881
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
> /etc/apt/sources.list.d/pgdg.list
882
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get update -qq
883
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
884
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq "postgresql-${POSTGRES_VERSION}" "postgresql-client-${POSTGRES_VERSION}"
885
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
886
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
887
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Redis
888
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists redis-server; then
889
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Redis..."
890
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt-get install -y -qq redis-server
891
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
892
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
893
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "System packages installed"
894
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
895
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
896
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_deps_rhel() {
897
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Installing system packages (RHEL/CentOS/Fedora/Amazon Linux)"
898
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
899
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q epel-release 2>/dev/null || true
900
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf groupinstall -y -q "Development Tools" 2>/dev/null || \
901
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q gcc gcc-c++ make
902
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
903
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# AL2023 ships curl-minimal which conflicts with curl; skip if any curl works
904
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local curl_pkg=""
905
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists curl || curl_pkg="curl"
906
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
907
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q \
908
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ca-certificates \
909
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
$curl_pkg \
910
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git \
911
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
zlib-devel \
912
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
openssl-devel \
913
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tcl \
914
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
openssh-server \
915
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo \
916
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
logrotate
917
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
918
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Python 3.12
919
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists python3 || ! version_gte "$(python3 --version 2>&1 | awk '{print $2}')" "$PYTHON_VERSION"; then
920
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Python ${PYTHON_VERSION}..."
921
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q "python${PYTHON_VERSION//.}" "python${PYTHON_VERSION//.}-devel" 2>/dev/null || \
922
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q python3 python3-devel
923
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
924
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
925
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# PostgreSQL
926
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists psql; then
927
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing PostgreSQL..."
928
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Try PG16 from PGDG repo first, fall back to distro version (PG15 on AL2023)
929
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if dnf install -y -q "https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-${OS_ARCH}/pgdg-redhat-repo-latest.noarch.rpm" 2>/dev/null; then
930
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q "postgresql${POSTGRES_VERSION}-server" "postgresql${POSTGRES_VERSION}" 2>/dev/null || \
931
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q postgresql15-server postgresql15
932
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
933
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q postgresql15-server postgresql15 2>/dev/null || \
934
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q postgresql-server postgresql
935
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
936
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
937
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
938
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Redis
939
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists redis-server && ! command_exists redis6-server; then
940
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Redis..."
941
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf install -y -q redis 2>/dev/null || dnf install -y -q redis6
942
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
943
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
944
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "System packages installed"
945
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
946
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
947
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_fossil_from_source() {
948
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Matches Dockerfile lines 11-22 exactly
949
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists fossil; then
950
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local current_ver
951
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
current_ver="$(fossil version | grep -oP 'version \K[0-9]+\.[0-9]+' | head -1)"
952
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if version_gte "${current_ver:-0}" "$FOSSIL_VERSION"; then
953
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Fossil $current_ver already installed (>= $FOSSIL_VERSION)"
954
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
955
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
956
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
957
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
958
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Building Fossil ${FOSSIL_VERSION} from source..."
959
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local build_dir
960
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
build_dir="$(mktemp -d)"
961
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
962
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
(
963
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd "$build_dir"
964
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -sSL "https://fossil-scm.org/home/tarball/version-${FOSSIL_VERSION}/fossil-src-${FOSSIL_VERSION}.tar.gz" \
965
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-o fossil.tar.gz
966
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar xzf fossil.tar.gz
967
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd "fossil-src-${FOSSIL_VERSION}"
968
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./configure --prefix=/usr/local --with-openssl=auto --json
969
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
make -j"$(nproc)"
970
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
make install
971
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
)
972
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
973
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf "$build_dir"
974
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
975
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists fossil; then
976
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Fossil build failed -- binary not found at /usr/local/bin/fossil"
977
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
978
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
979
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Fossil $(fossil version | grep -oP 'version \K[0-9]+\.[0-9]+') installed"
980
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
981
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
982
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_caddy_binary() {
983
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists caddy; then
984
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local current_ver
985
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
current_ver="$(caddy version 2>/dev/null | awk '{print $1}' | tr -d 'v')"
986
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if version_gte "${current_ver:-0}" "$CADDY_VERSION"; then
987
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Caddy $current_ver already installed (>= $CADDY_VERSION)"
988
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
989
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
990
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
991
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
992
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Caddy ${CADDY_VERSION}..."
993
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
994
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_arch="$OS_ARCH"
995
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_url="${CADDY_DOWNLOAD_BASE}?os=linux&arch=${caddy_arch}"
996
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
997
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -sSL "$caddy_url" -o /usr/local/bin/caddy
998
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chmod +x /usr/local/bin/caddy
999
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1000
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! /usr/local/bin/caddy version &>/dev/null; then
1001
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Caddy binary download failed or is not executable"
1002
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1003
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1004
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Allow Caddy to bind to privileged ports without root
1005
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists setcap; then
1006
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy 2>/dev/null || true
1007
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1008
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1009
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Caddy $(/usr/local/bin/caddy version | awk '{print $1}') installed"
1010
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1011
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1012
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_litestream_binary() {
1013
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -z "$OPT_S3_BUCKET" ]]; then
1014
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Skipping Litestream install (no S3 bucket configured)"
1015
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
1016
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1017
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1018
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists litestream; then
1019
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local current_ver
1020
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
current_ver="$(litestream version 2>/dev/null | tr -d 'v')"
1021
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if version_gte "${current_ver:-0}" "$LITESTREAM_VERSION"; then
1022
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Litestream $current_ver already installed (>= $LITESTREAM_VERSION)"
1023
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
1024
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1025
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1026
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1027
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing Litestream ${LITESTREAM_VERSION}..."
1028
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1029
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local ls_arch
1030
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$OS_ARCH" in
1031
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
amd64) ls_arch="amd64" ;;
1032
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
arm64) ls_arch="arm64" ;;
1033
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
1034
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1035
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local ls_url="${LITESTREAM_DOWNLOAD_BASE}/v${LITESTREAM_VERSION}/litestream-v${LITESTREAM_VERSION}-linux-${ls_arch}.tar.gz"
1036
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local tmp_dir
1037
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tmp_dir="$(mktemp -d)"
1038
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1039
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -sSL "$ls_url" -o "${tmp_dir}/litestream.tar.gz"
1040
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar xzf "${tmp_dir}/litestream.tar.gz" -C "${tmp_dir}"
1041
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install -m 0755 "${tmp_dir}/litestream" /usr/local/bin/litestream
1042
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf "$tmp_dir"
1043
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1044
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists litestream; then
1045
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Litestream install failed"
1046
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1047
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1048
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Litestream $(litestream version) installed"
1049
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1050
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1051
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_uv() {
1052
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if command_exists uv; then
1053
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "uv already installed"
1054
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
1055
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1056
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1057
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Installing uv (Python package manager)..."
1058
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export HOME="${HOME:-/root}"
1059
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -LsSf https://astral.sh/uv/install.sh | sh
1060
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Copy to /usr/local/bin so all users can access it (symlink fails because /root is 700)
1061
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f "${HOME}/.local/bin/uv" /usr/local/bin/uv 2>/dev/null || true
1062
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f "${HOME}/.local/bin/uvx" /usr/local/bin/uvx 2>/dev/null || true
1063
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chmod +x /usr/local/bin/uv /usr/local/bin/uvx 2>/dev/null || true
1064
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export PATH="/usr/local/bin:${HOME}/.local/bin:$PATH"
1065
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1066
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! command_exists uv; then
1067
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Fallback: pip install
1068
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pip3 install uv 2>/dev/null || pip install uv 2>/dev/null || \
1069
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Failed to install uv"
1070
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1071
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1072
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "uv installed"
1073
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1074
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1075
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
check_and_install_deps() {
1076
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "docker" ]]; then
1077
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! check_docker_deps; then
1078
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
confirm "Docker not found. Install Docker Engine?"
1079
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_docker_engine
1080
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1081
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1082
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Bare metal: install OS packages, then build/download remaining deps
1083
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$PKG_MANAGER" in
1084
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
apt) install_deps_debian ;;
1085
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dnf) install_deps_rhel ;;
1086
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) die "Unsupported package manager: $PKG_MANAGER" ;;
1087
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
1088
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1089
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_fossil_from_source
1090
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_caddy_binary
1091
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_litestream_binary
1092
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_uv
1093
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1094
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1095
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1096
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
1097
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 9: Docker Mode
1098
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
1099
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_env_file() {
1101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating .env file..."
1102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local proto="http"
1104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$OPT_SSL" == "true" ]] && proto="https"
1105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local base_url="${proto}://${OPT_DOMAIN}"
1106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local db_host="postgres"
1108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local redis_host="redis"
1109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local email_host="localhost"
1110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local use_s3="false"
1112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$OPT_S3_BUCKET" ]] && use_s3="true"
1113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local env_content
1115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_content="# fossilrepo -- generated by installer on $(date -u +%Y-%m-%dT%H:%M:%SZ)
1116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Mode: ${OPT_MODE}
1117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Security ---
1119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_SECRET_KEY=${GEN_SECRET_KEY}
1120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_DEBUG=false
1121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_ALLOWED_HOSTS=${OPT_DOMAIN},localhost,127.0.0.1
1122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Database ---
1124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_DB=${OPT_DB_NAME}
1125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_USER=${OPT_DB_USER}
1126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_PASSWORD=${GEN_DB_PASSWORD}
1127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_HOST=${db_host}
1128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_PORT=5432
1129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Redis / Celery ---
1131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
REDIS_URL=redis://${redis_host}:6379/1
1132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CELERY_BROKER=redis://${redis_host}:6379/0
1133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Email ---
1135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EMAIL_HOST=${email_host}
1136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EMAIL_PORT=587
1137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
1138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FROM_EMAIL=no-reply@${OPT_DOMAIN}
1139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- S3 / Media ---
1141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
USE_S3=${use_s3}
1142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_ACCESS_KEY_ID=${OPT_S3_ACCESS_KEY}
1143
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_SECRET_ACCESS_KEY=${OPT_S3_SECRET_KEY}
1144
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_STORAGE_BUCKET_NAME=${OPT_S3_BUCKET}
1145
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_S3_ENDPOINT_URL=${OPT_S3_ENDPOINT}
1146
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1147
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- CORS / CSRF ---
1148
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CORS_ALLOWED_ORIGINS=${base_url}
1149
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CSRF_TRUSTED_ORIGINS=${base_url}
1150
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1151
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Sentry ---
1152
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
SENTRY_DSN=
1153
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1154
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Litestream S3 Replication ---
1155
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_BUCKET=${OPT_S3_BUCKET}
1156
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_REGION=${OPT_S3_REGION:-us-east-1}
1157
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_ENDPOINT=${OPT_S3_ENDPOINT}"
1158
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1159
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/.env" "$env_content" "0600"
1160
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1161
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1162
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_docker_compose() {
1163
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating docker-compose.yml..."
1164
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1165
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local litestream_service=""
1166
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local litestream_depends=""
1167
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" ]]; then
1168
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
litestream_depends="
1169
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
litestream:
1170
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_started"
1171
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
litestream_service="
1172
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
litestream:
1173
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
image: litestream/litestream:${LITESTREAM_VERSION}
1174
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1175
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- fossil-repos:/data/repos
1176
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- ./litestream.yml:/etc/litestream.yml:ro
1177
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_file: .env
1178
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command: litestream replicate -config /etc/litestream.yml
1179
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped"
1180
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1181
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1182
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local compose_content
1183
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
compose_content="# fossilrepo -- production docker-compose
1184
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer on $(date -u +%Y-%m-%dT%H:%M:%SZ)
1185
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1186
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
services:
1187
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
app:
1188
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
build:
1189
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
context: ./src
1190
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dockerfile: Dockerfile
1191
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_file: .env
1192
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
environment:
1193
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_DEBUG: \"false\"
1194
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_HOST: postgres
1195
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
REDIS_URL: redis://redis:6379/1
1196
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CELERY_BROKER: redis://redis:6379/0
1197
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ports:
1198
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- \"${OPT_PORT}:8000\"
1199
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- \"2222:2222\"
1200
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1201
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- fossil-repos:/data/repos
1202
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- fossil-ssh:/data/ssh
1203
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- static-files:/app/assets
1204
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
depends_on:
1205
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
postgres:
1206
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1207
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
redis:
1208
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1209
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1210
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
healthcheck:
1211
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
test: [\"CMD-SHELL\", \"curl -sf -o /dev/null -w '%{http_code}' http://localhost:8000/health/ | grep -qE '200|301|302' || exit 1\"]
1212
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
interval: 15s
1213
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
timeout: 10s
1214
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
retries: 5
1215
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
start_period: 60s
1216
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1217
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
celery-worker:
1218
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
build:
1219
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
context: ./src
1220
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dockerfile: Dockerfile
1221
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command: celery -A config.celery worker -l info -Q celery
1222
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_file: .env
1223
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
environment:
1224
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_HOST: postgres
1225
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
REDIS_URL: redis://redis:6379/1
1226
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CELERY_BROKER: redis://redis:6379/0
1227
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1228
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- fossil-repos:/data/repos
1229
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
depends_on:
1230
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
postgres:
1231
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1232
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
redis:
1233
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1234
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1235
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1236
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
celery-beat:
1237
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
build:
1238
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
context: ./src
1239
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dockerfile: Dockerfile
1240
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command: celery -A config.celery beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
1241
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_file: .env
1242
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
environment:
1243
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_HOST: postgres
1244
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
REDIS_URL: redis://redis:6379/1
1245
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CELERY_BROKER: redis://redis:6379/0
1246
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
depends_on:
1247
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
postgres:
1248
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1249
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
redis:
1250
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_healthy
1251
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1252
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1253
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
postgres:
1254
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
image: postgres:${POSTGRES_VERSION}-alpine
1255
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
environment:
1256
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_DB: ${OPT_DB_NAME}
1257
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_USER: ${OPT_DB_USER}
1258
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_PASSWORD: ${GEN_DB_PASSWORD}
1259
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1260
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- pgdata:/var/lib/postgresql/data
1261
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
healthcheck:
1262
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
test: [\"CMD-SHELL\", \"pg_isready -U ${OPT_DB_USER} -d ${OPT_DB_NAME}\"]
1263
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
interval: 5s
1264
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
timeout: 5s
1265
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
retries: 5
1266
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1267
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1268
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
redis:
1269
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
image: redis:${REDIS_VERSION}-alpine
1270
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1271
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- redisdata:/data
1272
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command: redis-server --appendonly yes
1273
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
healthcheck:
1274
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
test: [\"CMD\", \"redis-cli\", \"ping\"]
1275
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
interval: 5s
1276
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
timeout: 5s
1277
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
retries: 5
1278
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1279
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1280
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy:
1281
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
image: caddy:2-alpine
1282
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ports:
1283
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- \"80:80\"
1284
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- \"443:443\"
1285
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- \"443:443/udp\"
1286
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1287
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- ./Caddyfile:/etc/caddy/Caddyfile:ro
1288
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- caddy-data:/data
1289
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- caddy-config:/config
1290
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- static-files:/srv/static:ro
1291
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
depends_on:
1292
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
app:
1293
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
condition: service_started
1294
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
restart: unless-stopped
1295
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
${litestream_service}
1296
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
volumes:
1297
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pgdata:
1298
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
redisdata:
1299
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fossil-repos:
1300
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fossil-ssh:
1301
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
static-files:
1302
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy-data:
1303
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy-config:"
1304
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1305
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/docker-compose.yml" "$compose_content"
1306
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1307
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1308
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_caddyfile() {
1309
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating Caddyfile..."
1310
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1311
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_content
1312
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1313
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_SSL" == "true" && "$OPT_DOMAIN" != "localhost" ]]; then
1314
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_content="# fossilrepo Caddy config -- auto HTTPS
1315
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1316
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1317
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Root domain -- Django app
1318
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
${OPT_DOMAIN} {
1319
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
encode gzip
1320
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1321
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Static files served by Caddy
1322
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
handle_path /static/* {
1323
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
root * /srv/static
1324
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
file_server
1325
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1326
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1327
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Everything else to Django/gunicorn
1328
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reverse_proxy app:8000
1329
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1330
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1331
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Wildcard subdomain routing -- repo subdomains to Django
1332
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*.${OPT_DOMAIN} {
1333
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tls {
1334
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dns
1335
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1336
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1337
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
encode gzip
1338
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reverse_proxy app:8000
1339
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}"
1340
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1341
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# No SSL / localhost
1342
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local listen_addr
1343
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_DOMAIN" == "localhost" || "$OPT_DOMAIN" == "127.0.0.1" ]]; then
1344
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
listen_addr=":80"
1345
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1346
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
listen_addr="${OPT_DOMAIN}:80"
1347
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1348
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1349
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_content="# fossilrepo Caddy config -- HTTP only
1350
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1351
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1352
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
1353
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auto_https off
1354
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1355
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1356
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
${listen_addr} {
1357
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
encode gzip
1358
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1359
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
handle_path /static/* {
1360
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
root * /srv/static
1361
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
file_server
1362
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1363
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1364
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reverse_proxy app:8000
1365
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}"
1366
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1367
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1368
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/Caddyfile" "$caddy_content"
1369
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1370
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1371
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_litestream_config() {
1372
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -z "$OPT_S3_BUCKET" ]]; then
1373
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 0
1374
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1375
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1376
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating litestream.yml..."
1377
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1378
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local ls_content
1379
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ls_content="# Litestream replication -- continuous .fossil backup to S3
1380
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1381
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1382
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dbs:
1383
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- path: /data/repos/*.fossil
1384
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
replicas:
1385
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- type: s3
1386
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bucket: ${OPT_S3_BUCKET}
1387
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
endpoint: ${OPT_S3_ENDPOINT}
1388
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
region: ${OPT_S3_REGION:-us-east-1}
1389
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
access-key-id: \${AWS_ACCESS_KEY_ID}
1390
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
secret-access-key: \${AWS_SECRET_ACCESS_KEY}"
1391
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1392
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/litestream.yml" "$ls_content"
1393
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1394
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1395
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_docker_systemd() {
1396
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Creating systemd service for auto-start..."
1397
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1398
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local unit_content
1399
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
unit_content="[Unit]
1400
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=fossilrepo (Docker Compose)
1401
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Requires=docker.service
1402
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=docker.service
1403
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1404
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1405
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=oneshot
1406
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RemainAfterExit=yes
1407
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WorkingDirectory=${OPT_PREFIX}
1408
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=/usr/bin/docker compose up -d --remove-orphans
1409
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStop=/usr/bin/docker compose down
1410
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
TimeoutStartSec=300
1411
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1412
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1413
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1414
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1415
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/fossilrepo.service" "$unit_content"
1416
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl daemon-reload
1417
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable fossilrepo.service
1418
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "systemd service enabled (fossilrepo.service)"
1419
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1420
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1421
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_docker() {
1422
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Installing fossilrepo (Docker mode)"
1423
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1424
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p "${OPT_PREFIX}/src"
1425
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1426
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Clone the repo
1427
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -d "${OPT_PREFIX}/src/.git" ]]; then
1428
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Updating existing repo..."
1429
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git -C "${OPT_PREFIX}/src" pull --ff-only || true
1430
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1431
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Cloning fossilrepo..."
1432
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git clone "$REPO_URL" "${OPT_PREFIX}/src"
1433
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1434
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1435
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generate all config files
1436
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_env_file
1437
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_docker_compose
1438
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_caddyfile
1439
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_litestream_config
1440
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1441
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Build and start
1442
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Building Docker images (this may take a few minutes)..."
1443
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd "$OPT_PREFIX"
1444
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose build
1445
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1446
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Starting services..."
1447
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose up -d
1448
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1449
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Wait for postgres to be healthy
1450
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Waiting for PostgreSQL to be ready..."
1451
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local attempts=0
1452
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while ! docker compose exec -T postgres pg_isready -U "$OPT_DB_USER" -d "$OPT_DB_NAME" &>/dev/null; do
1453
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
((attempts++))
1454
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ((attempts > 30)); then
1455
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "PostgreSQL did not become ready within 150 seconds"
1456
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1457
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sleep 5
1458
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
1459
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "PostgreSQL is ready"
1460
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1461
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Run Django setup
1462
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Running database migrations..."
1463
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose exec -T app python manage.py migrate --noinput
1464
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1465
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Collecting static files..."
1466
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose exec -T app python manage.py collectstatic --noinput
1467
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1468
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Create admin user
1469
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Creating admin user..."
1470
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose exec -T app python manage.py shell -c "
1471
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
from django.contrib.auth import get_user_model
1472
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User = get_user_model()
1473
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if not User.objects.filter(username='${OPT_ADMIN_USER}').exists():
1474
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
user = User.objects.create_superuser(
1475
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
username='${OPT_ADMIN_USER}',
1476
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
email='${OPT_ADMIN_EMAIL}',
1477
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
password='${GEN_ADMIN_PASSWORD}',
1478
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
)
1479
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
print(f'Admin user created: {user.username}')
1480
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else:
1481
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
print('Admin user already exists')
1482
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"
1483
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1484
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Create data directories inside the app container
1485
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose exec -T app mkdir -p /data/repos /data/trash /data/ssh
1486
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1487
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_docker_systemd
1488
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1489
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Docker installation complete"
1490
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1491
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1492
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
1493
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 10: Bare Metal Mode
1494
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
1495
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1496
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
create_system_user() {
1497
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Creating fossilrepo system user..."
1498
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1499
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if id fossilrepo &>/dev/null; then
1500
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "User fossilrepo already exists"
1501
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1502
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
useradd -r -m -d /home/fossilrepo -s /bin/bash fossilrepo
1503
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1504
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1505
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Data directories
1506
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p "${DATA_DIR}/repos" "${DATA_DIR}/trash" "${DATA_DIR}/ssh" "${DATA_DIR}/git-mirrors" "${DATA_DIR}/ssh-keys"
1507
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p "$LOG_DIR"
1508
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p "${OPT_PREFIX}"
1509
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown -R fossilrepo:fossilrepo "${DATA_DIR}"
1510
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown -R fossilrepo:fossilrepo "$LOG_DIR"
1511
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1512
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "System user and directories created"
1513
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1514
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1515
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
clone_repo() {
1516
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Configure SSH for GitHub if deploy key exists
1517
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -f /root/.ssh/deploy_key ]]; then
1518
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export GIT_SSH_COMMAND="ssh -i /root/.ssh/deploy_key -o StrictHostKeyChecking=no"
1519
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Use SSH URL for private repos
1520
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local repo_url="${REPO_URL/https:\/\/github.com\//[email protected] :}"
1521
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1522
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local repo_url="$REPO_URL"
1523
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1524
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1525
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -d "${OPT_PREFIX}/.git" ]]; then
1526
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Updating existing repo..."
1527
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git config --global --add safe.directory "$OPT_PREFIX" 2>/dev/null || true
1528
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git -C "$OPT_PREFIX" pull --ff-only || true
1529
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
elif [[ -d "$OPT_PREFIX" ]]; then
1530
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Safety: never move a directory that contains user data
1531
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -d "${OPT_PREFIX}/.venv" ]] || [[ -f "${OPT_PREFIX}/.env" ]]; then
1532
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "${OPT_PREFIX} exists (previous install). Cloning into subfolder..."
1533
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local src_dir="${OPT_PREFIX}/src"
1534
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf "$src_dir"
1535
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git clone "$repo_url" "$src_dir"
1536
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Move source files up, preserving .env and .venv
1537
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
find "$src_dir" -maxdepth 1 -not -name src -not -name . -exec mv -n {} "$OPT_PREFIX/" \;
1538
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf "$src_dir"
1539
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1540
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "${OPT_PREFIX} exists but is not a git repo or fossilrepo install. Backing up..."
1541
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mv "$OPT_PREFIX" "${OPT_PREFIX}.bak.$(date +%s)"
1542
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git clone "$repo_url" "$OPT_PREFIX"
1543
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1544
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1545
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Cloning fossilrepo to ${OPT_PREFIX}..."
1546
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git clone "$repo_url" "$OPT_PREFIX"
1547
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1548
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown -R fossilrepo:fossilrepo "$OPT_PREFIX"
1549
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Repository cloned"
1550
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1551
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1552
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_python_venv() {
1553
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Setting up Python virtual environment..."
1554
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1555
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local venv_dir="${OPT_PREFIX}/.venv"
1556
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1557
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Resolve uv path (sudo resets PATH)
1558
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local uv_bin
1559
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
uv_bin="$(command -v uv 2>/dev/null || echo /usr/local/bin/uv)"
1560
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1561
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Use uv to create venv and install deps
1562
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -x "$uv_bin" ]]; then
1563
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo "$uv_bin" venv "$venv_dir" --python "python${PYTHON_VERSION}" 2>/dev/null || \
1564
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo "$uv_bin" venv "$venv_dir" --clear 2>/dev/null || \
1565
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo "$uv_bin" venv "$venv_dir"
1566
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo bash -c "cd '${OPT_PREFIX}' && source '${venv_dir}/bin/activate' && '${uv_bin}' pip install -r pyproject.toml"
1567
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1568
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo "python${PYTHON_VERSION}" -m venv "$venv_dir" 2>/dev/null || \
1569
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo python3 -m venv "$venv_dir"
1570
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo bash -c "source '${venv_dir}/bin/activate' && pip install --upgrade pip && pip install -r '${OPT_PREFIX}/pyproject.toml'"
1571
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1572
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1573
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Python environment configured"
1574
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1575
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1576
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_postgres() {
1577
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Configuring PostgreSQL..."
1578
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1579
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ensure PostgreSQL service is running
1580
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pg_service
1581
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pg_service="postgresql"
1582
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if systemctl list-unit-files "postgresql-${POSTGRES_VERSION}.service" &>/dev/null; then
1583
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pg_service="postgresql-${POSTGRES_VERSION}"
1584
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1585
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1586
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Initialize cluster if needed (RHEL)
1587
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$PKG_MANAGER" == "dnf" ]]; then
1588
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pg_setup="/usr/pgsql-${POSTGRES_VERSION}/bin/postgresql-${POSTGRES_VERSION}-setup"
1589
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -x "$pg_setup" ]]; then
1590
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"$pg_setup" initdb 2>/dev/null || true
1591
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1592
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1593
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1594
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable --now "$pg_service"
1595
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1596
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Wait for PostgreSQL to accept connections
1597
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local attempts=0
1598
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while ! sudo -u postgres pg_isready -q 2>/dev/null; do
1599
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
((attempts++))
1600
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ((attempts > 20)); then
1601
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "PostgreSQL did not start within 100 seconds"
1602
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1603
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sleep 5
1604
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
1605
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1606
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ensure peer auth for postgres user (previous runs may have broken it)
1607
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pg_hba_candidates=("/var/lib/pgsql/data/pg_hba.conf" "/etc/postgresql/*/main/pg_hba.conf")
1608
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local pg_hba=""
1609
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
for f in ${pg_hba_candidates[@]}; do
1610
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -f "$f" ]] && pg_hba="$f" && break
1611
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
1612
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1613
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$pg_hba" ]]; then
1614
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ensure postgres user can connect via peer (unix socket)
1615
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! grep -q "^local.*all.*postgres.*peer" "$pg_hba"; then
1616
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sed -i '1i local all postgres peer' "$pg_hba"
1617
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl reload "$pg_service" 2>/dev/null || true
1618
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sleep 2
1619
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1620
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1621
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1622
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Create user and database (idempotent)
1623
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname = '${OPT_DB_USER}'" | \
1624
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
grep -q 1 || \
1625
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -c "CREATE USER ${OPT_DB_USER} WITH PASSWORD '${GEN_DB_PASSWORD}';"
1626
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1627
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Update password in case it changed
1628
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -c "ALTER USER ${OPT_DB_USER} WITH PASSWORD '${GEN_DB_PASSWORD}';"
1629
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1630
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname = '${OPT_DB_NAME}'" | \
1631
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
grep -q 1 || \
1632
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -c "CREATE DATABASE ${OPT_DB_NAME} OWNER ${OPT_DB_USER};"
1633
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1634
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${OPT_DB_NAME} TO ${OPT_DB_USER};"
1635
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -d "${OPT_DB_NAME}" -c "GRANT ALL ON SCHEMA public TO ${OPT_DB_USER};"
1636
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u postgres psql -d "${OPT_DB_NAME}" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ${OPT_DB_USER};"
1637
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1638
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Fix pg_hba.conf to allow md5 auth for app connections via TCP (127.0.0.1)
1639
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pg_hba="${pg_hba:-$(sudo -u postgres psql -t -c 'SHOW hba_file' 2>/dev/null | tr -d '[:space:]')}"
1640
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1641
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -f "$pg_hba" ]]; then
1642
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ensure md5 auth for 127.0.0.1 connections
1643
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! grep -q "host.*${OPT_DB_NAME}.*${OPT_DB_USER}.*127.0.0.1/32.*md5" "$pg_hba" && \
1644
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
! grep -q "host.*${OPT_DB_NAME}.*${OPT_DB_USER}.*127.0.0.1/32.*scram-sha-256" "$pg_hba"; then
1645
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
backup_file "$pg_hba"
1646
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Insert before the first 'host' line to take priority
1647
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sed -i "/^# IPv4 local connections/a host ${OPT_DB_NAME} ${OPT_DB_USER} 127.0.0.1/32 md5" "$pg_hba" 2>/dev/null || \
1648
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo "host ${OPT_DB_NAME} ${OPT_DB_USER} 127.0.0.1/32 md5" >> "$pg_hba"
1649
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl reload "$pg_service"
1650
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Added md5 auth rule to pg_hba.conf"
1651
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1652
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1653
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1654
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Verify connection works
1655
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! PGPASSWORD="$GEN_DB_PASSWORD" psql -h 127.0.0.1 -U "$OPT_DB_USER" -d "$OPT_DB_NAME" -c "SELECT 1" &>/dev/null; then
1656
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "PostgreSQL connection test failed -- you may need to manually adjust pg_hba.conf"
1657
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1658
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "PostgreSQL configured and connection verified"
1659
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1660
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1661
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1662
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_redis() {
1663
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Configuring Redis..."
1664
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable --now redis-server 2>/dev/null || systemctl enable --now redis6 2>/dev/null || systemctl enable --now redis 2>/dev/null
1665
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Verify Redis is responding
1666
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local attempts=0
1667
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local redis_cli="redis-cli"
1668
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command_exists redis-cli || redis_cli="redis6-cli"
1669
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
while ! $redis_cli ping &>/dev/null; do
1670
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
((attempts++))
1671
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ((attempts > 10)); then
1672
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Redis did not start within 50 seconds"
1673
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1674
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sleep 5
1675
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
done
1676
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Redis running"
1677
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1678
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1679
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_bare_metal_env() {
1680
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating .env file..."
1681
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1682
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local proto="http"
1683
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$OPT_SSL" == "true" ]] && proto="https"
1684
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local base_url="${proto}://${OPT_DOMAIN}"
1685
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1686
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local use_s3="false"
1687
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$OPT_S3_BUCKET" ]] && use_s3="true"
1688
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1689
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local env_content
1690
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
env_content="# fossilrepo -- generated by installer on $(date -u +%Y-%m-%dT%H:%M:%SZ)
1691
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Mode: bare-metal
1692
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1693
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Security ---
1694
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_SECRET_KEY=${GEN_SECRET_KEY}
1695
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_DEBUG=false
1696
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_ALLOWED_HOSTS=${OPT_DOMAIN},localhost,127.0.0.1
1697
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_SETTINGS_MODULE=config.settings
1698
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1699
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Database ---
1700
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_DB=${OPT_DB_NAME}
1701
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_USER=${OPT_DB_USER}
1702
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_PASSWORD=${GEN_DB_PASSWORD}
1703
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_HOST=127.0.0.1
1704
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
POSTGRES_PORT=5432
1705
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1706
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Redis / Celery ---
1707
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
REDIS_URL=redis://127.0.0.1:6379/1
1708
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CELERY_BROKER=redis://127.0.0.1:6379/0
1709
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1710
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Email ---
1711
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EMAIL_HOST=localhost
1712
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EMAIL_PORT=587
1713
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
1714
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FROM_EMAIL=no-reply@${OPT_DOMAIN}
1715
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1716
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- S3 / Media ---
1717
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
USE_S3=${use_s3}
1718
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_ACCESS_KEY_ID=${OPT_S3_ACCESS_KEY}
1719
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_SECRET_ACCESS_KEY=${OPT_S3_SECRET_KEY}
1720
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_STORAGE_BUCKET_NAME=${OPT_S3_BUCKET}
1721
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_S3_ENDPOINT_URL=${OPT_S3_ENDPOINT}
1722
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1723
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- CORS / CSRF ---
1724
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CORS_ALLOWED_ORIGINS=${base_url}
1725
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CSRF_TRUSTED_ORIGINS=${base_url}
1726
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1727
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Sentry ---
1728
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
SENTRY_DSN=
1729
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1730
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- Litestream S3 Replication ---
1731
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_BUCKET=${OPT_S3_BUCKET}
1732
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_REGION=${OPT_S3_REGION:-us-east-1}
1733
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FOSSILREPO_S3_ENDPOINT=${OPT_S3_ENDPOINT}"
1734
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1735
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/.env" "$env_content" "0600"
1736
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown fossilrepo:fossilrepo "${OPT_PREFIX}/.env"
1737
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1738
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1739
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
run_django_setup() {
1740
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Running Django setup..."
1741
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1742
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local venv_activate="${OPT_PREFIX}/.venv/bin/activate"
1743
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local env_file="${OPT_PREFIX}/.env"
1744
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1745
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Migrate
1746
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Running database migrations..."
1747
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo bash -c "
1748
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
set -a; source '${env_file}'; set +a
1749
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
source '${venv_activate}'
1750
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd '${OPT_PREFIX}'
1751
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
python manage.py migrate --noinput
1752
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"
1753
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1754
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Collect static
1755
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Collecting static files..."
1756
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo bash -c "
1757
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
set -a; source '${env_file}'; set +a
1758
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
source '${venv_activate}'
1759
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd '${OPT_PREFIX}'
1760
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
python manage.py collectstatic --noinput
1761
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"
1762
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1763
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Create admin user
1764
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Creating admin user..."
1765
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo -u fossilrepo bash -c "
1766
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
set -a; source '${env_file}'; set +a
1767
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
source '${venv_activate}'
1768
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd '${OPT_PREFIX}'
1769
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
python manage.py shell -c \"
1770
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
from django.contrib.auth import get_user_model
1771
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User = get_user_model()
1772
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if not User.objects.filter(username='${OPT_ADMIN_USER}').exists():
1773
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
user = User.objects.create_superuser(
1774
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
username='${OPT_ADMIN_USER}',
1775
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
email='${OPT_ADMIN_EMAIL}',
1776
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
password='${GEN_ADMIN_PASSWORD}',
1777
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
)
1778
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
print(f'Admin user created: {user.username}')
1779
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else:
1780
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
print('Admin user already exists')
1781
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
\"
1782
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"
1783
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1784
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Django setup complete"
1785
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1786
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1787
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_caddy_bare_metal() {
1788
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Configuring Caddy..."
1789
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1790
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p /etc/caddy
1791
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_content
1792
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1793
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_SSL" == "true" && "$OPT_DOMAIN" != "localhost" ]]; then
1794
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_content="# fossilrepo Caddy config -- auto HTTPS (bare metal)
1795
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1796
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1797
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
${OPT_DOMAIN} {
1798
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
encode gzip
1799
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1800
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
handle_path /static/* {
1801
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
root * ${OPT_PREFIX}/assets
1802
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
file_server
1803
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1804
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1805
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reverse_proxy 127.0.0.1:8000
1806
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1807
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1808
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"
1809
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
1810
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_content="# fossilrepo Caddy config -- HTTP (bare metal)
1811
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1812
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1813
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
1814
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auto_https off
1815
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1816
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1817
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
:80 {
1818
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
encode gzip
1819
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1820
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
handle_path /static/* {
1821
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
root * ${OPT_PREFIX}/assets
1822
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
file_server
1823
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1824
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1825
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
reverse_proxy 127.0.0.1:8000
1826
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}"
1827
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1828
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1829
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/caddy/Caddyfile" "$caddy_content"
1830
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1831
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Caddy systemd unit
1832
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_bin
1833
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_bin="$(command -v caddy)"
1834
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1835
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local caddy_unit
1836
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
caddy_unit="[Unit]
1837
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=Caddy web server (fossilrepo)
1838
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network-online.target
1839
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Wants=network-online.target
1840
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1841
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1842
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=notify
1843
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=caddy
1844
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=caddy
1845
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=${caddy_bin} run --config /etc/caddy/Caddyfile --adapter caddyfile
1846
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecReload=${caddy_bin} reload --config /etc/caddy/Caddyfile --adapter caddyfile
1847
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
TimeoutStopSec=5s
1848
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
LimitNOFILE=1048576
1849
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
LimitNPROC=512
1850
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1851
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1852
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1853
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1854
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Create caddy user if it doesn't exist
1855
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! id caddy &>/dev/null; then
1856
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
useradd -r -m -d /var/lib/caddy -s /usr/sbin/nologin caddy
1857
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
1858
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p /var/lib/caddy/.local/share/caddy
1859
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown -R caddy:caddy /var/lib/caddy
1860
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1861
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/caddy.service" "$caddy_unit"
1862
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Caddy configured"
1863
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
1864
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1865
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
create_systemd_services() {
1866
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Creating systemd service units..."
1867
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1868
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local venv_activate="${OPT_PREFIX}/.venv/bin/activate"
1869
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local env_file="${OPT_PREFIX}/.env"
1870
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1871
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- gunicorn (fossilrepo-web) ---
1872
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local gunicorn_unit
1873
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
gunicorn_unit="[Unit]
1874
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=fossilrepo web (gunicorn)
1875
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network.target postgresql.service redis.service
1876
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Requires=postgresql.service
1877
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1878
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1879
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=notify
1880
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=fossilrepo
1881
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=fossilrepo
1882
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WorkingDirectory=${OPT_PREFIX}
1883
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EnvironmentFile=${env_file}
1884
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=${OPT_PREFIX}/.venv/bin/gunicorn config.wsgi:application \\
1885
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--bind 127.0.0.1:8000 \\
1886
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--workers 3 \\
1887
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--timeout 120 \\
1888
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--access-logfile ${LOG_DIR}/gunicorn-access.log \\
1889
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--error-logfile ${LOG_DIR}/gunicorn-error.log
1890
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecReload=/bin/kill -s HUP \$MAINPID
1891
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Restart=on-failure
1892
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RestartSec=10
1893
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
KillMode=mixed
1894
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardOutput=append:${LOG_DIR}/web.log
1895
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardError=append:${LOG_DIR}/web.log
1896
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1897
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1898
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1899
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1900
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/fossilrepo-web.service" "$gunicorn_unit"
1901
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1902
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- celery worker ---
1903
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local celery_worker_unit
1904
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
celery_worker_unit="[Unit]
1905
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=fossilrepo Celery worker
1906
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network.target postgresql.service redis.service
1907
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Requires=redis.service
1908
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1909
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1910
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=forking
1911
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=fossilrepo
1912
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=fossilrepo
1913
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WorkingDirectory=${OPT_PREFIX}
1914
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EnvironmentFile=${env_file}
1915
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=${OPT_PREFIX}/.venv/bin/celery -A config.celery worker \\
1916
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-l info \\
1917
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-Q celery \\
1918
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--detach \\
1919
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--pidfile=${OPT_PREFIX}/celery-worker.pid \\
1920
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--logfile=${LOG_DIR}/celery-worker.log
1921
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStop=/bin/kill -s TERM \$(cat ${OPT_PREFIX}/celery-worker.pid)
1922
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PIDFile=${OPT_PREFIX}/celery-worker.pid
1923
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Restart=on-failure
1924
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RestartSec=10
1925
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1926
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1927
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1928
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1929
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/fossilrepo-celery-worker.service" "$celery_worker_unit"
1930
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1931
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- celery beat ---
1932
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local celery_beat_unit
1933
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
celery_beat_unit="[Unit]
1934
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=fossilrepo Celery beat scheduler
1935
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network.target postgresql.service redis.service
1936
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Requires=redis.service
1937
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1938
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1939
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=forking
1940
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=fossilrepo
1941
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=fossilrepo
1942
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WorkingDirectory=${OPT_PREFIX}
1943
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EnvironmentFile=${env_file}
1944
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=${OPT_PREFIX}/.venv/bin/celery -A config.celery beat \\
1945
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-l info \\
1946
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--scheduler django_celery_beat.schedulers:DatabaseScheduler \\
1947
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--detach \\
1948
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--pidfile=${OPT_PREFIX}/celery-beat.pid \\
1949
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--logfile=${LOG_DIR}/celery-beat.log
1950
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStop=/bin/kill -s TERM \$(cat ${OPT_PREFIX}/celery-beat.pid)
1951
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
PIDFile=${OPT_PREFIX}/celery-beat.pid
1952
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Restart=on-failure
1953
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RestartSec=10
1954
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1955
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1956
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1957
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1958
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/fossilrepo-celery-beat.service" "$celery_beat_unit"
1959
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1960
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# --- litestream (optional) ---
1961
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" ]]; then
1962
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local litestream_unit
1963
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
litestream_unit="[Unit]
1964
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=fossilrepo Litestream replication
1965
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network.target
1966
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1967
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
1968
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Type=simple
1969
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=fossilrepo
1970
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=fossilrepo
1971
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EnvironmentFile=${env_file}
1972
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=/usr/local/bin/litestream replicate -config ${OPT_PREFIX}/litestream.yml
1973
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Restart=on-failure
1974
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RestartSec=10
1975
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardOutput=append:${LOG_DIR}/litestream.log
1976
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardError=append:${LOG_DIR}/litestream.log
1977
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1978
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
1979
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target"
1980
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1981
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generate litestream config for bare metal
1982
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local ls_content
1983
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ls_content="# Litestream replication -- continuous .fossil backup to S3
1984
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer
1985
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1986
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
dbs:
1987
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- path: ${DATA_DIR}/repos/*.fossil
1988
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
replicas:
1989
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- type: s3
1990
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bucket: ${OPT_S3_BUCKET}
1991
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
endpoint: ${OPT_S3_ENDPOINT}
1992
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
region: ${OPT_S3_REGION:-us-east-1}
1993
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
access-key-id: \${AWS_ACCESS_KEY_ID}
1994
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
secret-access-key: \${AWS_SECRET_ACCESS_KEY}"
1995
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1996
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/litestream.yml" "$ls_content"
1997
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown fossilrepo:fossilrepo "${OPT_PREFIX}/litestream.yml"
1998
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/systemd/system/fossilrepo-litestream.service" "$litestream_unit"
1999
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2000
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2001
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Reload systemd and enable all services
2002
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl daemon-reload
2003
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable fossilrepo-web.service
2004
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable fossilrepo-celery-worker.service
2005
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable fossilrepo-celery-beat.service
2006
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable caddy.service
2007
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$OPT_S3_BUCKET" ]] && systemctl enable fossilrepo-litestream.service
2008
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2009
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Start services
2010
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start caddy.service
2011
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start fossilrepo-web.service
2012
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start fossilrepo-celery-worker.service
2013
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start fossilrepo-celery-beat.service
2014
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ -n "$OPT_S3_BUCKET" ]] && systemctl start fossilrepo-litestream.service
2015
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2016
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "All systemd services created and started"
2017
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2018
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2019
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_logrotate() {
2020
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Configuring log rotation..."
2021
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2022
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local logrotate_content
2023
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
logrotate_content="${LOG_DIR}/*.log {
2024
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
daily
2025
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
missingok
2026
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rotate 14
2027
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
compress
2028
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
delaycompress
2029
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
notifempty
2030
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
create 0640 fossilrepo fossilrepo
2031
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sharedscripts
2032
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
postrotate
2033
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl reload fossilrepo-web.service 2>/dev/null || true
2034
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
endscript
2035
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}"
2036
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2037
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "/etc/logrotate.d/fossilrepo" "$logrotate_content"
2038
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Log rotation configured (14 days, compressed)"
2039
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2040
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2041
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_bare_metal() {
2042
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Installing fossilrepo (Bare Metal mode)"
2043
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2044
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
create_system_user
2045
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
clone_repo
2046
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_python_venv
2047
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_postgres
2048
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_redis
2049
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_bare_metal_env
2050
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
run_django_setup
2051
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_caddy_bare_metal
2052
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
create_systemd_services
2053
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
setup_logrotate
2054
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2055
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Bare metal installation complete"
2056
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2057
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2058
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2059
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 11: Uninstall Generator
2060
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2061
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2062
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_uninstall_script() {
2063
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_info "Generating uninstall script..."
2064
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2065
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local uninstall_content
2066
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
uninstall_content="#!/usr/bin/env bash
2067
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# fossilrepo uninstaller
2068
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generated by installer on $(date -u +%Y-%m-%dT%H:%M:%SZ)
2069
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Mode: ${OPT_MODE}
2070
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2071
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
set -euo pipefail
2072
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2073
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'fossilrepo uninstaller'
2074
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo '======================'
2075
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2076
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'This will remove all fossilrepo services, files, and data.'
2077
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'PostgreSQL data and Fossil repositories will be DELETED.'
2078
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2079
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
read -p 'Are you sure? Type YES to confirm: ' confirm
2080
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ \"\$confirm\" == \"YES\" ]] || { echo 'Aborted.'; exit 1; }"
2081
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2082
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "docker" ]]; then
2083
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
uninstall_content+="
2084
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2085
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Stopping Docker services (preserving volumes)...'
2086
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd '${OPT_PREFIX}'
2087
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose down 2>/dev/null || true
2088
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2089
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2090
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' NOTE: Docker volumes have been preserved.'
2091
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' To remove them (DELETES ALL DATA): docker volume prune'
2092
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2093
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2094
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing systemd service...'
2095
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop fossilrepo.service 2>/dev/null || true
2096
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl disable fossilrepo.service 2>/dev/null || true
2097
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/fossilrepo.service
2098
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl daemon-reload
2099
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing application code (preserving .env backup)...'
2101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f '${OPT_PREFIX}/.env' '/tmp/fossilrepo-env.bak' 2>/dev/null || true
2102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f '${OPT_PREFIX}/.credentials' '/tmp/fossilrepo-creds.bak' 2>/dev/null || true
2103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf '${OPT_PREFIX}'
2104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' Backup of .env saved to /tmp/fossilrepo-env.bak'
2105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Done. Docker volumes and images may still be cached.'
2107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' To remove volumes (DELETES DATA): docker volume prune'
2108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' To remove images: docker system prune'"
2109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
uninstall_content+="
2111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Stopping services...'
2113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop fossilrepo-web.service 2>/dev/null || true
2114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop fossilrepo-celery-worker.service 2>/dev/null || true
2115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop fossilrepo-celery-beat.service 2>/dev/null || true
2116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop fossilrepo-litestream.service 2>/dev/null || true
2117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop caddy.service 2>/dev/null || true
2118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Disabling services...'
2120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl disable fossilrepo-web.service 2>/dev/null || true
2121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl disable fossilrepo-celery-worker.service 2>/dev/null || true
2122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl disable fossilrepo-celery-beat.service 2>/dev/null || true
2123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl disable fossilrepo-litestream.service 2>/dev/null || true
2124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing systemd units...'
2126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/fossilrepo-web.service
2127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/fossilrepo-celery-worker.service
2128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/fossilrepo-celery-beat.service
2129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/fossilrepo-litestream.service
2130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/systemd/system/caddy.service
2131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl daemon-reload
2132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing Caddy config...'
2134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/caddy/Caddyfile
2135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing logrotate config...'
2137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -f /etc/logrotate.d/fossilrepo
2138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing log files...'
2140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf '${LOG_DIR}'
2141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2143
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo '================================================================'
2144
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' DATA PRESERVATION NOTICE'
2145
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo '================================================================'
2146
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2147
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' The following data has been PRESERVED (not deleted):'
2148
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2149
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' Fossil repositories: ${DATA_DIR}/repos/'
2150
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' PostgreSQL database: ${OPT_DB_NAME} (user: ${OPT_DB_USER})'
2151
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' Git mirrors: ${DATA_DIR}/git-mirrors/'
2152
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' SSH keys: ${DATA_DIR}/ssh/'
2153
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2154
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' To remove the database:'
2155
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' sudo -u postgres psql -c \"DROP DATABASE IF EXISTS ${OPT_DB_NAME};\"'
2156
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' sudo -u postgres psql -c \"DROP USER IF EXISTS ${OPT_DB_USER};\"'
2157
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2158
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' To remove repo data (IRREVERSIBLE):'
2159
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' rm -rf ${DATA_DIR}/repos'
2160
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' rm -rf ${DATA_DIR}/git-mirrors'
2161
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' rm -rf ${DATA_DIR}/ssh'
2162
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2163
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' These are left intact so you can back them up or migrate.'
2164
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo '================================================================'
2165
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2166
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing application code (preserving .env backup)...'
2167
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f '${OPT_PREFIX}/.env' '/tmp/fossilrepo-env.bak' 2>/dev/null || true
2168
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cp -f '${OPT_PREFIX}/.credentials' '/tmp/fossilrepo-creds.bak' 2>/dev/null || true
2169
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf '${OPT_PREFIX}'
2170
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ' Backup of .env saved to /tmp/fossilrepo-env.bak'
2171
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2172
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Removing system user...'
2173
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
userdel -r fossilrepo 2>/dev/null || true
2174
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2175
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'Done. System packages (PostgreSQL, Redis, Fossil, Caddy) were NOT removed.'"
2176
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2177
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2178
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
uninstall_content+="
2179
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2180
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo ''
2181
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
echo 'fossilrepo has been uninstalled.'"
2182
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2183
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/uninstall.sh" "$uninstall_content" "0755"
2184
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_ok "Uninstall script: ${OPT_PREFIX}/uninstall.sh"
2185
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2186
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2187
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2188
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 12: Post-Install Summary
2189
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2190
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2191
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_summary() {
2192
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local proto="http"
2193
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[[ "$OPT_SSL" == "true" ]] && proto="https"
2194
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local base_url="${proto}://${OPT_DOMAIN}"
2195
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2196
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_DOMAIN" == "localhost" && "$OPT_PORT" != "80" && "$OPT_PORT" != "443" ]]; then
2197
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
base_url="${proto}://localhost:${OPT_PORT}"
2198
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2199
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2200
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local box_width=64
2201
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local border
2202
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
border="$(printf '%*s' $box_width '' | tr ' ' '=')"
2203
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2204
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2205
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_GREEN}${_C_BOLD}"
2206
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %s\n" "$border"
2207
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-${box_width}s\n" " fossilrepo installation complete"
2208
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %s\n" "$border"
2209
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_RESET}"
2210
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2211
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Web UI:" "${base_url}"
2212
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Django Admin:" "${base_url}/admin/"
2213
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Health Check:" "${base_url}/health/"
2214
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2215
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Admin username:" "$OPT_ADMIN_USER"
2216
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Admin email:" "$OPT_ADMIN_EMAIL"
2217
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Admin password:" "$GEN_ADMIN_PASSWORD"
2218
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2219
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2220
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_DOMAIN" != "localhost" ]]; then
2221
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "SSH clone:" "ssh://fossil@${OPT_DOMAIN}:2222/<repo>"
2222
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2223
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2224
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Install mode:" "$OPT_MODE"
2225
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Install prefix:" "$OPT_PREFIX"
2226
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Config file:" "${OPT_PREFIX}/.env"
2227
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}%-24s${_C_RESET} %s\n" "Uninstall:" "${OPT_PREFIX}/uninstall.sh"
2228
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2229
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2230
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "docker" ]]; then
2231
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}Useful commands:${_C_RESET}\n"
2232
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " cd %s\n" "$OPT_PREFIX"
2233
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " docker compose logs -f # tail all logs\n"
2234
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " docker compose logs -f app # tail app logs\n"
2235
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " docker compose exec app bash # shell into app container\n"
2236
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " docker compose restart # restart all services\n"
2237
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " docker compose down # stop all services\n"
2238
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2239
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}Useful commands:${_C_RESET}\n"
2240
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " systemctl status fossilrepo-web # check web status\n"
2241
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " journalctl -u fossilrepo-web -f # tail web logs\n"
2242
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " journalctl -u fossilrepo-celery-worker -f # tail worker logs\n"
2243
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " systemctl restart fossilrepo-web # restart web\n"
2244
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " tail -f %s/*.log # tail log files\n" "$LOG_DIR"
2245
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2246
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2247
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2248
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2249
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" ]]; then
2250
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " ${_C_BOLD}Litestream backup:${_C_RESET} s3://%s\n" "$OPT_S3_BUCKET"
2251
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2252
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2253
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "${_C_YELLOW} IMPORTANT: Save the admin password above -- it will not be shown again.${_C_RESET}\n"
2254
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2255
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2256
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Write credentials to a restricted file for reference
2257
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
local creds_content
2258
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
creds_content="# fossilrepo credentials -- generated $(date -u +%Y-%m-%dT%H:%M:%SZ)
2259
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# KEEP THIS FILE SECURE -- delete after recording credentials elsewhere
2260
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2261
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ADMIN_USER=${OPT_ADMIN_USER}
2262
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ADMIN_EMAIL=${OPT_ADMIN_EMAIL}
2263
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ADMIN_PASSWORD=${GEN_ADMIN_PASSWORD}
2264
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DB_PASSWORD=${GEN_DB_PASSWORD}
2265
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
DJANGO_SECRET_KEY=${GEN_SECRET_KEY}"
2266
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2267
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
write_file "${OPT_PREFIX}/.credentials" "$creds_content" "0600"
2268
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "bare-metal" ]]; then
2269
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown fossilrepo:fossilrepo "${OPT_PREFIX}/.credentials"
2270
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2271
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " Credentials also saved to: ${_C_BOLD}%s/.credentials${_C_RESET} (mode 0600)\n" "$OPT_PREFIX"
2272
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2273
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2274
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2275
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2276
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Section 13: Validation + Secret Generation + Main Dispatcher
2277
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# ============================================================================
2278
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2279
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
validate_options() {
2280
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Validate mode
2281
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
case "$OPT_MODE" in
2282
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker|bare-metal) ;;
2283
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
*) die "Invalid mode: '$OPT_MODE'. Must be 'docker' or 'bare-metal'." ;;
2284
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
esac
2285
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2286
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Validate port
2287
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if ! [[ "$OPT_PORT" =~ ^[0-9]+$ ]] || ((OPT_PORT < 1 || OPT_PORT > 65535)); then
2288
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Invalid port: $OPT_PORT"
2289
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2290
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2291
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Validate domain (basic check)
2292
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -z "$OPT_DOMAIN" ]]; then
2293
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
die "Domain must not be empty"
2294
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2295
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2296
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Default admin email
2297
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -z "$OPT_ADMIN_EMAIL" ]]; then
2298
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_ADMIN_EMAIL="${OPT_ADMIN_USER}@${OPT_DOMAIN}"
2299
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2300
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2301
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# S3: if bucket is set, region should be too
2302
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" && -z "$OPT_S3_REGION" ]]; then
2303
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_S3_REGION="us-east-1"
2304
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2305
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2306
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Warn about SSL on localhost
2307
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_SSL" == "true" && ( "$OPT_DOMAIN" == "localhost" || "$OPT_DOMAIN" == "127.0.0.1" ) ]]; then
2308
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_warn "SSL is enabled but domain is '$OPT_DOMAIN' -- Let's Encrypt will not work. Disabling SSL."
2309
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
OPT_SSL="false"
2310
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2311
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2312
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2313
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auto_generate_secrets() {
2314
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Generate any secrets not provided by the user
2315
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_SECRET_KEY="$(generate_secret_key)"
2316
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Generated Django secret key"
2317
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2318
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_DB_PASSWORD" ]]; then
2319
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_DB_PASSWORD="$OPT_DB_PASSWORD"
2320
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2321
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_DB_PASSWORD="$(generate_password 32)"
2322
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Generated database password"
2323
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2324
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2325
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_ADMIN_PASSWORD" ]]; then
2326
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_ADMIN_PASSWORD="$OPT_ADMIN_PASSWORD"
2327
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2328
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
GEN_ADMIN_PASSWORD="$(generate_password 24)"
2329
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
verbose "Generated admin password"
2330
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2331
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2332
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2333
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_config_summary() {
2334
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2335
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
log_step "Configuration"
2336
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Mode:" "$OPT_MODE"
2337
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Domain:" "$OPT_DOMAIN"
2338
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "SSL:" "$OPT_SSL"
2339
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Port:" "$OPT_PORT"
2340
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Install prefix:" "$OPT_PREFIX"
2341
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Database:" "${OPT_DB_NAME} (user: ${OPT_DB_USER})"
2342
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "Admin:" "${OPT_ADMIN_USER} <${OPT_ADMIN_EMAIL}>"
2343
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -n "$OPT_S3_BUCKET" ]]; then
2344
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s (region: %s)\n" "S3 backup:" "$OPT_S3_BUCKET" "${OPT_S3_REGION:-us-east-1}"
2345
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2346
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf " %-24s %s\n" "S3 backup:" "disabled"
2347
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2348
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
printf "\n"
2349
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2350
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2351
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
main() {
2352
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
_color_init
2353
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
parse_args "$@"
2354
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
require_root
2355
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
detect_os
2356
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2357
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Run interactive TUI if mode is not set
2358
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ -z "$OPT_MODE" ]]; then
2359
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
run_interactive
2360
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2361
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2362
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
validate_options
2363
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auto_generate_secrets
2364
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_config_summary
2365
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
confirm "Begin installation?"
2366
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
check_and_install_deps
2367
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2368
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
if [[ "$OPT_MODE" == "docker" ]]; then
2369
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_docker
2370
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
else
2371
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install_bare_metal
2372
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fi
2373
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2374
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
generate_uninstall_script
2375
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
show_summary
2376
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
2377
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2378
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
main "$@"
2379
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!