taler-merchant-rproxy-setup (12217B)
1 #!/usr/bin/env bash 2 # 3 # Usage: 4 # taler-merchant-rproxy-setup --domain some.domain.name [--nginx | --apache] [--httponly | --httpsonly] 5 # 6 # If neither --nginx nor --apache is specified, the script: 7 # 1) Detects if exactly one of them is installed -> uses it 8 # 2) Otherwise, errors out 9 # 10 # Description: 11 # - Requires --domain <name> 12 # - At most one of {--nginx, --apache} (or auto-detection) 13 # - Optionally {--httponly} or {--httpsonly} (but not both) 14 # - Checks for required packages (nginx/apache2, certbot (unless HTTP-only)) 15 # - Verifies Apache modules if using --apache (proxy, proxy_http, headers, ssl) 16 # - Attempts to start the selected web server 17 # - Runs certbot to get certificates (unless HTTP-only) 18 # - Updates config(s), backs up originals, optionally forces HTTP->HTTPS 19 # - Activates the new configuration 20 # 21 # Paths used: 22 # - Nginx: /etc/nginx/sites-available/taler-merchant 23 # - Apache: /etc/apache2/sites-available/taler-merchant.conf 24 # 25 26 ########################### 27 # 0. Parse input arguments 28 ########################### 29 30 DOMAIN="" 31 USE_NGINX=0 32 USE_APACHE=0 33 HTTP_ONLY=0 34 HTTPS_ONLY=0 35 36 usage() { 37 echo "Usage:" 38 echo " taler-merchant-rproxy-setup --domain <example.com> [--nginx | --apache] [--httponly | --httpsonly]" 39 echo 40 echo "Description:" 41 echo " Configures reverse proxy settings for Taler merchant under either Nginx or Apache." 42 echo " If no server type is specified, the script auto-detects if exactly one of them is installed." 43 echo 44 echo "Options:" 45 echo " --domain <example.com> (Required) Domain name to configure" 46 echo " --nginx Force use of Nginx" 47 echo " --apache Force use of Apache" 48 echo " --httponly Only configure HTTP (no TLS). Skips certbot." 49 echo " --httpsonly Configure HTTPS with automatic redirect from HTTP." 50 echo " -h, --help Show this help message and exit." 51 exit 0 52 } 53 54 ########################## 55 # 0.a. Must run as root 56 ########################## 57 if [[ $EUID -ne 0 ]]; then 58 echo "ERROR: This script must be run as root (e.g. with sudo)." 59 exit 1 60 fi 61 62 while [[ $# -gt 0 ]]; do 63 case "$1" in 64 --domain) 65 DOMAIN="$2" 66 shift 2 67 ;; 68 --nginx) 69 USE_NGINX=1 70 shift 71 ;; 72 --apache) 73 USE_APACHE=1 74 shift 75 ;; 76 --httponly) 77 HTTP_ONLY=1 78 shift 79 ;; 80 --httpsonly) 81 HTTPS_ONLY=1 82 shift 83 ;; 84 -h|--help) 85 usage 86 ;; 87 *) 88 echo "Unknown argument: $1" 89 echo "Use --help for usage information." 90 exit 1 91 ;; 92 esac 93 done 94 95 # Check domain 96 if [[ -z "$DOMAIN" ]]; then 97 echo "ERROR: --domain <name> is required." 98 echo "Use --help for usage information." 99 exit 1 100 fi 101 102 ############################## 103 # 0.b. Optional DNS check 104 ############################## 105 # Checks that the domain resolves to at least one local IP. 106 # If it doesn't, you can either warn or exit. Below, we exit. 107 # If your environment uses NAT or multiple interfaces, you may 108 # wish to relax this check into a warning. 109 110 if command -v dig &>/dev/null; then 111 # Gather the local machine's IP addresses 112 local_ips="$(hostname -I 2>/dev/null || true)" 113 # Attempt to resolve $DOMAIN via DNS 114 domain_ips="$(dig +short A "$DOMAIN")" 115 116 if [[ -z "$domain_ips" ]]; then 117 echo "ERROR: DNS lookup for '$DOMAIN' returned no A record." 118 echo "Please ensure the domain name is configured correctly in DNS." 119 exit 1 120 fi 121 122 echo "Local IP(s): $local_ips" 123 echo "Domain IP(s): $domain_ips" 124 125 match_found=0 126 while read -r dip; do 127 if echo "$local_ips" | grep -qw "$dip"; then 128 match_found=1 129 break 130 fi 131 done <<< "$domain_ips" 132 133 if [[ $match_found -eq 0 ]]; then 134 echo "ERROR: None of the DNS IPs for '$DOMAIN' match this server's IP(s)." 135 echo "Fix DNS or check networking before continuing." 136 exit 1 137 fi 138 else 139 echo "WARNING: 'dig' not installed; skipping DNS check." 140 fi 141 142 ############################## 143 # Detect installed web server 144 ############################## 145 check_installed() { 146 dpkg -s "$1" &>/dev/null 147 } 148 149 # If user did NOT specify --nginx or --apache, see if exactly one is installed. 150 if [[ $USE_NGINX -eq 0 && $USE_APACHE -eq 0 ]]; then 151 NGINX_INSTALLED=0 152 APACHE_INSTALLED=0 153 if check_installed nginx; then 154 NGINX_INSTALLED=1 155 fi 156 if check_installed apache2; then 157 APACHE_INSTALLED=1 158 fi 159 160 if [[ $NGINX_INSTALLED -eq 1 && $APACHE_INSTALLED -eq 0 ]]; then 161 USE_NGINX=1 162 echo "Detected only nginx installed; proceeding with nginx." 163 elif [[ $NGINX_INSTALLED -eq 0 && $APACHE_INSTALLED -eq 1 ]]; then 164 USE_APACHE=1 165 echo "Detected only apache2 installed; proceeding with apache." 166 else 167 echo "ERROR: Both or neither of nginx/apache2 are installed." 168 echo " Please install one or specify --nginx / --apache explicitly." 169 exit 1 170 fi 171 fi 172 173 # At this point, we have either USE_NGINX=1 or USE_APACHE=1. 174 175 # Check that at most one of {--httponly, --httpsonly} 176 if [[ $HTTP_ONLY -eq 1 && $HTTPS_ONLY -eq 1 ]]; then 177 echo "ERROR: Cannot specify both --httponly and --httpsonly." 178 exit 1 179 fi 180 181 # We need certbot only if HTTPS is involved 182 if [[ $HTTP_ONLY -eq 0 ]]; then 183 if ! check_installed certbot; then 184 echo "ERROR: certbot is not installed." 185 echo "Install it via: sudo apt-get install certbot" 186 exit 1 187 fi 188 fi 189 190 ################################### 191 # 1. Check presence of chosen server 192 ################################### 193 if [[ $USE_NGINX -eq 1 ]]; then 194 if ! check_installed nginx; then 195 echo "ERROR: nginx is not installed or not detected." 196 echo "Install it via: sudo apt-get install nginx" 197 exit 1 198 fi 199 else 200 if ! check_installed apache2; then 201 echo "ERROR: apache2 is not installed or not detected." 202 echo "Install it via: sudo apt-get install apache2" 203 exit 1 204 fi 205 206 # Check Apache modules. If missing, enable them. Then restart Apache. 207 APACHE_MODULES="$(apache2ctl -M 2>/dev/null)" 208 for mod in proxy proxy_http headers ssl; do 209 if ! echo "$APACHE_MODULES" | grep -qE "^ $mod(_module)?"; then 210 echo "Apache module '$mod' not enabled. Enabling it now..." 211 a2enmod "$mod" 212 NEED_RESTART=1 213 fi 214 done 215 216 if [[ -n "$NEED_RESTART" ]]; then 217 echo "Restarting apache2 to load newly enabled module(s)..." 218 systemctl restart apache2 219 fi 220 fi 221 222 ########################################### 223 # 2. Start/ensure the requested service is up 224 ########################################### 225 start_service() { 226 local service_name="$1" 227 if ! systemctl is-active --quiet "$service_name"; then 228 echo "Attempting to start $service_name ..." 229 if ! systemctl start "$service_name"; then 230 echo "ERROR: Could not start $service_name. Fix manually or switch server type." 231 exit 1 232 fi 233 fi 234 } 235 236 if [[ $USE_NGINX -eq 1 ]]; then 237 start_service "nginx" 238 else 239 start_service "apache2" 240 fi 241 242 ####################################################### 243 # 2.5 Adjust config for HTTP-only (if requested FIRST) 244 ####################################################### 245 CONFIG_FILE_NGINX="/etc/nginx/sites-available/taler-merchant" 246 CONFIG_FILE_APACHE="/etc/apache2/sites-available/taler-merchant.conf" 247 248 backup_and_edit_nginx_http_only() { 249 if [[ ! -f "${CONFIG_FILE_NGINX}.legacy" && -f "$CONFIG_FILE_NGINX" ]]; then 250 sudo cp "$CONFIG_FILE_NGINX" "${CONFIG_FILE_NGINX}.legacy" 251 fi 252 if [[ -f "${CONFIG_FILE_NGINX}.legacy" ]]; then 253 sudo cp "${CONFIG_FILE_NGINX}.legacy" "$CONFIG_FILE_NGINX" 254 fi 255 sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_NGINX" 2>/dev/null 256 # Remove any 'server { ... listen 443 ... }' block 257 sudo sed -i '/listen 443/,/}/d' "$CONFIG_FILE_NGINX" 2>/dev/null 258 } 259 260 backup_and_edit_apache_http_only() { 261 if [[ ! -f "${CONFIG_FILE_APACHE}.legacy" && -f "$CONFIG_FILE_APACHE" ]]; then 262 sudo cp "$CONFIG_FILE_APACHE" "${CONFIG_FILE_APACHE}.legacy" 263 fi 264 if [[ -f "${CONFIG_FILE_APACHE}.legacy" ]]; then 265 sudo cp "${CONFIG_FILE_APACHE}.legacy" "$CONFIG_FILE_APACHE" 266 fi 267 sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_APACHE" 2>/dev/null 268 # Remove everything from "<VirtualHost *:443>" to "</VirtualHost>" 269 sudo sed -i '/<VirtualHost \*:443>/,/<\/VirtualHost>/d' "$CONFIG_FILE_APACHE" 2>/dev/null 270 } 271 272 if [[ $HTTP_ONLY -eq 1 ]]; then 273 if [[ $USE_NGINX -eq 1 ]]; then 274 backup_and_edit_nginx_http_only 275 if ! systemctl reload nginx; then 276 echo "ERROR: Failed to reload nginx after HTTP-only config changes." 277 exit 1 278 fi 279 else 280 backup_and_edit_apache_http_only 281 if ! systemctl reload apache2; then 282 echo "ERROR: Failed to reload apache2 after HTTP-only config changes." 283 exit 1 284 fi 285 fi 286 fi 287 288 ############################################# 289 # 3. Acquire certificate via certbot 290 ############################################# 291 if [[ $HTTP_ONLY -eq 0 ]]; then 292 echo "Running certbot to obtain certificate for $DOMAIN ..." 293 echo "Please follow the certbot prompts." 294 if ! certbot certonly --webroot -w /var/www/html -d "$DOMAIN"; then 295 echo "ERROR: certbot failed. Exiting." 296 exit 1 297 fi 298 fi 299 300 ############################################################## 301 # 4. Update config to use SSL (unless strictly HTTP only) 302 ############################################################## 303 backup_and_edit_nginx_https() { 304 if [[ ! -f "${CONFIG_FILE_NGINX}.legacy" && -f "$CONFIG_FILE_NGINX" ]]; then 305 sudo cp "$CONFIG_FILE_NGINX" "${CONFIG_FILE_NGINX}.legacy" 306 fi 307 if [[ -f "${CONFIG_FILE_NGINX}.legacy" ]]; then 308 sudo cp "${CONFIG_FILE_NGINX}.legacy" "$CONFIG_FILE_NGINX" 309 fi 310 sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_NGINX" 2>/dev/null 311 312 if [[ $HTTPS_ONLY -eq 1 ]]; then 313 # Insert a simple HTTP->HTTPS redirect into the server block with "listen 80;" 314 sudo sed -i '/listen 80;/a \ 315 if ($scheme = http) { return 301 https://$host$request_uri; }' "$CONFIG_FILE_NGINX" 2>/dev/null 316 fi 317 } 318 319 backup_and_edit_apache_https() { 320 if [[ ! -f "${CONFIG_FILE_APACHE}.legacy" && -f "$CONFIG_FILE_APACHE" ]]; then 321 sudo cp "$CONFIG_FILE_APACHE" "${CONFIG_FILE_APACHE}.legacy" 322 fi 323 if [[ -f "${CONFIG_FILE_APACHE}.legacy" ]]; then 324 sudo cp "${CONFIG_FILE_APACHE}.legacy" "$CONFIG_FILE_APACHE" 325 fi 326 sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_APACHE" 2>/dev/null 327 328 if [[ $HTTPS_ONLY -eq 1 ]]; then 329 # Insert naive rewrite for forcing HTTPS 330 sudo sed -i '/<VirtualHost \*:80>/a \ 331 RewriteEngine On\nRewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R=301,L]' "$CONFIG_FILE_APACHE" 2>/dev/null 332 fi 333 } 334 335 if [[ $HTTP_ONLY -eq 0 ]]; then 336 if [[ $USE_NGINX -eq 1 ]]; then 337 backup_and_edit_nginx_https 338 if ! systemctl reload nginx; then 339 echo "ERROR: Failed to reload nginx after enabling HTTPS." 340 exit 1 341 fi 342 else 343 backup_and_edit_apache_https 344 if ! systemctl reload apache2; then 345 echo "ERROR: Failed to reload apache2 after enabling HTTPS." 346 exit 1 347 fi 348 fi 349 else 350 echo "HTTP-only mode requested; skipping HTTPS config edits." 351 fi 352 353 ################################################## 354 # 5. Activate the configuration and final reload 355 ################################################## 356 if [[ $USE_NGINX -eq 1 ]]; then 357 # Symlink into sites-enabled if not already done 358 if [[ -f "/etc/nginx/sites-available/taler-merchant" && ! -e "/etc/nginx/sites-enabled/taler-merchant" ]]; then 359 echo "Linking /etc/nginx/sites-available/taler-merchant to /etc/nginx/sites-enabled/" 360 ln -s /etc/nginx/sites-available/taler-merchant /etc/nginx/sites-enabled/ 361 fi 362 363 echo "Testing nginx configuration..." 364 if ! nginx -t; then 365 echo "ERROR: 'nginx -t' reported a problem. Please fix the config before proceeding." 366 exit 1 367 fi 368 369 echo "Reloading nginx with new configuration..." 370 if ! systemctl reload nginx; then 371 echo "ERROR: Failed to reload nginx after final activation." 372 exit 1 373 fi 374 else 375 echo "Enabling the taler-merchant site in Apache..." 376 if ! a2ensite taler-merchant; then 377 echo "ERROR: Failed to run 'a2ensite taler-merchant'." 378 exit 1 379 fi 380 381 echo "Reloading Apache with new configuration..." 382 if ! systemctl reload apache2; then 383 echo "ERROR: Failed to reload apache2 after final activation." 384 exit 1 385 fi 386 fi 387 388 echo "Done. Configuration updated and activated for $DOMAIN."