website-scripts/Odoo/Install-Odoo16-Debian11.sh

341 lines
12 KiB
Bash

#!/bin/bash
#
# Install Odoo 16 on Debian 11 with LetsEncrypt SSL certificate
# Created by Rob Fauls 10/27/2022
#
# Description:
# This script automates the installation of Odoo 16 on a fresh Debian 11 system.
# It configures Nginx as a reverse proxy and sets up Let's Encrypt SSL certificate.
#
# Usage:
# - Run the script as a user with sudo privileges.
# - Make sure you have a fresh install of Debian 11 with a domain name and accessible ports 80 and 443.
# - Follow the prompts to enter the domain name and email address associated with the SSL certificate.
# - The script will update the system, install prerequisites, install Odoo 16, configure Let's Encrypt, and set up Nginx.
#
# Dependencies:
# - wget, gnupg2, certbot, python3-certbot-nginx
#
# Note: Please review the script and modify it to fit your specific requirements.
#
# Feel free to use and modify this script, ensuring that you contribute any improvements back to the source.
#
if [ "$EUID" -ne 0 ]
then
echo "This script must be run with sudo privileges. Exiting."
exit 1
fi
#If anything fails, exit the script.
set -e
# Set the log file path
LOG_FILE="$(dirname "$0")/OdooInstall.log"
# Redirect stdout and stderr to the log file
exec > >(tee -a "$LOG_FILE") 2>&1
# Function to print print_to_terminal commands to the terminal
print_to_terminal() {
echo ">> $@"
}
print_to_terminal "SYSTEM REQUIREMENTS"
print_to_terminal "Fresh install of Debian 11"
print_to_terminal "Domain name"
print_to_terminal "Public IP with ports 80 and 443 accessible (LetsEncrypt)"
print_to_terminal ""
print_to_terminal "Please be sure everything is properly configured."
print_to_terminal "If you are missing the domain name or ports, LetsEncrypt and Nginx will not be properly configured"
#Install prerequisites
print_to_terminal "Making sure we have the basics installed before beginning..."
DEBIAN_FRONTEND=noninteractive apt-get install -qq -y wget gnupg2 curl >/dev/null 2>&1
# Check the installation status
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to install prerequisites. Exiting."
exit 1
fi
# Create an empty crontab for root if it doesn't exist
if ! crontab -l -u root >/dev/null 2>&1; then
echo | crontab -u root -
fi
###START Check if user would like to update the script###
read -rp "Would you like to check for an updated script? [y/N]: " response
# Convert the response to lowercase for case-insensitive comparison
response=${response,,}
# Check if the user wants to check for an updated script
if [[ $response == "y" || $response == "yes" ]]; then
# Retrieve the latest version of the script
curl -s -o odoo_install_update.sh https://code.flatironnetworks.com/RobFauls-Com/website-scripts/raw/branch/main/Odoo/Install-Odoo16-Debian11.sh
# Calculate the hash values
current_hash=$(md5sum "$0" | awk '{print $1}')
updated_hash=$(md5sum odoo_install_update.sh | awk '{print $1}')
# Compare the hash values
if [[ $current_hash != $updated_hash ]]; then
print_to_terminal "An update is available. Performing self-update..."
# Replace the existing script with the updated script
mv odoo_install_update.sh "$0"
chmod +x "$0"
# Run the updated script
exec "$0" "$@"
else
print_to_terminal "The script is already up to date."
fi
else
print_to_terminal "Skipping script update."
fi
###FINISH Check if user would like to update the script###
###START Unattended Upgrades###
read -rp "Would you like to enable unattended upgrades for automatic security updates? [y/N]: " response
# Convert the response to lowercase for case-insensitive comparison
response=${response,,}
if [[ $response == "y" || $response == "yes" ]]; then
# Install unattended-upgrades package
apt-get update >/dev/null 2>&1
apt-get install unattended-upgrades -y >/dev/null 2>&1
# Configure unattended-upgrades
cat <<EOT > /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
EOT
# Customize the configuration as needed
cat <<EOT > /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"\${distro_id}:\${distro_codename}-security";
"\${distro_id}:\${distro_codename}-updates";
"\${distro_id}:\${distro_codename}-proposed";
"\${distro_id}:\${distro_codename}-backports";
};
Unattended-Upgrade::Package-Blacklist {
// Uncomment the following line to exclude specific packages from automatic upgrades
// "package-name";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Mail "false";
EOT
# Enable and start the unattended-upgrades service
systemctl enable unattended-upgrades
systemctl start unattended-upgrades
print_to_terminal "Unattended upgrades have been enabled."
else
print_to_terminal "Unattended upgrades have not been enabled."
fi
###FINISH Unattended Upgrades###
###BEGIN Gather user input###
print_to_terminal "Let's collect some information about your environment"
# Validate domain name
while true; do
print_to_terminal "Please enter your domain name:"
read -r DOMAIN
# Validate domain name using regular expression
if [[ ! $DOMAIN =~ ^[a-zA-Z0-9]+([-.][a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$ ]]; then
print_to_terminal "Invalid domain name. Please enter a valid domain name."
else
break
fi
done
# Validate email address
while true; do
print_to_terminal "Please enter the email address you'd like to associate with the SSL certificate:"
read -r EMAIL
# Validate email address using regular expression
if [[ ! $EMAIL =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
print_to_terminal "Invalid email address. Please enter a valid email address."
else
break
fi
done
###END Gather user input###
#Make sure system is up to date and remove any unnecessary packages
print_to_terminal "Checking for updates."
apt update >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to update packages. Exiting."
exit 1
fi
print_to_terminal "Applying system updates."
apt upgrade -y >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to install packages. Exiting."
exit 1
fi
print_to_terminal "Autoremoving unnecessary packages."
apt autoremove -y >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to auto-remove packages. Exiting."
exit 1
fi
#Install wkhtmltopdf
print_to_terminal "Installing wkhtmltopdf"
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.bullseye_amd64.deb >/dev/null 2>&1
apt install ./wkhtmltox*bullseye_amd64.deb -y >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to install wkhtmltopdf. Exiting."
exit 1
fi
#Install Odoo 16
print_to_terminal "Installing Odoo 16."
print_to_terminal "This may take a few minutes, as Odoo's servers can be a bit slow..."
wget https://nightly.odoo.com/odoo.key >/dev/null 2>&1
cat odoo.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/odoo.gpg >/dev/null 2>&1
echo "deb http://nightly.odoo.com/16.0/nightly/deb/ ./" | tee -a /etc/apt/sources.list.d/odoo.list >/dev/null
apt update >/dev/null 2>&1
apt install odoo -y >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to install Odoo. Exiting."
exit 1
fi
#Install LetsEncrypt and configure SSL certificates
print_to_terminal "Installing LetsEncrypt and configuring SSL certificates."
apt install certbot python3-certbot-nginx -y >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to install Let's Encrypt and Certbot. Exiting."
exit 1
fi
systemctl stop nginx
/usr/bin/certbot certonly --standalone -d ${DOMAIN} --preferred-challenges http --agree-tos -n -m ${EMAIL} --keep-until-expiring >/dev/null 2>&1
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to configure SSL certificates with Let's Encrypt. Exiting."
exit 1
fi
#Insert cron job for LetsEncypt refresh certs into crontab
print_to_terminal "Configuring cron job to renew LetsEncrypt Certificates"
crontab -l; echo "15 3 * * * /usr/bin/certbot renew --pre-hook 'systemctl stop nginx' --post-hook 'systemctl start nginx'" | sort -u | crontab - >/dev/null 2>&1
#Create Nginx configuration file:
cat <<EOF >/etc/nginx/sites-available/odoo.conf
#odoo server
upstream odoo {
server 127.0.0.1:8069;
}
upstream odoochat {
server 127.0.0.1:8072;
}
map \$http_upgrade \$connection_upgrade {
default upgrade;
'' close;
}
# http -> https
server {
listen 80;
server_name $DOMAIN;
rewrite ^(.*) https://\$host$1 permanent;
}
server {
listen 443 ssl;
server_name $DOMAIN;
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
# Add Headers for odoo proxy mode
proxy_set_header X-Forwarded-Host \$host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Real-IP \$remote_addr;
# SSL parameters
ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/$DOMAIN/chain.pem;
ssl_session_timeout 30m;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# log
access_log /var/log/nginx/odoo.access.log;
error_log /var/log/nginx/odoo.error.log;
# Redirect websocket requests to odoo gevent port
location /websocket {
proxy_pass http://odoochat;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$connection_upgrade;
proxy_set_header X-Forwarded-Host \$host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Real-IP \$remote_addr;
}
# Redirect requests to odoo backend server
location / {
proxy_redirect off;
proxy_pass http://odoo;
}
# common gzip
gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
gzip on;
}
EOF
#Create symlink to enable the site
ln -s /etc/nginx/sites-available/odoo.conf /etc/nginx/sites-enabled/
if [ $? -ne 0 ]; then
print_to_terminal "Error: Failed to create symlink for Nginx configuration. Exiting."
exit 1
fi
# Check health of Nginx configuration
print_to_terminal "Checking health of NGINX configuration."
if ! nginx -t; then
print_to_terminal "Error: Nginx configuration test failed. Exiting."
exit 1
fi
#Modify odoo.conf to properly use Nginx, allow chat to work, and define the default addons path
cat <<EOF >>/etc/odoo/odoo.conf
proxy_mode = True
max_cron_threads = 1
workers = 2
longpolling_port = 8072
addons_path = /var/lib/odoo/.local/share/Odoo/addons/16.0
EOF
#Restart Odoo and Nginx
systemctl restart odoo
systemctl restart nginx
print_to_terminal
print_to_terminal
print_to_terminal "Odoo16 installation has completed!"
print_to_terminal "If you're using CloudFlare, you may need to modify the SSL/TLS encryption mode."
print_to_terminal "Without modifying the encryption mode, you may be unable to access the site"
print_to_terminal
print_to_terminal "Please go to https://"${DOMAIN}"/ to access your installation."
print_to_terminal ${RED}"https://"${DOMAIN}":8069 is also currently accessible."${RESET}
print_to_terminal ${YELLOW}"You may consider blocking port 8069 to avoid unsecure or uncached connections to Odoo."${RESET}