550
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
# Updates APT packages and installs required system dependencies.
|
||||
function systemApt() {
|
||||
apt update && apt upgrade -y || return 1
|
||||
apt install -y curl ipset iptables-persistent ipset-persistent jq zip mc nano idn2 acl xfsprogs opendkim-tools pigz
|
||||
}
|
||||
|
||||
# Creates ipset sets for WEDOS, WEDOS Global, and whitelist traffic, and installs an hourly update cron job.
|
||||
function systemIpset() {
|
||||
ipset list wedos &>/dev/null || ipset create wedos hash:ip family inet || {
|
||||
appError "Failed create ipset: wedos"
|
||||
return 1
|
||||
}
|
||||
ipset list wedos6 &>/dev/null || ipset create wedos6 hash:ip family inet6 || {
|
||||
appError "Failed create ipset: wedos6"
|
||||
return 1
|
||||
}
|
||||
ipset list wedos-global &>/dev/null || ipset create wedos-global hash:net family inet || {
|
||||
appError "Failed create ipset: wedos-global"
|
||||
return 1
|
||||
}
|
||||
ipset list wedos-global6 &>/dev/null || ipset create wedos-global6 hash:net family inet6 || {
|
||||
appError "Failed create ipset: wedos-global6"
|
||||
return 1
|
||||
}
|
||||
ipset list whitelist &>/dev/null || ipset create whitelist hash:ip family inet || {
|
||||
appError "Failed create ipset: whitelist"
|
||||
return 1
|
||||
}
|
||||
ipset list whitelist6 &>/dev/null || ipset create whitelist6 hash:ip family inet6 || {
|
||||
appError "Failed create ipset: whitelist6"
|
||||
return 1
|
||||
}
|
||||
|
||||
ipset add wedos 46.28.104.66 -exist
|
||||
ipset add wedos 46.28.107.200 -exist
|
||||
ipset add wedos 46.28.104.146 -exist
|
||||
ipset add wedos 46.28.107.215 -exist
|
||||
|
||||
local cron="/etc/cron.d/wedos-global-update"
|
||||
local job='0 * * * * root curl -fsSL https://ips.wedos.global/ips.json | jq -r '"'"'.list[]'"'"' | while read -r ip; do [[ "$ip" == *:* ]] && ipset add wedos-global6 "$ip" -exist || ipset add wedos-global "$ip" -exist; done >> /var/log/wedos-ipset-update.log 2>&1'
|
||||
printf '%s\n' "$job" > "$cron" || {
|
||||
appError "Failed write cron file: $cron"
|
||||
return 1
|
||||
}
|
||||
chmod 644 "$cron" || {
|
||||
appError "Failed chmod cron file: $cron"
|
||||
return 1
|
||||
}
|
||||
|
||||
(set -o pipefail; curl -fsSL https://ips.wedos.global/ips.json | jq -r '.list[]' | while read -r ip; do
|
||||
[[ "$ip" == *:* ]] && ipset add wedos-global6 "$ip" -exist || ipset add wedos-global "$ip" -exist
|
||||
done) >> /var/log/wedos-ipset-update.log 2>&1 || appError "Failed to update WEDOS Global IP sets."
|
||||
}
|
||||
|
||||
# Installs persistent iptables and ip6tables INPUT rules, then saves and reloads via netfilter-persistent.
|
||||
function systemIptables() {
|
||||
iptables -C INPUT -m set --match-set wedos src -j ACCEPT 2>/dev/null || iptables -I INPUT 1 -m set --match-set wedos src -j ACCEPT
|
||||
ip6tables -C INPUT -m set --match-set wedos6 src -j ACCEPT 2>/dev/null || ip6tables -I INPUT 1 -m set --match-set wedos6 src -j ACCEPT
|
||||
|
||||
iptables -C INPUT -m set --match-set wedos-global src -p tcp -m multiport --dports 80,443 -j ACCEPT 2>/dev/null || \
|
||||
iptables -I INPUT 2 -m set --match-set wedos-global src -p tcp -m multiport --dports 80,443 -j ACCEPT
|
||||
ip6tables -C INPUT -m set --match-set wedos-global6 src -p tcp -m multiport --dports 80,443 -j ACCEPT 2>/dev/null || \
|
||||
ip6tables -I INPUT 2 -m set --match-set wedos-global6 src -p tcp -m multiport --dports 80,443 -j ACCEPT
|
||||
|
||||
iptables -C INPUT -m set --match-set whitelist src -p tcp -m multiport --dports 80,443 -j ACCEPT 2>/dev/null || \
|
||||
iptables -I INPUT 3 -m set --match-set whitelist src -p tcp -m multiport --dports 80,443 -j ACCEPT
|
||||
ip6tables -C INPUT -m set --match-set whitelist6 src -p tcp -m multiport --dports 80,443 -j ACCEPT 2>/dev/null || \
|
||||
ip6tables -I INPUT 3 -m set --match-set whitelist6 src -p tcp -m multiport --dports 80,443 -j ACCEPT
|
||||
|
||||
iptables -C INPUT -i lo -j ACCEPT 2>/dev/null || iptables -I INPUT 4 -i lo -j ACCEPT
|
||||
ip6tables -C INPUT -i lo -j ACCEPT 2>/dev/null || ip6tables -I INPUT 4 -i lo -j ACCEPT
|
||||
|
||||
iptables -C INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || \
|
||||
iptables -I INPUT 5 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
ip6tables -C INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || \
|
||||
ip6tables -I INPUT 5 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
iptables -C INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT 2>/dev/null || \
|
||||
iptables -I INPUT 6 -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
|
||||
ip6tables -C INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT 2>/dev/null || \
|
||||
ip6tables -I INPUT 6 -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
|
||||
|
||||
iptables -C INPUT -j DROP 2>/dev/null || iptables -A INPUT -j DROP
|
||||
ip6tables -C INPUT -j DROP 2>/dev/null || ip6tables -A INPUT -j DROP
|
||||
|
||||
netfilter-persistent save || return 1
|
||||
netfilter-persistent reload || return 1
|
||||
}
|
||||
|
||||
# Returns non-empty root crontab lines; empty result if no crontab exists.
|
||||
function systemCronList() {
|
||||
local result
|
||||
if result="$(crontab -u root -l 2>&1)"; then
|
||||
:
|
||||
elif grep -qi 'no crontab for' <<< "$result"; then
|
||||
result=""
|
||||
else
|
||||
appError "Failed to retrieve cron jobs: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$result" | awk 'NF'
|
||||
}
|
||||
|
||||
# Returns the IP address for a domain from /etc/hosts.
|
||||
# $1 (domain): domain name to look up.
|
||||
function systemHostGet() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
awk -v domain="$domain" '
|
||||
$1 !~ /^#/ {
|
||||
for (i = 2; i <= NF; i++) {
|
||||
if ($i == domain) {
|
||||
print $1
|
||||
exit
|
||||
}
|
||||
}
|
||||
}
|
||||
' /etc/hosts
|
||||
}
|
||||
|
||||
# Adds a domain entry to /etc/hosts if not already present.
|
||||
# $1 (domain): site domain name.
|
||||
# [$2] (ip): IP address (defaults to 127.0.0.1).
|
||||
function systemHostAdd() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local ip="${2:-127.0.0.1}"
|
||||
|
||||
if ! awk -v ip="$ip" -v domain="$domain" '$1 == ip && $2 == domain { found=1 } END { exit !found }' /etc/hosts; then
|
||||
printf '%s %s\n' "$ip" "$domain" >> /etc/hosts || {
|
||||
appError "Failed writing hosts"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
# Removes a domain entry from /etc/hosts.
|
||||
# $1 (domain): site domain name.
|
||||
# [$2] (ip): IP address (defaults to 127.0.0.1).
|
||||
function systemHostRemove() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local ip="${2:-127.0.0.1}"
|
||||
|
||||
local tmp
|
||||
tmp=$(mktemp) || return 1
|
||||
|
||||
if ! awk -v ip="$ip" -v domain="$domain" '!($1 == ip && $2 == domain)' /etc/hosts > "$tmp"; then
|
||||
rm -f "$tmp"
|
||||
appError "Failed editing hosts"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mv -- "$tmp" /etc/hosts || {
|
||||
rm -f "$tmp"
|
||||
appError "Failed writing hosts"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
# Lists users in the SFTP access group.
|
||||
function sftpUserList() {
|
||||
getent group "$sftpAccessGroup" | awk -F: '{print $4}' | tr ',' '\n' | sed '/^$/d' | sort
|
||||
}
|
||||
|
||||
# Sets the SFTP password for a domain user from site config.
|
||||
function sftpPasswordSet() {
|
||||
local domain="$1"
|
||||
domain=$(domainPrepare "$domain")
|
||||
domainCheck "$domain" || return 1
|
||||
[[ -n "$domain" && "$domain" != "root" ]] || { appError "Incorrect or empty domain: $domain"; return 1; }
|
||||
|
||||
local ug sftpPass
|
||||
ug=$(domainToUser "$domain")
|
||||
|
||||
id "$ug" >/dev/null 2>&1 || { appError "User does not exist: $ug"; return 1; }
|
||||
sftpPass=$(siteConfigGetOrCreate "$domain" "sftpPass")
|
||||
[[ -n "$sftpPass" ]] || { appError "SFTP password is empty for domain: $domain"; return 1; }
|
||||
|
||||
printf '%s:%s\n' "$ug" "$sftpPass" | chpasswd || { appError "Change SFTP password failed for user: $ug"; return 1; }
|
||||
}
|
||||
|
||||
# Enables SFTP access for a domain user.
|
||||
function sftpAccessEnable() {
|
||||
local domain="$1"
|
||||
domain=$(domainPrepare "$domain")
|
||||
domainCheck "$domain" || return 1
|
||||
[[ -n "$domain" && "$domain" != "root" ]] || { appError "Incorrect or empty domain: $domain"; return 1; }
|
||||
|
||||
local output error ug
|
||||
ug=$(domainToUser "$domain")
|
||||
id "$ug" >/dev/null 2>&1 || { appError "User does not exist: $ug"; return 1; }
|
||||
[[ -d "$olsVhostsPath/$domain/www" ]] || { appError "Vhost www directory does not exist: $olsVhostsPath/$domain/www"; return 1; }
|
||||
|
||||
if ! id -nG "$ug" | tr ' ' '\n' | grep -Fxq "$sftpAccessGroup"; then
|
||||
run output error usermod -aG "$sftpAccessGroup" "$ug" || { appError "Add user $ug to $sftpAccessGroup: $error"; return 1; }
|
||||
fi
|
||||
|
||||
sftpPasswordSet "$domain"
|
||||
}
|
||||
|
||||
# Disables SFTP access for a domain user by removing them from the SFTP group.
|
||||
function sftpAccessDisable() {
|
||||
local domain="$1"
|
||||
domain=$(domainPrepare "$domain")
|
||||
domainCheck "$domain" || return 1
|
||||
[[ -n "$domain" && "$domain" != "root" ]] || { appError "Incorrect or empty domain: $domain"; return 1; }
|
||||
|
||||
local output error ug
|
||||
ug=$(domainToUser "$domain")
|
||||
id "$ug" >/dev/null 2>&1 || { appError "User does not exist: $ug"; return 1; }
|
||||
|
||||
if id -nG "$ug" | tr ' ' '\n' | grep -Fxq "$sftpAccessGroup"; then
|
||||
run output error gpasswd -d "$ug" "$sftpAccessGroup" || { appError "Remove user $ug from $sftpAccessGroup: $error"; return 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# [WARNING] Patches sshd_config to enable SFTP via internal-sftp with group-based chroot.
|
||||
function sftpAddingSupport() {
|
||||
local sftpConfig="/etc/ssh/sshd_config"
|
||||
local sshService sshdBin sftpBackup output error
|
||||
|
||||
# printInfo "$systemLabel SFTP Adding support for SFTP access"
|
||||
[[ -f "$sftpConfig" ]] || { appError "SFTP Config not found: $sftpConfig"; return 1; }
|
||||
|
||||
if systemctl list-unit-files | grep -q '^sshd\.service'; then
|
||||
sshService="sshd"
|
||||
elif systemctl list-unit-files | grep -q '^ssh\.service'; then
|
||||
sshService="ssh"
|
||||
else
|
||||
appError "SFTP Service not found"
|
||||
return 1
|
||||
fi
|
||||
# printInfo "$systemLabel SFTP Use service: $sshService"
|
||||
|
||||
sshdBin="$(command -v sshd || true)"
|
||||
[[ -n "$sshdBin" ]] || { appError "SFTP Binary not found"; return 1; }
|
||||
|
||||
if ! getent group "$sftpAccessGroup" >/dev/null 2>&1; then
|
||||
# printInfo "$systemLabel SFTP Create SFTP access group: $sftpAccessGroup"
|
||||
run output error groupadd "$sftpAccessGroup" || { appError "SFTP Failed create group $sftpAccessGroup: $error"; return 1; }
|
||||
fi
|
||||
|
||||
grep -Eq '^[[:space:]]*Subsystem[[:space:]]+sftp[[:space:]]+' "$sftpConfig" || {
|
||||
appError "SFTP Not found Subsystem in $sftpConfig"
|
||||
return 1
|
||||
}
|
||||
|
||||
sftpBackup="$sftpConfig.$(date +%F_%H-%M-%S).bak"
|
||||
cp -a "$sftpConfig" "$sftpBackup" || { appError "SFTP Backup failed"; return 1; }
|
||||
|
||||
# printInfo "$systemLabel SFTP Update config..."
|
||||
if ! sed -i -E 's|^[[:space:]]*Subsystem[[:space:]]+sftp[[:space:]]+.*$|Subsystem sftp internal-sftp|' "$sftpConfig"; then
|
||||
cp -a "$sftpBackup" "$sftpConfig"
|
||||
appError "SFTP Update Subsystem SFTP failed"
|
||||
return 1
|
||||
fi
|
||||
if ! sed -i \
|
||||
-e '/^# --- KUBE SFTP GLOBAL BEGIN ---$/,/^# --- KUBE SFTP GLOBAL END ---$/d' \
|
||||
-e '/^# --- KUBE SFTP GROUP BEGIN ---$/,/^# --- KUBE SFTP GROUP END ---$/d' \
|
||||
"$sftpConfig"; then
|
||||
cp -a "$sftpBackup" "$sftpConfig"
|
||||
appError "SFTP Remove old SFTP blocks failed"
|
||||
return 1
|
||||
fi
|
||||
local tmpFile
|
||||
tmpFile="$(mktemp)"
|
||||
if ! {
|
||||
cat "$appAssetsPath/system/sftp-global.conf"
|
||||
echo
|
||||
cat "$sftpConfig"
|
||||
echo
|
||||
sed "s|{{sftp_access_group}}|$sftpAccessGroup|g" "$appAssetsPath/system/sftp-group.conf"
|
||||
} > "$tmpFile" || ! mv "$tmpFile" "$sftpConfig"; then
|
||||
rm -f "$tmpFile"
|
||||
cp -a "$sftpBackup" "$sftpConfig"
|
||||
appError "SFTP Append SFTP config blocks failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# printInfo "$systemLabel SFTP Config validation..."
|
||||
if ! run output error "$sshdBin" -t -f "$sftpConfig"; then
|
||||
cp -a "$sftpBackup" "$sftpConfig"
|
||||
appError "SFTP Config validation failed: $error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# printInfo "$systemLabel SFTP Reload/restart service..."
|
||||
if ! run output error systemctl reload "$sshService"; then
|
||||
if ! run output error systemctl restart "$sshService"; then
|
||||
cp -a "$sftpBackup" "$sftpConfig"
|
||||
systemctl restart "$sshService" >/dev/null 2>&1 || true
|
||||
appError "SFTP Reload/restart failed: $error"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# printSuccess "$systemLabel SFTP Adding support complete"
|
||||
}
|
||||
|
||||
function fail2banConfigUpdate() {
|
||||
local sourceConfig targetConfig
|
||||
targetConfig="/etc/fail2ban/jail.local"
|
||||
sourceConfig="$appAssetsPath/system/fail2ban.conf"
|
||||
|
||||
[[ ! -f "$targetConfig" ]] || {
|
||||
appError "The file $targetConfig already exists. Make changes manually.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
cp -a "$sourceConfig" "$targetConfig" >/dev/null 2>&1 || {
|
||||
appError "File copy error";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if command -v fail2ban-client >/dev/null 2>&1; then
|
||||
fail2ban-client -t >/dev/null 2>&1 || {
|
||||
appError "Configuration error";
|
||||
return 1;
|
||||
}
|
||||
fi
|
||||
|
||||
systemctl restart fail2ban
|
||||
sleep 2
|
||||
systemctl is-active --quiet fail2ban || {
|
||||
appError "fail2ban did not start after applying the new configuration";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user