-
Notifications
You must be signed in to change notification settings - Fork 36
/
essl.sh
250 lines (206 loc) · 7.59 KB
/
essl.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#!/bin/bash
# Function definitions for colored output
colors=( "\033[1;31m" "\033[1;35m" "\033[1;92m" "\033[38;5;46m" "\033[1;38;5;208m" "\033[1;36m" "\033[0m" )
red=${colors[0]} pink=${colors[1]} green=${colors[2]} spring=${colors[3]} orange=${colors[4]} cyan=${colors[5]} reset=${colors[6]}
print() { echo -e "${cyan}$1${reset}"; }
error() { echo -e "${red}✗ $1${reset}"; }
success() { echo -e "${spring}✓ $1${reset}"; }
log() { echo -e "${green}! $1${reset}"; }
warn() { echo -e "${orange} $1${reset}"; }
# Trap for script interruption
trap 'echo -e "\n${red}Script interrupted!${reset}"; exit 1' SIGINT
# Validate domain format
validate_domain() {
if [[ ! "$1" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
error "Invalid domain format: $1"
return 1
fi
return 0
}
# Function to install necessary dependencies
install_dependencies() {
local pkg_manager
if command -v apt-get &> /dev/null; then
pkg_manager="apt-get"
elif command -v dnf &> /dev/null; then
pkg_manager="dnf"
elif command -v yum &> /dev/null; then
pkg_manager="yum"
else
error "No supported package manager found. Please install packages manually."
exit 1
fi
log "Updating package lists..."
$pkg_manager update -y || warn "Failed to update package lists."
local packages=("curl" "socat" "certbot")
for pkg in "${packages[@]}"; do
if ! command -v "$pkg" &> /dev/null; then
log "Installing $pkg..."
$pkg_manager install -y "$pkg" || error "Failed to install $pkg"
fi
done
if ! command -v acme.sh &> /dev/null; then
log "Installing acme.sh..."
curl https://get.acme.sh | sh -s email="$email" || error "Failed to install acme.sh"
source ~/.bashrc
fi
success "Dependencies are installed."
}
# Function to obtain and install SSL certificate using acme.sh for multiple domains
get_install_certificate_acme() {
local domains=("$@")
local domain_args=""
local main_domain="${domains[0]}"
for domain in "${domains[@]}"; do
domain=$(echo "$domain" | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//")
domain_args+=" -d $domain"
done
~/.acme.sh/acme.sh --issue --standalone $domain_args --accountemail "$email" || return 1
local cert_dir="$destination"
mkdir -p "$cert_dir" || error "Failed to create certificate directory"
~/.acme.sh/acme.sh --install-cert -d "$main_domain" \
--key-file "$cert_dir/privkey.pem" \
--fullchain-file "$cert_dir/fullchain.pem" || return 1
success "SSL certificate obtained and installed using acme.sh for domains: ${domains[*]}"
return 0
}
# Function to obtain and install SSL certificate using certbot for multiple domains
get_install_certificate_certbot() {
local domains=("$@")
local domain_args=""
for domain in "${domains[@]}"; do
domain=$(echo "$domain" | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//")
domain_args+=" -d $domain"
done
certbot certonly --standalone $domain_args --non-interactive --agree-tos --email "$email" || return 1
local main_domain="${domains[0]}"
local cert_dir="$destination"
mkdir -p "$cert_dir" || error "Failed to create certificate directory"
cat /etc/letsencrypt/live/$main_domain/privkey.pem > "$cert_dir/privkey.pem"
cat /etc/letsencrypt/live/$main_domain/fullchain.pem > "$cert_dir/fullchain.pem"
success "SSL certificate obtained and installed using certbot for domains: ${domains[*]}"
return 0
}
# Function to install the ESSL script
install_script() {
log "Installing ESSL script..."
local install_dir="/usr/local/bin"
local script_path="$install_dir/essl"
curl -s -o "$script_path" https://raw.githubusercontent.com/erfjab/ESSL/master/essl.sh
chmod +x "$script_path"
success "ESSL script installed successfully."
}
# Function to upgrade the ESSL script
upgrade_script() {
log "Upgrading ESSL script..."
local install_dir="/usr/local/bin"
local script_path="$install_dir/essl"
if [ -f "$script_path" ]; then
curl -s -o "$script_path" https://raw.githubusercontent.com/erfjab/ESSL/master/essl.sh
chmod +x "$script_path"
success "ESSL script upgraded successfully."
else
error "ESSL script not found. Use '--install' to install it first."
fi
}
# Function to display help message
show_help() {
cat << EOF
Usage: essl [email] [domain1 domain2 ...] <destination> | --install | --upgrade
Email:
Provide an email address to use with acme.sh and certbot.
Domains:
You can provide one or more domains.
Destination:
Use 'marzban', 'marzneshin', 'x-ui', '3x-ui', 's-ui', or 'hiddify' for predefined paths,
or provide a custom path starting with '/'.
Commands:
--install Install the ESSL script.
--upgrade Upgrade the ESSL script to the latest version.
--help Show this help message.
--version Show script version
Examples:
essl [email protected] example.com /etc/ssl/certs
essl [email protected] domain1.com domain2.com domain3.com /custom/path
essl --install
essl --upgrade
Note: This script must be run as root.
EOF
}
# Main function to handle the script logic
main() {
[ "$EUID" -eq 0 ] || { error "This script must be run as root."; exit 1; }
# Handle --install and --upgrade options
case "$1" in
--install)
install_script
exit 0
;;
--upgrade)
upgrade_script
exit 0
;;
--help|-h)
show_help
exit 0
;;
--version|-v)
print "currect essl version: v3.1.2"
exit 0
;;esac
# Check if user provided enough arguments for SSL installation
if [ $# -lt 3 ]; then
error "Not enough arguments provided. Use 'essl --help' for more details."
exit 1
fi
# Get email and domain arguments
email="$1"
shift
local destination="${@: -1}"
local domains=("${@:1:$#-1}")
# Validate and handle the domains
for domain in "${domains[@]}"; do
validate_domain "$domain" || exit 1
done
# Set predefined paths if necessary
case "$destination" in
marzban) base_destination="/var/lib/marzban/certs" ;;
marzneshin) base_destination="/var/lib/marzneshin/certs" ;;
x-ui|3x-ui|s-ui|hiddify) base_destination="/certs" ;;
*)
if [[ "$destination" != /* ]]; then
error "Invalid destination path. Must start with '/'"
exit 1
fi
base_destination="$destination"
;;
esac
[[ "$destination" != */ ]] && destination="${destination}/"
# Install dependencies
install_dependencies
# Create subdirectory using the first domain
first_domain="${domains[0]}"
destination="${base_destination}/${first_domain}/"
# Try acme.sh first
if get_install_certificate_acme "${domains[@]}"; then
log "Certificate successfully obtained using acme.sh"
else
warn "Failed to obtain certificate using acme.sh. Trying certbot..."
if get_install_certificate_certbot "${domains[@]}"; then
log "Certificate successfully obtained using certbot"
else
error "Failed to obtain certificate using both acme.sh and certbot"
exit 1
fi
fi
# Display final certificate path
success "Certificate files are located at:"
print "⭐ Private key: ${destination}privkey.pem"
print "⭐ Full chain: ${destination}fullchain.pem"
}
# If no arguments are provided, show help
if [ $# -eq 0 ]; then
show_help
else
main "$@"
fi