merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

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."