#!/bin/bash

sectionPrompt() {
	printf "\n"
	IFS=
	while true; do
		printf "=> $@ [Y/n]"
		read -rs -n 1 key
		case $key in
			'Y'|'y'|' '|'' )
				printf " starting.\n"
				return 0;;
			'N'|'n'|$'\t' )
				printf " skipping.\n"
				return 1;;
			$'\e' )
				printf " exiting.\n"
				sleep 0.5
				exit 0;;
			* )
				printf " invalid input.\n";;
		esac
	done
}



# Development web server configuration
if sectionPrompt "Set up as development web server?"; then
	release="bookworm"
	user="web-dev"
	php="8.2"
	dev="true"
		dev_tools="clang clang-19"
	proxy="false"
# Main web server configuration
elif sectionPrompt "Set up as production web server?"; then
	release="bookworm"
	user="web-main"
	php="8.2"
	dev="false"
	proxy="false"
# Proxy configuration
elif sectionPrompt "Set up as web proxy?"; then
	release="bookworm"
	user="proxy"
	php="8.2"
	dev="false"
	proxy="true"
		cloudflare_cred="./cloudflare.ini"
else
	printf "\nEnd of choices. Exiting.\n"
	exit
fi




##
## Configure sources and update
##

sectionPrompt "Configure sources?" && {
	cat > /etc/apt/sources.list.d/debian.sources <<- EOF
		Types: deb
		URIs: https://deb.debian.org/debian
		Suites: $release $release-updates
		Components: main contrib
		Enabled: yes
		Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg

		Types: deb
		URIs: https://security.debian.org/debian-security
		Suites: $release-security
		Components: main contrib
		Enabled: yes
		Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
	EOF
	cat > /etc/apt/sources.list <<- EOF
		# Sources should be defined in "/etc/apt/sources.list.d/debian.sources".
		# Old one-line-style sources can still be defined here if needed.
	EOF

	apt update
}

sectionPrompt "Upgrade system?" && {
	apt full-upgrade -y
}



##
## Set up user
##

sectionPrompt "Create user: $user?" && {
	deluser $user
	mkdir -p /home/$user
	adduser --home /home/$user $user
}

sectionPrompt "Set up sudo?" && {
	apt install -y sudo
	usermod -aG sudo $user
}

sectionPrompt "Increase user file limits?" && {
	cat > /etc/security/limits.d/$user.conf <<- EOF
		$user soft nofile 65536
	EOF
}



##
## Set up SSH
##

sectionPrompt "Install SSH?" && {
	apt install -y openssh-server
	if [ "$dev" = "true" ]; then
		sed -i "s/^#\?AllowTcpForwarding .*/AllowTcpForwarding yes/" /etc/ssh/sshd_config
	fi
	systemctl enable ssh
	systemctl start ssh

	lan_addr="$(ip route get 255.255.255.255 | grep -oP '(?<=src )[^ ]*')"
	cat <<- EOS
		
		The following commands can be run on a device to be used as an SSH client.
		
		Create a new SSH key pair for web servers (or use an existing key):
		    ssh-keygen -f ~/.ssh/id_ed25519_web -t ed25519
		The copy the public key to this server (from local network):
		    ssh-copy-id -i ~/.ssh/id_ed25519_web $user@$lan_addr
		
		Then add the following entry to ~/.ssh/config:
		Host $lan_addr
		  HostName $lan_addr
		  User $user
		  IdentityFile ~/.ssh/id_ed25519_web
	EOS
}



##
## Install development tools
##

if [ "$dev" = "true" ]; then
	sectionPrompt "Install development tools?" && {
		apt install -y build-essential $dev_tools
	}
fi



##
## Install Nginx
##

sectionPrompt "Install Nginx?" && {
	apt install -y curl gnupg2 ca-certificates debian-archive-keyring
	curl https://nginx.org/keys/nginx_signing.key \
		| gpg --dearmor \
		| tee /usr/share/keyrings/nginx-archive-keyring.gpg > /dev/null

	cat > /etc/apt/sources.list.d/nginx.sources <<- EOF
		Types: deb
		URIs: http://nginx.org/packages/mainline/debian
		Suites: $release
		Components: nginx
		Enabled: yes
		Signed-By: /usr/share/keyrings/nginx-archive-keyring.gpg
	EOF

	echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
		| tee /etc/apt/preferences.d/99nginx

	apt update
	apt install -y nginx

	systemctl enable nginx
}



##
## Configure Nginx
##

sectionPrompt "Configure Nginx?" && {
	cp -r /etc/nginx /tmp/nginx-conf
	rm -rf /etc/nginx/*
	cp /tmp/nginx-conf/nginx.conf /etc/nginx/nginx.conf.bak
	cp /tmp/nginx-conf/mime.types /etc/nginx/mime.types.bak
	if [ -f /tmp/nginx-conf/fastcgi.conf ]; then
		cp /tmp/nginx-conf/fastcgi.conf /etc/nginx/fastcgi.conf.bak
	fi
	mkdir /etc/nginx/conf.d /etc/nginx/sites-enabled
	if [ -f /tmp/nginx-conf/conf.d/default.conf ]; then
		mv /tmp/nginx-conf/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
	fi
	cp -r /tmp/nginx-conf/modules /etc/nginx/modules
	rm -rf /tmp/nginx-conf

	mkdir -p /etc/nginx/log
	# This directory must exist to prevent an Nginx alert on startup (not necessary)
	mkdir -p /var/log/nginx

	# Create nginx.conf
	if [ "$proxy" = "true" ]; then
		cat > /etc/nginx/nginx.conf <<- EOF
			user $user;
			worker_processes auto;
			worker_rlimit_nofile 65536;
			error_log /etc/nginx/log/error.log;
			include /etc/nginx/modules/*.conf;
			include /etc/nginx/conf.d/*.conf;
			pcre_jit on;
			
			events {
			    worker_connections 65536;
			}
			
			http {
			    # Server and header optimizations
			    sendfile on;
			    tcp_nopush on;
			    tcp_nodelay on;
			    server_tokens off;
			    etag off;
			
			    # Prevents using temporary files and reduces latency
			    proxy_buffering off;
			    #proxy_temp_path /tmp;
			
			    # Consistent redirects
			    server_name_in_redirect off;
			    port_in_redirect off;
			
			    include /etc/nginx/mime.types;
			    default_type application/octet-stream;
			
			    # Logging
			    access_log /etc/nginx/log/access.log;
			    log_not_found off;
			
			    http2 on;
			
			    # SSL
			    ssl_protocols TLSv1.2 TLSv1.3;
			    ssl_prefer_server_ciphers on;
			    ssl_session_tickets off;
			
			    # Gzip
			    gzip on;
			    gzip_vary on;
			    gzip_proxied any;
			    gzip_comp_level 2;
			    gzip_http_version 1.1;
			    gzip_types text/css application/javascript text/plain text/xml application/xml;
			
			    # Hosts, redirects, and error configurations
			    include /etc/nginx/sites-enabled/*.conf;
			    include /etc/nginx/sites-enabled/redirects/*.conf;
			    include /etc/nginx/sites-enabled/errors/*.conf;
			}
		EOF
	else
		cat > /etc/nginx/nginx.conf <<- EOF
			user $user;
			worker_processes auto;
			worker_rlimit_nofile 65536;
			error_log /etc/nginx/log/error.log;
			include /etc/nginx/modules/*.conf;
			include /etc/nginx/conf.d/*.conf;
			pcre_jit on;
			
			events {
			    worker_connections 65536;
			}
			
			http {
			    # Server and header optimizations
			    sendfile on;
			    tcp_nopush on;
			    tcp_nodelay on;
			    server_tokens off;
			    etag off;
			
			    # Consistent redirects
			    server_name_in_redirect off;
			    port_in_redirect off;
			
			    include /etc/nginx/mime.types;
			    default_type application/octet-stream;
			
			    # Logging
			    access_log /etc/nginx/log/access.log;
			    log_not_found off;
			
			    http2 on;
			
			    # Gzip
			    gzip off;
			
			    # Host configurations
			    include /etc/nginx/sites-enabled/*.conf;
			}
		EOF
	fi

	cat > /etc/nginx/fastcgi.conf <<- EOF
		fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
		fastcgi_param  QUERY_STRING       $query_string;
		fastcgi_param  REQUEST_METHOD     $request_method;
		fastcgi_param  CONTENT_TYPE       $content_type;
		fastcgi_param  CONTENT_LENGTH     $content_length;
		
		fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
		fastcgi_param  REQUEST_URI        $request_uri;
		fastcgi_param  DOCUMENT_URI       $document_uri;
		fastcgi_param  DOCUMENT_ROOT      $document_root;
		fastcgi_param  SERVER_PROTOCOL    $server_protocol;
		fastcgi_param  REQUEST_SCHEME     $scheme;
		fastcgi_param  HTTPS              $https if_not_empty;
		
		fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
		fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
		
		fastcgi_param  REMOTE_ADDR        $remote_addr;
		fastcgi_param  REMOTE_PORT        $remote_port;
		fastcgi_param  REMOTE_USER        $remote_user;
		fastcgi_param  SERVER_ADDR        $server_addr;
		fastcgi_param  SERVER_PORT        $server_port;
		fastcgi_param  SERVER_NAME        $server_name;
		
		# PHP only, required if PHP was built with --enable-force-cgi-redirect
		fastcgi_param  REDIRECT_STATUS    200;
	EOF

	cat > /etc/nginx/mime.types <<- EOF
		types {
		    text/html                                        html htm shtml;
		    text/css                                         css;
		    text/xml                                         xml;
		    image/gif                                        gif;
		    image/jpeg                                       jpeg jpg;
		    application/javascript                           js;
		    application/atom+xml                             atom;
		    application/rss+xml                              rss;
		
		    text/mathml                                      mml;
		    # Added sh and bash
		    text/plain                                       txt sh bash;
		    text/vnd.sun.j2me.app-descriptor                 jad;
		    text/vnd.wap.wml                                 wml;
		    text/x-component                                 htc;
		
		    image/avif                                       avif;
		    image/png                                        png;
		    image/svg+xml                                    svg svgz;
		    image/tiff                                       tif tiff;
		    image/vnd.wap.wbmp                               wbmp;
		    image/webp                                       webp;
		    image/x-icon                                     ico;
		    image/x-jng                                      jng;
		    image/x-ms-bmp                                   bmp;
		
		    # Added font/ttf
		    font/ttf                                         ttf;
		    font/woff                                        woff;
		    font/woff2                                       woff2;
		
		    application/java-archive                         jar war ear;
		    application/json                                 json;
		    application/mac-binhex40                         hqx;
		    application/msword                               doc;
		    application/pdf                                  pdf;
		    application/postscript                           ps eps ai;
		    application/rtf                                  rtf;
		    application/vnd.apple.mpegurl                    m3u8;
		    application/vnd.google-earth.kml+xml             kml;
		    application/vnd.google-earth.kmz                 kmz;
		    application/vnd.ms-excel                         xls;
		    application/vnd.ms-fontobject                    eot;
		    application/vnd.ms-powerpoint                    ppt;
		    application/vnd.oasis.opendocument.graphics      odg;
		    application/vnd.oasis.opendocument.presentation  odp;
		    application/vnd.oasis.opendocument.spreadsheet   ods;
		    application/vnd.oasis.opendocument.text          odt;
		    application/vnd.openxmlformats-officedocument.presentationml.presentation
		                                                    pptx;
		    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
		                                                    xlsx;
		    application/vnd.openxmlformats-officedocument.wordprocessingml.document
		                                                    docx;
		    application/vnd.wap.wmlc                         wmlc;
		    application/wasm                                 wasm;
		    application/x-7z-compressed                      7z;
		    application/x-cocoa                              cco;
		    application/x-java-archive-diff                  jardiff;
		    application/x-java-jnlp-file                     jnlp;
		    application/x-makeself                           run;
		    application/x-perl                               pl pm;
		    application/x-pilot                              prc pdb;
		    application/x-rar-compressed                     rar;
		    application/x-redhat-package-manager             rpm;
		    application/x-sea                                sea;
		    application/x-shockwave-flash                    swf;
		    application/x-stuffit                            sit;
		    application/x-tcl                                tcl tk;
		    application/x-x509-ca-cert                       der pem crt;
		    application/x-xpinstall                          xpi;
		    application/xhtml+xml                            xhtml;
		    application/xspf+xml                             xspf;
		    application/zip                                  zip;
		
		    application/octet-stream                         bin exe dll;
		    application/octet-stream                         deb;
		    application/octet-stream                         dmg;
		    application/octet-stream                         iso img;
		    application/octet-stream                         msi msp msm;
		
		    audio/midi                                       mid midi kar;
		    audio/mpeg                                       mp3;
		    audio/ogg                                        ogg;
		    audio/x-m4a                                      m4a;
		    audio/x-realaudio                                ra;
		
		    video/3gpp                                       3gpp 3gp;
		    video/mp2t                                       ts;
		    video/mp4                                        mp4;
		    video/mpeg                                       mpeg mpg;
		    video/quicktime                                  mov;
		    video/webm                                       webm;
		    video/x-flv                                      flv;
		    video/x-m4v                                      m4v;
		    video/x-mng                                      mng;
		    video/x-ms-asf                                   asx asf;
		    video/x-ms-wmv                                   wmv;
		    video/x-msvideo                                  avi;
		}
	EOF
}



##
## Proxy DNS and SSL
##

if [ "$proxy" = "true" ]; then
	sectionPrompt "Create self-signed certificate?" && {
		apt install -y openssl
		# Create a self-signed certificate
		mkdir -p /etc/nginx/self-signed
		openssl req -x509 -newkey rsa:4096 \
			-keyout /etc/nginx/self-signed/private.key \
			-out /etc/nginx/self-signed/cert.pem \
			-sha256 -days 36500 -nodes -subj "/CN=localhost"
	}
	sectionPrompt "Set up Certbot?" && {
		apt install -y certbot python3-certbot-dns-cloudflare

		# Example cloudflare.ini file
		#
		## Cloudflare API token used by Certbot
		#dns_cloudflare_api_token = <api_token>

		# Prompts to create certificates
		printf "\n=> Enter domains to create certificates (space separated):\n"
		while true; do
			printf " -> Enter domains (leave blank to stop): "
			read -r -a domains
			if [ ${#domains[@]} -eq 0 ]; then
				break
			fi
			args=""
			for domain in "${domains[@]}"; do
				args+=("-d" "$domain")
			done
			certbot certonly --dns-cloudflare \
				--dns-cloudflare-credentials "$cloudflare_cred" \
				-d ${args[@]}
		done
	}
fi



##
## Install and configure PHP
##

sectionPrompt "Install PHP?" && {
	apt install -y php$php-fpm

	sectionPrompt "Configure PHP?" && {
		# Set user as PHP user
		sed -i "s/^;\?\(user\|group\|listen\.owner\|listen\.group\) = .*/\1 = $user/" /etc/php/$php/fpm/pool.d/www.conf
		sed -i "s/^;\?listen = .*/listen = \/run\/php\/php$php-fpm.sock/" /etc/php/$php/fpm/pool.d/www.conf
		# Set PHP error log to Nginx directory for convenience
		sed -i "s/^;\?error_log = .*/error_log = \/etc\/nginx\/log\/php-error.log/" /etc/php/$php/fpm/php-fpm.conf
		# Disable "X-Powered-By" PHP header
		sed -i "s/^;\?expose_php = On/expose_php = Off/" /etc/php/$php/fpm/php.ini
	}

	systemctl enable php$php-fpm
}



##
## Set permissions
##

sectionPrompt "Set user home and Nginx config directory owner to $user?" && {
	chown -R $user:$user /etc/nginx
	chown -R $user:$user /home/$user
}



##
## Start services
##

sectionPrompt "Start services?" && {
	systemctl restart nginx
	systemctl start php$php-fpm
}