Added expanded README.md (still need video link)

This commit is contained in:
Rodger Castle 2026-05-04 20:41:00 -04:00
parent c8fcd5beb5
commit e7bc3decdc
2 changed files with 219 additions and 465 deletions

230
README.md
View File

@ -1,30 +1,234 @@
# imagehost-setup # imagehost-setup
A single-script installer that turns a fresh AlmaLinux 10 VPS into a A single-script installer that turns a fresh AlmaLinux 10 VPS into a lightweight, secure image host — SFTP upload, Nginx file serving, optional Let's Encrypt SSL, and brute-force protection out of the box.
lightweight, secure image host — SFTP upload, Nginx serving, optional
Let's Encrypt SSL, and fail2ban out of the box.
## Requirements ## Requirements
- A fresh AlmaLinux 10 VPS - A fresh AlmaLinux 10 VPS (tested on Linode/Akamai)
- A domain name pointed at your server's IP address *(optional but recommended for SSL)*
- Root or sudo access - Root or sudo access
## Usage ## Quick Start *(for experienced users)*
Download and run the script:
```bash
curl -O https://git.castlehollow.com/rodger/imagehost-setup/raw/branch/main/imagehost-setup.sh curl -O https://git.castlehollow.com/rodger/imagehost-setup/raw/branch/main/imagehost-setup.sh
sudo bash imagehost-setup.sh sudo bash imagehost-setup.sh
```
The script will walk you through the rest interactively. The script will walk you through the rest interactively. When it finishes, it prints your SFTP credentials and image URL — save them somewhere safe.
## What it sets up ## What it sets up
- **Nginx** — serves image files only (JPG, PNG, GIF, WebP, AVIF, SVG, BMP, TIFF) - **Nginx** — serves image files only (JPG, PNG, GIF, WebP, AVIF, SVG, BMP, TIFF); everything else returns a 404
- **SFTP chroot** — a locked-down upload user with no shell access - **SFTP chroot** — a locked-down upload user that can only access the images folder; no shell access
- **firewalld** — opens only SSH, HTTP, and HTTPS - **Maintenance user** — a normal SSH login with sudo access for administration
- **fail2ban** — brute-force protection on SSH and Nginx - **firewalld** — opens only SSH, HTTP, and HTTPS; everything else is blocked
- **Let's Encrypt SSL** — optional, with HTTP fallback - **fail2ban** — automatically bans IPs that repeatedly fail to log in
- **Let's Encrypt SSL** — optional; falls back to plain HTTP if no domain is provided
---
## Guide for Windows Users New to Linux
Never used a terminal before? No problem. This section walks you through everything from zero.
### Before You Start
You'll need to have already done two things that aren't covered here:
1. **Rented a VPS** (Virtual Private Server) — a small cloud computer you can run 24/7. Linode/Akamai is a good choice. Their smallest plan (Nanode, $5/month) is plenty for this.
2. **Set up a domain name** *(optional)* — if you want a proper web address like `images.yourdomain.com` instead of a raw IP address, you'll need a domain and need to point it at your server's IP address. Your VPS provider and domain registrar will have guides for this.
If you need help with either of those, check the video walkthrough [link here].
Once your server is running and you have its **IP address** (looks something like `172.237.151.226`) and **root password** from your provider, come back here.
---
### Step 1 — Get a Terminal on Windows
A terminal (also called a command prompt or console) is a text-based window you type commands into. On modern Windows you have a few options:
**Option A — Windows Terminal + SSH (Windows 10/11, recommended)**
Windows 10 and 11 come with SSH built in. Press the **Windows key**, type `Terminal`, and open **Windows Terminal** or **PowerShell**. Either one works fine.
**Option B — PuTTY (older Windows, or if the above doesn't work)**
Download PuTTY from [https://www.putty.org](https://www.putty.org) — it's free and has been the standard Windows SSH client for decades. Install it and open it.
---
### Step 2 — Log Into Your Server
Your server is running Linux and is waiting for you to connect to it. The way you connect is called **SSH** (Secure Shell) — it's an encrypted connection that lets you type commands on the remote server as if you were sitting in front of it.
**Using Windows Terminal or PowerShell:**
Type the following, replacing `YOUR.SERVER.IP` with your actual IP address:
```
ssh root@YOUR.SERVER.IP
```
Press Enter. You'll see a message like:
```
The authenticity of host '172.237.151.226' can't be established.
Are you sure you want to continue connecting (yes/no)?
```
Type `yes` and press Enter. This is normal — it's just your computer remembering the server for next time.
Then it will ask for a password. Type your root password (the one your VPS provider gave you) and press Enter. **You won't see anything as you type — that's normal**, Linux hides passwords for security.
You should end up at a prompt that looks something like:
```
[root@localhost ~]#
```
You're in. You're now typing commands directly on your server.
**Using PuTTY:**
Open PuTTY. In the **Host Name** box, type your server's IP address. Make sure **Port** is `22` and **SSH** is selected. Click **Open**. When the security warning appears, click **Accept**. Log in as `root` with your server password.
---
### Step 3 — Download and Run the Setup Script
Now you'll download and run the installer. Copy and paste these two commands, pressing Enter after each one:
```bash
curl -O https://git.castlehollow.com/rodger/imagehost-setup/raw/branch/main/imagehost-setup.sh
```
```bash
bash imagehost-setup.sh
```
> **Tip:** To paste into Windows Terminal, right-click or press **Ctrl+Shift+V**. In PuTTY, just right-click.
The script will now ask you a series of questions. Here's what each one means:
---
### Step 4 — Answering the Setup Questions
**Domain name**
If you have a domain name pointed at this server (like `images.yourdomain.com`), type it here and press Enter. If not, just press Enter to skip — your images will be accessible by IP address instead.
**Email address**
Only asked if you entered a domain. This is used by Let's Encrypt to send you certificate expiry notices. Enter any email address you check.
**SFTP username**
This is the username you'll use to upload images. Press Enter to accept the default (`imageuser`), or type your own.
**SFTP password**
This is the password for uploading images. You can type your own password or just press Enter to have a strong one generated for you automatically. Either way, it will be displayed at the end — make sure you save it.
**Maintenance username**
This is a separate login for managing the server itself (not for uploading images). Press Enter to accept the default (`siteadmin`), or type your own.
**Maintenance password**
Same as above — type one or press Enter to auto-generate.
**Maximum image file size**
The largest file size (in megabytes) that can be uploaded. Press Enter to accept the default of 20 MB, or type a number.
**Proceed with installation?**
Review the summary and type `y` then Enter to start the installation. The script will now run for a few minutes — you'll see progress messages scrolling by. This is normal.
---
### Step 5 — Save Your Credentials
When the script finishes, it will print a summary that looks something like this:
```
Image URL format:
https://images.yourdomain.com/<filename.jpg>
SFTP connection details:
Host : images.yourdomain.com
Port : 22
Username : imageuser
Password : Xk92mPqL... ← Save this now!
Upload to: /images/
Maintenance (SSH) login:
Host : images.yourdomain.com
Port : 22
Username : siteadmin
Password : Rt47vNwM... ← Save this now!
Sudo : sudo -i to become root
```
**Copy this entire block and save it somewhere safe** — a password manager, a secure note, anywhere you won't lose it. The passwords cannot be recovered after this point (though they can be reset if needed).
---
### Step 6 — Upload Your First Image
You'll need an SFTP client — a program that lets you transfer files to your server. These are all free:
- **FileZilla** — [https://filezilla-project.org](https://filezilla-project.org) (Windows, Mac, Linux)
- **WinSCP** — [https://winscp.net](https://winscp.net) (Windows only, very beginner-friendly)
- **Cyberduck** — [https://cyberduck.io](https://cyberduck.io) (Windows and Mac)
**Connecting with FileZilla (as an example):**
1. Open FileZilla
2. At the top, fill in:
- **Host:** your domain or IP address
- **Username:** your SFTP username (e.g. `imageuser`)
- **Password:** your SFTP password
- **Port:** `22`
3. Click **Quickconnect**
4. On the right side you'll see a folder called `images` — that's where your files go
5. Drag an image from your computer into that folder
**Accessing your image:**
Once uploaded, your image is immediately available at:
```
https://images.yourdomain.com/your-filename.jpg
```
Or if you're using an IP address:
```
http://172.237.151.226/your-filename.jpg
```
That's the URL you'd paste into your inventory management system listing.
---
### Troubleshooting
**"Connection refused" when trying to SSH**
Your server may still be booting, or your IP address is wrong. Wait a minute and try again. Double-check the IP in your VPS provider's dashboard.
**Images returning a 404 error**
Make sure you uploaded the file into the `/images/` folder, not the root of the SFTP connection. In FileZilla, you should see an `images` folder when you first connect — put your files inside that.
**Forgot the SFTP or maintenance password**
Log into your server via SSH as your maintenance user, then run:
```bash
sudo passwd imageuser
```
Replace `imageuser` with whichever account needs a password reset. You'll be prompted to set a new one.
**SSL certificate didn't install / getting a security warning**
This usually means your domain's DNS record wasn't pointing at your server's IP yet when the script ran. Once DNS is set up correctly, log in via SSH and run:
```bash
sudo certbot --nginx -d images.yourdomain.com
```
---
## License ## License

View File

@ -1,450 +0,0 @@
#!/usr/bin/env bash
# =============================================================================
# imagehost-setup.sh
# Turns a fresh AlmaLinux 10 VPS into a lightweight, secure image host.
# - Nginx (image-type-restricted static file serving)
# - Chrooted SFTP-only upload user
# - firewalld rules
# - fail2ban
# - Optional Let's Encrypt SSL (falls back to plain HTTP)
#
# Usage: sudo bash imagehost-setup.sh
# =============================================================================
set -euo pipefail
# ── Colour helpers ────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
info() { echo -e "${CYAN}[INFO]${RESET} $*"; }
success() { echo -e "${GREEN}[OK]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
die() { echo -e "${RED}[ERROR]${RESET} $*" >&2; exit 1; }
banner() { echo -e "\n${BOLD}${CYAN}══════════════════════════════════════════════${RESET}"; \
echo -e "${BOLD}${CYAN} $*${RESET}"; \
echo -e "${BOLD}${CYAN}══════════════════════════════════════════════${RESET}\n"; }
# ── Root check ────────────────────────────────────────────────────────────────
[[ $EUID -eq 0 ]] || die "This script must be run as root (use: sudo bash imagehost-setup.sh)"
# ── Detect AlmaLinux ─────────────────────────────────────────────────────────
if ! grep -qi 'almalinux' /etc/os-release 2>/dev/null; then
warn "This script is designed for AlmaLinux. Proceeding anyway, but results may vary."
fi
# =============================================================================
# INTERACTIVE CONFIGURATION
# =============================================================================
banner "Image Host Setup — Configuration"
# ── Domain ────────────────────────────────────────────────────────────────────
echo -e "${BOLD}Domain name${RESET} (leave blank to use the server's IP address only):"
read -rp " Domain [none]: " DOMAIN
DOMAIN="${DOMAIN// /}" # strip spaces
if [[ -n "$DOMAIN" ]]; then
echo -e "${BOLD}Email address${RESET} for Let's Encrypt certificate notices:"
read -rp " Email: " LE_EMAIL
LE_EMAIL="${LE_EMAIL// /}"
[[ "$LE_EMAIL" =~ ^[^@]+@[^@]+\.[^@]+$ ]] || die "Invalid email address."
USE_SSL=true
else
USE_SSL=false
info "No domain provided — will serve over HTTP only."
fi
# ── SFTP user ─────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}SFTP username${RESET} for image uploads (leave blank to use 'imageuser'):"
read -rp " Username [imageuser]: " SFTP_USER
SFTP_USER="${SFTP_USER:-imageuser}"
# Validate username
[[ "$SFTP_USER" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || die "Invalid username. Use lowercase letters, numbers, hyphens, underscores."
echo ""
echo -e "${BOLD}SFTP password${RESET} (leave blank to auto-generate a strong password):"
read -rsp " Password [auto]: " SFTP_PASS
echo ""
if [[ -z "$SFTP_PASS" ]]; then
SFTP_PASS="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 24 || true)"
GENERATED_PASS=true
else
GENERATED_PASS=false
fi
# ── Max upload file size ──────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}Maximum image file size${RESET} in megabytes (leave blank for 20 MB):"
read -rp " Max size MB [20]: " MAX_SIZE_MB
MAX_SIZE_MB="${MAX_SIZE_MB:-20}"
[[ "$MAX_SIZE_MB" =~ ^[0-9]+$ ]] || die "Max size must be a whole number."
# ── Confirm ───────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}──────── Summary ────────${RESET}"
echo -e " SFTP username : ${CYAN}${SFTP_USER}${RESET}"
if $GENERATED_PASS; then
echo -e " SFTP password : ${YELLOW}(auto-generated — shown at the end)${RESET}"
else
echo -e " SFTP password : ${CYAN}(as entered)${RESET}"
fi
echo -e " Domain : ${CYAN}${DOMAIN:-'(none — IP only)'}${RESET}"
echo -e " SSL : ${CYAN}${USE_SSL}${RESET}"
echo -e " Max file size : ${CYAN}${MAX_SIZE_MB} MB${RESET}"
echo ""
read -rp "Proceed with installation? [y/N] " CONFIRM
[[ "${CONFIRM,,}" == "y" ]] || { echo "Aborted."; exit 0; }
# =============================================================================
# DERIVED VARIABLES
# =============================================================================
CHROOT_DIR="/srv/imagehost"
IMAGES_DIR="${CHROOT_DIR}/images"
NGINX_CONF="/etc/nginx/conf.d/imagehost.conf"
MAX_SIZE_NGINX="${MAX_SIZE_MB}m"
LOG_FILE="/var/log/imagehost-setup.log"
# All output also goes to a log file
exec > >(tee -a "$LOG_FILE") 2>&1
# =============================================================================
# STEP 1 — System update & packages
# =============================================================================
banner "Step 1/7 — Installing packages"
info "Updating system packages…"
dnf -y update --quiet
info "Installing EPEL repository…"
dnf -y install epel-release --quiet
info "Installing Nginx, fail2ban, certbot, and utilities…"
dnf -y install nginx fail2ban firewalld pwgen --quiet
if $USE_SSL; then
dnf -y install certbot python3-certbot-nginx --quiet
fi
success "Packages installed."
# =============================================================================
# STEP 2 — Create chroot jail + SFTP user
# =============================================================================
banner "Step 2/7 — Creating SFTP user and chroot jail"
# OpenSSH chroot requires the chroot root owned by root:root, mode 755
info "Creating chroot directory structure…"
mkdir -p "${IMAGES_DIR}"
chown root:root "${CHROOT_DIR}"
chmod 755 "${CHROOT_DIR}"
# The images subdirectory is owned by the SFTP user so they can write to it
if id "${SFTP_USER}" &>/dev/null; then
warn "User '${SFTP_USER}' already exists — skipping user creation."
else
info "Creating user '${SFTP_USER}'…"
useradd -r -s /sbin/nologin -d "${CHROOT_DIR}" -M "${SFTP_USER}"
fi
echo "${SFTP_USER}:${SFTP_PASS}" | chpasswd
chown "${SFTP_USER}:${SFTP_USER}" "${IMAGES_DIR}"
chmod 750 "${IMAGES_DIR}"
success "User '${SFTP_USER}' created with chroot at ${CHROOT_DIR}."
# =============================================================================
# STEP 2b — Create maintenance user
# =============================================================================
banner "Step 2b/7 — Creating maintenance user"
echo -e "${BOLD}Maintenance username${RESET} for server administration (leave blank for 'siteadmin'):"
read -rp " Username [siteadmin]: " ADMIN_USER
ADMIN_USER="${ADMIN_USER:-siteadmin}"
[[ "$ADMIN_USER" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || die "Invalid username."
echo ""
echo -e "${BOLD}Maintenance password${RESET} (leave blank to auto-generate):"
read -rsp " Password [auto]: " ADMIN_PASS
echo ""
if [[ -z "$ADMIN_PASS" ]]; then
ADMIN_PASS="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 24 || true)"
GENERATED_ADMIN_PASS=true
else
GENERATED_ADMIN_PASS=false
fi
if id "${ADMIN_USER}" &>/dev/null; then
warn "User '${ADMIN_USER}' already exists — resetting password only."
else
info "Creating user '${ADMIN_USER}'…"
useradd -m -s /bin/bash "${ADMIN_USER}"
fi
echo "${ADMIN_USER}:${ADMIN_PASS}" | chpasswd
usermod -aG wheel "${ADMIN_USER}"
success "Maintenance user '${ADMIN_USER}' created and added to wheel (sudo) group."
# =============================================================================
# STEP 3 — Harden SSH / configure chroot SFTP
# =============================================================================
banner "Step 3/7 — Configuring SSH & SFTP chroot"
SSHD_CONFIG="/etc/ssh/sshd_config"
SFTP_STANZA="
# ── imagehost SFTP chroot ──────────────────────────────────────────────────
Match User ${SFTP_USER}
ChrootDirectory ${CHROOT_DIR}
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
AllowAgentForwarding no
"
# Remove any previous stanza for this user, then append the new one
if grep -q "Match User ${SFTP_USER}" "$SSHD_CONFIG"; then
info "Removing existing SSH stanza for '${SFTP_USER}'…"
# Use python for reliable multi-line deletion
python3 - "${SFTP_USER}" "$SSHD_CONFIG" <<'PYEOF'
import sys, re, pathlib
user = sys.argv[1]
path = pathlib.Path(sys.argv[2])
text = path.read_text()
pattern = rf'\n# ── imagehost SFTP chroot ──.*?Match User {re.escape(user)}.*?AllowAgentForwarding no\n'
text = re.sub(pattern, '', text, flags=re.DOTALL)
path.write_text(text)
PYEOF
fi
# Apply global hardening options FIRST (before the Match block)
apply_ssh_option() {
local key="$1" val="$2"
if grep -qiE "^\s*${key}\s" "$SSHD_CONFIG"; then
sed -i -E "s|^\s*${key}\s.*|${key} ${val}|i" "$SSHD_CONFIG"
else
# Insert before the first Match block, or append if no Match block exists
if grep -q "^Match " "$SSHD_CONFIG"; then
sed -i "/^Match /i ${key} ${val}" "$SSHD_CONFIG"
else
echo "${key} ${val}" >> "$SSHD_CONFIG"
fi
fi
}
apply_ssh_option "PermitRootLogin" "prohibit-password"
apply_ssh_option "PasswordAuthentication" "yes"
apply_ssh_option "MaxAuthTries" "4"
apply_ssh_option "LoginGraceTime" "30"
# Append the Match block LAST
printf '%s\n' "$SFTP_STANZA" >> "$SSHD_CONFIG"
sshd -t || die "SSH config test failed — check ${SSHD_CONFIG}"
systemctl restart sshd
success "SSH/SFTP configured."
# =============================================================================
# STEP 4 — Nginx configuration
# =============================================================================
banner "Step 4/7 — Configuring Nginx"
# Determine server_name
if [[ -n "$DOMAIN" ]]; then
SERVER_NAME="$DOMAIN"
else
# Use the primary non-loopback IP
SERVER_NAME=$(hostname -I | awk '{print $1}')
fi
cat > "$NGINX_CONF" <<NGINXCONF
# imagehost — generated by imagehost-setup.sh
server {
listen 80;
listen [::]:80;
server_name ${SERVER_NAME};
root ${IMAGES_DIR};
autoindex off;
server_tokens off;
client_max_body_size ${MAX_SIZE_NGINX};
# Security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer" always;
add_header Content-Security-Policy "default-src 'none'; img-src 'self'" always;
# Allow only image file types
location ~* \.(jpe?g|png|gif|webp|avif|svg|ico|bmp|tiff?)$ {
expires 30d;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff" always;
try_files \$uri =404;
}
# Block everything else
location / {
return 404;
}
# Hide dot-files
location ~ /\. {
deny all;
}
access_log /var/log/nginx/imagehost_access.log;
error_log /var/log/nginx/imagehost_error.log;
}
NGINXCONF
# Remove default Nginx config if present
[[ -f /etc/nginx/conf.d/default.conf ]] && mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
nginx -t || die "Nginx config test failed — check ${NGINX_CONF}"
systemctl enable --now nginx
success "Nginx configured and started."
# Nginx needs read access to the images directory (SELinux-aware)
info "Setting file contexts for SELinux…"
if command -v semanage &>/dev/null && command -v restorecon &>/dev/null; then
semanage fcontext -a -t httpd_sys_content_t "${CHROOT_DIR}(/.*)?" 2>/dev/null || \
semanage fcontext -m -t httpd_sys_content_t "${CHROOT_DIR}(/.*)?." 2>/dev/null || true
restorecon -Rv "${CHROOT_DIR}" >/dev/null
# Allow Nginx to read the chroot dir
setsebool -P httpd_read_user_content 1 2>/dev/null || true
success "SELinux contexts applied."
else
warn "semanage not found — skipping SELinux context setup (may not be needed)."
fi
# =============================================================================
# STEP 5 — Firewall
# =============================================================================
banner "Step 5/7 — Configuring firewall"
systemctl enable --now firewalld
firewall-cmd --quiet --permanent --add-service=ssh
firewall-cmd --quiet --permanent --add-service=http
$USE_SSL && firewall-cmd --quiet --permanent --add-service=https
firewall-cmd --quiet --reload
success "Firewall rules applied (SSH + HTTP${USE_SSL:+ + HTTPS})."
# =============================================================================
# STEP 6 — fail2ban
# =============================================================================
banner "Step 6/7 — Configuring fail2ban"
cat > /etc/fail2ban/jail.d/imagehost.conf <<F2B
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
[nginx-http-auth]
enabled = true
[nginx-limit-req]
enabled = true
F2B
systemctl enable --now fail2ban
success "fail2ban configured and started."
# =============================================================================
# STEP 7 — Let's Encrypt SSL (optional)
# =============================================================================
if $USE_SSL; then
banner "Step 7/7 — Obtaining SSL certificate"
info "Requesting certificate for ${DOMAIN}"
if certbot --nginx \
--staging \
--non-interactive \
--agree-tos \
--email "$LE_EMAIL" \
--domains "$DOMAIN" \
--redirect; then
success "SSL certificate installed. HTTPS enabled."
# Ensure auto-renewal is active
systemctl enable --now certbot-renew.timer 2>/dev/null || \
(crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet") | crontab -
else
warn "Certbot failed — falling back to HTTP."
warn "Make sure your domain's DNS A record points to this server's IP."
warn "You can re-run certbot manually later:"
warn " certbot --nginx -d ${DOMAIN} --email ${LE_EMAIL} --agree-tos --redirect"
USE_SSL=false
fi
else
banner "Step 7/7 — SSL skipped (no domain provided)"
info "Serving over HTTP only."
fi
# =============================================================================
# FINAL SUMMARY
# =============================================================================
banner "Setup Complete!"
# Determine the base URL
if $USE_SSL; then
BASE_URL="https://${DOMAIN}"
elif [[ -n "$DOMAIN" ]]; then
BASE_URL="http://${DOMAIN}"
else
IP=$(hostname -I | awk '{print $1}')
BASE_URL="http://${IP}"
fi
echo -e "${BOLD}Your image host is ready.${RESET}"
echo ""
echo -e " ${BOLD}Image URL format:${RESET}"
echo -e " ${CYAN}${BASE_URL}/<filename.jpg>${RESET}"
echo ""
echo -e " ${BOLD}SFTP connection details:${RESET}"
echo -e " Host : ${CYAN}${DOMAIN:-$(hostname -I | awk '{print $1}')}${RESET}"
echo -e " Port : ${CYAN}22${RESET}"
echo -e " Username : ${CYAN}${SFTP_USER}${RESET}"
if $GENERATED_PASS; then
echo -e " Password : ${YELLOW}${SFTP_PASS}${RESET} ${RED}← Save this now!${RESET}"
else
echo -e " Password : ${CYAN}(as you entered)${RESET}"
fi
echo -e " Upload to: ${CYAN}/images/${RESET} (this is the root you'll see in your SFTP client)"
echo ""
echo -e " ${BOLD}Maintenance (SSH) login:${RESET}"
echo -e " Host : ${CYAN}${DOMAIN:-$(hostname -I | awk '{print $1}')}${RESET}"
echo -e " Port : ${CYAN}22${RESET}"
echo -e " Username : ${CYAN}${ADMIN_USER}${RESET}"
if $GENERATED_ADMIN_PASS; then
echo -e " Password : ${YELLOW}${ADMIN_PASS}${RESET} ${RED}← Save this now!${RESET}"
else
echo -e " Password : ${CYAN}(as you entered)${RESET}"
fi
echo -e " Sudo : ${CYAN}sudo -i${RESET} to become root"
echo ""
echo -e " ${BOLD}Allowed file types:${RESET} JPG, PNG, GIF, WebP, AVIF, SVG, BMP, TIFF"
echo -e " ${BOLD}Max file size:${RESET} ${MAX_SIZE_MB} MB"
echo ""
echo -e " ${BOLD}Recommended SFTP clients:${RESET}"
echo -e " • FileZilla (Windows / Mac / Linux) — free"
echo -e " • Cyberduck (Windows / Mac) — free"
echo -e " • WinSCP (Windows) — free"
echo ""
echo -e " ${BOLD}Setup log:${RESET} ${LOG_FILE}"
echo ""
echo -e "${GREEN}${BOLD}All done!${RESET}"