newscript

#!/usr/bin/env bash
# ohs-to-nginx.sh
# Convert *all* Oracle HTTP Server (OHS/Apache httpd) .conf files in a directory
# into ONE CIS-minded nginx.conf. File names are unrestricted as long as they end in .conf.
#
# Multi-instance support:
# - Files may be grouped by a prefix before the first underscore, e.g., OHS1_*.conf, OHS2_*.conf.
# - Files without a prefix belong to the "default" instance.
#
# Output
# - Writes ./nginx_from_ohs/nginx.conf (or to a custom output dir if provided).
#
# Security profile
# - TLS 1.2 ONLY (per requirement) with ECDHE AES-GCM ciphers.
# - CIS-minded http defaults: server_tokens off, hardened timeouts, HSTS, etc.
#
# Usage
#   ./ohs-to-nginx.sh [<ohs_config_dir> [<output_dir>]]
#   example: ./ohs-to-nginx.sh ./ohs_config ./nginx_from_ohs
#
# Notes / Limitations
# - Complex Include graphs, multiple <VirtualHost> blocks, PathTrim/PathPrepend rules are best-effort.
# - This emits at most one HTTP and one HTTPS server per instance. Review & tailor as needed.

set -euo pipefail

OHSDIR=${1:-"./ohs_config"}
OUTDIR=${2:-"./nginx_from_ohs"}
OUTFILE="$OUTDIR/nginx.conf"
mkdir -p "$OUTDIR"

# ----------------------------- helpers ---------------------------------------
trim() {
  # usage: trim "  text  " -> prints "text"
  local s=${1-}
  # strip leading
  s=${s#${s%%[!$'\t\r\n ']*}}
  # strip trailing
  s=${s%${s##*[!$'\t\r\n ']}}
  printf '%s' "$s"
}

lower() { printf '%s' "${1,,}"; }

append_tmp() { TMPFILES+=("$1"); }

declare -a TMPFILES=()
cleanup() { [[ ${#TMPFILES[@]} -gt 0 ]] && rm -f -- "${TMPFILES[@]}" 2>/dev/null || true; }
trap cleanup EXIT ERR INT TERM

# Save original shopt state and enable desired globs locally (in case the caller changed them)
save_globs() { SAVED_GLOBS=$(shopt -p nullglob nocaseglob); shopt -s nullglob nocaseglob; }
restore_globs() { eval "$SAVED_GLOBS"; }

# ------------------------ per-instance state (associative) -------------------
declare -A FILES_BY_INST

# core
declare -A LISTEN SERVERNAME DOCROOT ERRLOG ACCLOG
# ssl
declare -A SSL_ON SSL_CERT SSL_KEY SSL_CHAIN SSL_PROTOCOLS SSL_CIPHERS
# weblogic
declare -A WL_MODE WL_CLUSTER WL_SINGLE_HOST WL_SINGLE_PORT WL_TIMEOUT WL_KEEPALIVE WL_LOC_TMP

init_instance() {
  local inst=$1
  LISTEN[$inst]=""
  SERVERNAME[$inst]=""
  DOCROOT[$inst]=""
  ERRLOG[$inst]=""
  ACCLOG[$inst]=""
  SSL_ON[$inst]=0
  SSL_CERT[$inst]=""
  SSL_KEY[$inst]=""
  SSL_CHAIN[$inst]=""
  SSL_PROTOCOLS[$inst]=""
  SSL_CIPHERS[$inst]=""
  WL_MODE[$inst]="none"
  WL_CLUSTER[$inst]=""
  WL_SINGLE_HOST[$inst]=""
  WL_SINGLE_PORT[$inst]=""
  WL_TIMEOUT[$inst]=""
  WL_KEEPALIVE[$inst]=""
  local t
  t=$(mktemp)
  append_tmp "$t"
  WL_LOC_TMP[$inst]="$t"
}

# ----------------------------- discover files --------------------------------
# Recursively gather all *.conf files under OHSDIR
save_globs
CONF_LIST=$(find "$OHSDIR" -type f -name '*.conf' 2>/dev/null | sort || true)
restore_globs

if [[ -z ${CONF_LIST} ]]; then
  cat >"$OUTFILE" <<'EMPTY'
# Empty nginx.conf generated: no .conf files discovered in the source directory.
# Verify your input path and ensure files end with .conf (recursively searched).
EMPTY
  echo "Wrote: $OUTFILE (empty scaffold)" >&2
  exit 0
fi

# Bucket files by instance
while IFS= read -r f; do
  base=$(basename -- "$f")
  lbase=$(lower "$base")
  inst="default"
  if [[ "$lbase" == *_*.conf ]]; then
    inst=${lbase%%_*}
  fi
  if [[ -n ${FILES_BY_INST[$inst]:-} ]]; then
    FILES_BY_INST[$inst]+=$'\n'"$f"
  else
    FILES_BY_INST[$inst]="$f"
  fi
done <<< "$CONF_LIST"

# ----------------------------- parsing ---------------------------------------
parse_conf_file() {
  local inst=$1 file=$2 inloc=0 lpath="" matchExpr="" sawWL=0
  while IFS= read -r raw || [[ -n ${raw-} ]]; do
    local line=${raw%%#*}
    line=$(trim "$line")
    [[ -z $line ]] && continue

    # <Location ...> tracking for weblogic-handler
    if [[ $line =~ ^<Location[[:space:]]+ ]]; then
      inloc=1
      lpath=${line#<Location }
      lpath=${lpath%>}
      matchExpr=""; sawWL=0
      continue
    fi
    if (( inloc==1 )) && [[ $line =~ ^</Location> ]]; then
      if (( sawWL==1 )); then
        if [[ -n $matchExpr ]]; then
          printf '%s\t%s\t%s\n' "$lpath" "regex" "$matchExpr" >>"${WL_LOC_TMP[$inst]}"
        else
          printf '%s\t%s\t%s\n' "$lpath" "path" "$lpath" >>"${WL_LOC_TMP[$inst]}"
        fi
      fi
      inloc=0; lpath=""; matchExpr=""; sawWL=0
      continue
    fi
    if (( inloc==1 )); then
      case "${line,,}" in
        sethandler\ weblogic-handler) sawWL=1 ;;
        matchexpression*) matchExpr=${line#* } ;;
      esac
      continue
    fi

    # flat directives
    local key=${line%% *}
    local rest=""; [[ "$line" == *" "* ]] && rest=${line#* }
    case "${key,,}" in
      listen)
        # handle "IP:PORT" or "PORT"
        local prt=${rest##*:}
        prt=$(trim "$prt")
        LISTEN[$inst]="$prt" ;;
      servername)
        SERVERNAME[$inst]="$(trim "$rest")" ;;
      documentroot)
        DOCROOT[$inst]="${rest%\"}"; DOCROOT[$inst]="${DOCROOT[$inst]#\"}" ;;
      errorlog)
        ERRLOG[$inst]="$(trim "$rest")" ;;
      customlog)
        ACCLOG[$inst]="$(printf '%s' "$rest" | awk '{print $1}')" ;;
      # SSL
      sslcertificatefile)
        SSL_ON[$inst]=1; SSL_CERT[$inst]="$(trim "$rest")" ;;
      sslcertificatekeyfile)
        SSL_ON[$inst]=1; SSL_KEY[$inst]="$(trim "$rest")" ;;
      sslcertificatechainfile)
        SSL_ON[$inst]=1; SSL_CHAIN[$inst]="$(trim "$rest")" ;;
      sslprotocol)
        SSL_ON[$inst]=1; SSL_PROTOCOLS[$inst]="$(trim "$rest")" ;;
      sslciphersuite)
        SSL_ON[$inst]=1; SSL_CIPHERS[$inst]="$(trim "$rest")" ;;
      # WebLogic
      weblogiccluster)
        WL_MODE[$inst]="cluster"; WL_CLUSTER[$inst]="$(trim "$rest" | tr -d '"')" ;;
      weblogichost)
        WL_SINGLE_HOST[$inst]="$(trim "$rest" | tr -d '"')" ;;
      weblogicport)
        WL_SINGLE_PORT[$inst]="$(trim "$rest" | tr -d '"')" ;;
      connecttimeoutsecs)
        WL_TIMEOUT[$inst]="$(trim "$rest")" ;;
      keepaliveenabled)
        WL_KEEPALIVE[$inst]="$(lower "$(trim "$rest")")" ;;
    esac
  done < "$file"
}

# init + parse per instance
INSTANCES=()
for inst in "${!FILES_BY_INST[@]}"; do INSTANCES+=("$inst"); init_instance "$inst"; done

for inst in "${INSTANCES[@]}"; do
  while IFS= read -r f; do parse_conf_file "$inst" "$f"; done < <(printf '%s\n' "${FILES_BY_INST[$inst]}")
  # derive single-host mode if host+port present and no cluster
  if [[ ${WL_MODE[$inst]} == "none" && -n ${WL_SINGLE_HOST[$inst]} && -n ${WL_SINGLE_PORT[$inst]} ]]; then
    WL_MODE[$inst]="single"
  fi
  [[ -z ${LISTEN[$inst]} ]] && LISTEN[$inst]=80
done

# ----------------------------- security profile ------------------------------
CIS_TLS12_CIPHERS='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'

# ----------------------------- emit nginx.conf -------------------------------
{
  printf '# Generated by ohs-to-nginx.sh on %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  printf '# Source: %s\n\n' "$OHSDIR"
  cat <<'HDR'
user  nginx;
worker_processes  auto;

events {
    worker_connections  10240;
}

http {
    # --- CIS-minded global defaults ---
    server_tokens off;
    include       mime.types;
    default_type  application/octet-stream;
    sendfile      on;
    tcp_nopush    on;
    tcp_nodelay   on;
    keepalive_timeout  15;
    client_body_timeout  15;
    client_header_timeout 15;
    send_timeout         15;
    client_max_body_size 10m;
    access_log  /var/log/nginx/access.log;
    error_log   /var/log/nginx/error.log warn;
HDR
  # [snipped: generation of per-instance blocks]
  printf '}
'
} >"$OUTFILE"

# ----------------------------- README ----------------------------------------
cat > "$OUTDIR/README.txt" <<'EOT'
This nginx.conf was auto-generated from Oracle HTTP Server configs.

Key properties
- Reads ALL *.conf files from the provided directory (recursively); names are unrestricted.
- Groups files by instance prefix before the first underscore; unprefixed => "default".
- CIS-minded HTTP defaults; TLS 1.2 only with ECDHE AES-GCM cipher suites.

Review checklist
1) Verify upstream servers/ports (under upstream <instance>_weblogic).
2) Confirm server_name/root and log paths.
3) If OHS used PathTrim/PathPrepend/MatchExpression, add equivalent rewrites.
4) Check certificate/key paths and bundle chain as needed.
5) Validate and reload: nginx -t && systemctl reload nginx
EOT

printf 'Wrote: %s\n' "$OUTFILE"
Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments