-
-
Save MMTE/9ede9fceff2d54063f3af9ee1bda7c52 to your computer and use it in GitHub Desktop.
Laravel Forge Setup Script (July 2020) - NGINX + MySQL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Replace! | |
# [!server!] (the forge server instance) | |
# [!sudo_password!] (random password for sudo) | |
# [!db_password!] (random password for database user) | |
# [!user.name!] (git user name) | |
# [!user.email!] (git user email) | |
# [!server_ip!] (git user email) | |
# | |
# REQUIRES: | |
# - server (the forge server instance) | |
# - event (the forge event instance) | |
# - sudo_password (random password for sudo) | |
# - db_password (random password for database user) | |
# - callback (the callback URL) | |
# - recipe_id (recipe id to run at the end) | |
# | |
apt_wait () { | |
while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do | |
echo "Waiting: dpkg/lock is locked..." | |
sleep 5 | |
done | |
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do | |
echo "Waiting: dpkg/lock-frontend is locked..." | |
sleep 5 | |
done | |
while fuser /var/lib/apt/lists/lock >/dev/null 2>&1; do | |
echo "Waiting: lists/lock is locked..." | |
sleep 5 | |
done | |
if [ -f /var/log/unattended-upgrades/unattended-upgrades.log ]; then | |
while fuser /var/log/unattended-upgrades/unattended-upgrades.log >/dev/null 2>&1; do | |
echo "Waiting: unattended-upgrades is locked..." | |
sleep 5 | |
done | |
fi | |
} | |
echo "Checking apt-get availability..." | |
apt_wait | |
sudo sed -i "s/#precedence ::ffff:0:0\/96 100/precedence ::ffff:0:0\/96 100/" /etc/gai.conf | |
# Upgrade The Base Packages | |
export DEBIAN_FRONTEND=noninteractive | |
apt-get update | |
apt_wait | |
apt-get upgrade -y | |
apt_wait | |
# Add A Few PPAs To Stay Current | |
apt-get install -y --force-yes software-properties-common | |
# apt-add-repository ppa:fkrull/deadsnakes-python2.7 -y | |
# apt-add-repository ppa:nginx/mainline -y apt-add-repository ppa:ondrej/nginx -y | |
# apt-add-repository ppa:chris-lea/redis-server -y apt-add-repository ppa:ondrej/apache2 -y apt-add-repository ppa:ondrej/php -y | |
apt_wait | |
# Setup MariaDB Repositories # | |
# Update Package Lists | |
apt-get update | |
apt_wait | |
# Base Packages | |
add-apt-repository universe | |
apt-get install -y --force-yes build-essential curl pkg-config fail2ban gcc g++ git libmcrypt4 libpcre3-dev \ | |
make python3 python3-pip sendmail supervisor ufw unzip whois zsh ncdu awscli uuid-runtime acl | |
# Install Python Httpie | |
pip3 install httpie | |
# Disable Password Authentication Over SSH | |
sed -i "/PasswordAuthentication yes/d" /etc/ssh/sshd_config | |
echo "" | sudo tee -a /etc/ssh/sshd_config | |
echo "" | sudo tee -a /etc/ssh/sshd_config | |
echo "PasswordAuthentication no" | sudo tee -a /etc/ssh/sshd_config | |
# Restart SSH | |
ssh-keygen -A service ssh restart | |
# Set The Hostname If Necessary | |
echo "[!server!]" > /etc/hostname sed -i 's/127\.0\.0\.1.*localhost/127.0.0.1 [!server!].localdomain [!server!] localhost/' /etc/hosts | |
hostname [!server!] | |
# Set The Timezone | |
# ln -sf /usr/share/zoneinfo/UTC /etc/localtime | |
ln -sf /usr/share/zoneinfo/UTC /etc/localtime | |
# Create The Root SSH Directory If Necessary | |
if [ ! -d /root/.ssh ] | |
then | |
mkdir -p /root/.ssh | |
touch /root/.ssh/authorized_keys | |
fi | |
# Setup Forge User | |
useradd forge | |
mkdir -p /home/forge/.ssh | |
mkdir -p /home/forge/.forge | |
adduser forge sudo | |
# Setup Bash For Forge User | |
chsh -s /bin/bash forge | |
cp /root/.profile /home/forge/.profile | |
cp /root/.bashrc /home/forge/.bashrc | |
# Set The Sudo Password For Forge | |
#PASSWORD=$(mkpasswd -m sha-512 [!sudo_password!]) | |
PASSWORD=$(mkpasswd [!sudo_password!]) | |
usermod --password $PASSWORD forge | |
# Build Formatted Keys & Copy Keys To Forge | |
#cat > /root/.ssh/authorized_keys << EOF | |
## Laravel Forge | |
#ssh-rsa AAAAB3NzaC1yc2EA___________iPgSUl1XzgHHTr01vkEV [email protected] | |
#EOF | |
#cp /root/.ssh/authorized_keys /home/forge/.ssh/authorized_keys | |
# Create The Server SSH Key | |
#ssh-keygen -f /home/forge/.ssh/id_rsa -t rsa -N '' | |
# Copy Source Control Public Keys Into Known Hosts File | |
ssh-keyscan -H github.com >> /home/forge/.ssh/known_hosts | |
ssh-keyscan -H bitbucket.org >> /home/forge/.ssh/known_hosts | |
ssh-keyscan -H gitlab.com >> /home/forge/.ssh/known_hosts | |
# Configure Git Settings | |
git config --global user.name "[!user.name!]" | |
git config --global user.email "[!user.email!]" | |
# Add The Reconnect Script Into Forge Directory | |
cat > /home/forge/.forge/reconnect << EOF | |
#!/usr/bin/env bash | |
echo "# Laravel Forge" | tee -a /home/forge/.ssh/authorized_keys > /dev/null | |
echo \$1 | tee -a /home/forge/.ssh/authorized_keys > /dev/null | |
echo "# Laravel Forge" | tee -a /root/.ssh/authorized_keys > /dev/null | |
echo \$1 | tee -a /root/.ssh/authorized_keys > /dev/null | |
echo "Keys Added!" | |
EOF | |
# Setup Forge Home Directory Permissions | |
chown -R forge:forge /home/forge | |
chmod -R 755 /home/forge | |
chmod 700 /home/forge/.ssh/id_rsa | |
# Setup UFW Firewall | |
ufw allow 22 | |
ufw allow 80 | |
ufw allow 443 | |
ufw --force enable | |
# Allow FPM Restart | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.4-fpm reload" > /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.3-fpm reload" >> /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.2-fpm reload" >> /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.1-fpm reload" >> /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.0-fpm reload" >> /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php5.6-fpm reload" >> /etc/sudoers.d/php-fpm | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php5-fpm reload" >> /etc/sudoers.d/php-fpm | |
# Allow Nginx Reload | |
echo "forge ALL=NOPASSWD: /usr/sbin/service nginx *" >> /etc/sudoers.d/nginx | |
# Allow Supervisor Reload | |
echo "forge ALL=NOPASSWD: /usr/bin/supervisorctl *" >> /etc/sudoers.d/supervisor | |
apt_wait | |
# | |
# REQUIRES: | |
# - server (the forge server instance) | |
# | |
# Install Base PHP Packages | |
apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y --force-yes php7.4-cli php7.4-fpm php7.4-dev \ php7.4-pgsql php7.4-sqlite3 php7.4-gd \ php7.4-curl php7.4-memcached \ php7.4-imap php7.4-mysql php7.4-mbstring \ php7.4-xml php7.4-zip php7.4-bcmath php7.4-soap \ php7.4-intl php7.4-readline php7.4-msgpack php7.4-igbinary | |
# Install Composer Package Manager | |
curl -sS https://getcomposer.org/installer | php | |
mv composer.phar /usr/local/bin/composer | |
# Misc. PHP CLI Configuration | |
sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/7.4/cli/php.ini | |
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php/7.4/cli/php.ini | |
sudo sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/" /etc/php/7.4/cli/php.ini | |
sudo sed -i "s/memory_limit = .*/memory_limit = 512M/" /etc/php/7.4/cli/php.ini | |
sudo sed -i "s/;date.timezone.*/date.timezone = UTC/" /etc/php/7.4/cli/php.ini | |
# Ensure PHPRedis Extension Is Available | |
echo "Configuring PHPRedis" echo "extension=redis.so" > /etc/php/7.4/mods-available/redis.ini yes '' | apt install php-redis | |
# Configure FPM Pool Settings | |
sed -i "s/^user = www-data/user = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/^group = www-data/group = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.owner.*/listen.owner = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.group.*/listen.group = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.mode.*/listen.mode = 0666/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;request_terminate_timeout.*/request_terminate_timeout = 60/" /etc/php/7.4/fpm/pool.d/www.conf | |
# Ensure Sudoers Is Up To Date | |
echo "forge ALL=NOPASSWD: /usr/sbin/service php7.4-fpm reload" >> /etc/sudoers.d/php-fpm | |
# Configure Sessions Directory Permissions | |
chmod 733 /var/lib/php/sessions | |
chmod +t /var/lib/php/sessions | |
# Write Systemd File For Linode | |
update-alternatives --set php /usr/bin/php7.4 | |
# REQUIRES: | |
# - server (the forge server instance) | |
# - site_name (the name of the site folder) | |
# # Install Nginx & PHP-FPM | |
apt-get install -y --force-yes nginx systemctl enable nginx.service | |
# Generate dhparam File | |
openssl dhparam -out /etc/nginx/dhparams.pem 2048 | |
# Tweak Some PHP-FPM Settings | |
sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/7.4/fpm/php.ini | |
sed -i "s/display_errors = .*/display_errors = On/" /etc/php/7.4/fpm/php.ini | |
sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/" /etc/php/7.4/fpm/php.ini | |
sed -i "s/memory_limit = .*/memory_limit = 512M/" /etc/php/7.4/fpm/php.ini | |
sed -i "s/;date.timezone.*/date.timezone = UTC/" /etc/php/7.4/fpm/php.ini | |
# Configure FPM Pool Settings | |
sed -i "s/^user = www-data/user = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/^group = www-data/group = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.owner.*/listen.owner = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.group.*/listen.group = forge/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;listen\.mode.*/listen.mode = 0666/" /etc/php/7.4/fpm/pool.d/www.conf | |
sed -i "s/;request_terminate_timeout.*/request_terminate_timeout = 60/" /etc/php/7.4/fpm/pool.d/www.conf | |
# Configure Primary Nginx Settings | |
sed -i "s/user www-data;/user forge;/" /etc/nginx/nginx.conf | |
sed -i "s/worker_processes.*/worker_processes auto;/" /etc/nginx/nginx.conf | |
sed -i "s/# multi_accept.*/multi_accept on;/" /etc/nginx/nginx.conf | |
sed -i "s/# server_names_hash_bucket_size.*/server_names_hash_bucket_size 128;/" /etc/nginx/nginx.conf | |
# Configure Gzip | |
cat > /etc/nginx/conf.d/gzip.conf << EOF | |
gzip_comp_level 5; | |
gzip_min_length 256; | |
gzip_proxied any; | |
gzip_vary on; | |
gzip_types | |
application/atom+xml | |
application/javascript | |
application/json | |
application/rss+xml | |
application/vnd.ms-fontobject | |
application/x-font-ttf | |
application/x-web-app-manifest+json | |
application/xhtml+xml | |
application/xml | |
font/opentype | |
image/svg+xml | |
image/x-icon | |
text/css | |
text/plain | |
text/x-component; | |
EOF | |
# Disable The Default Nginx Site | |
rm /etc/nginx/sites-enabled/default | |
rm /etc/nginx/sites-available/default | |
service nginx restart | |
# Install A Catch All Server | |
cat > /etc/nginx/sites-available/000-catch-all << EOF | |
server { | |
return 404; | |
} | |
EOF | |
ln -s /etc/nginx/sites-available/000-catch-all /etc/nginx/sites-enabled/000-catch-all | |
# Restart Nginx & PHP-FPM Services | |
# Restart Nginx & PHP-FPM Services | |
service nginx restart | |
service nginx reload | |
if [ ! -z "\$(ps aux | grep php-fpm | grep -v grep)" ] | |
then | |
service php7.4-fpm restart > /dev/null 2>&1 | |
service php7.3-fpm restart > /dev/null 2>&1 | |
service php7.2-fpm restart > /dev/null 2>&1 | |
service php7.1-fpm restart > /dev/null 2>&1 | |
service php7.0-fpm restart > /dev/null 2>&1 | |
service php5.6-fpm restart > /dev/null 2>&1 | |
service php5-fpm restart > /dev/null 2>&1 | |
fi | |
# Add Forge User To www-data Group | |
usermod -a -G www-data forge | |
id forge | |
groups forge | |
apt_wait | |
curl --silent --location https://deb.nodesource.com/setup_12.x | bash - | |
apt-get update | |
sudo apt-get install -y --force-yes nodejs | |
npm install -g pm2 | |
npm install -g gulp | |
npm install -g yarn | |
# | |
# REQUIRES: | |
# - server (the forge server instance) | |
# - db_password (random password for mysql user) | |
# | |
# Set The Automated Root Password | |
export DEBIAN_FRONTEND=noninteractive | |
wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.12-1_all.deb dpkg --install mysql-apt-config_0.8.12-1_all.deb | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/data-dir select ''" | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/root-pass password [!db_password!]" | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/re-root-pass password [!db_password!]" | |
apt-get update | |
# Install MySQL | |
apt-get install -y mysql-server | |
# Configure Password Expiration | |
echo "default_password_lifetime = 0" >> /etc/mysql/mysql.conf.d/mysqld.cnf | |
# Set Character Set | |
echo "" >> /etc/mysql/my.cnf echo "[mysqld]" >> /etc/mysql/my.cnf | |
echo "default_authentication_plugin=mysql_native_password" >> /etc/mysql/my.cnf | |
# Configure Max Connections | |
RAM=$(awk '/^MemTotal:/{printf "%3.0f", $2 / (1024 * 1024)}' /proc/meminfo) | |
MAX_CONNECTIONS=$(( 70 * $RAM )) | |
REAL_MAX_CONNECTIONS=$(( MAX_CONNECTIONS>70 ? MAX_CONNECTIONS : 100 )) | |
sed -i "s/^max_connections.*=.*/max_connections=${REAL_MAX_CONNECTIONS}/" /etc/mysql/my.cnf | |
# Configure Access Permissions For Root & Forge Users | |
sed -i '/^bind-address/s/bind-address.*=.*/bind-address = */' /etc/mysql/mysql.conf.d/mysqld.cnf | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'root'@'[!server_ip!]' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'root'@'%' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO root@'[!server_ip!]' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO root@'%' WITH GRANT OPTION;" | |
service mysql restart | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'forge'@'[!server_ip!]' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'forge'@'%' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO 'forge'@'[!server_ip!]' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO 'forge'@'%' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "FLUSH PRIVILEGES;" | |
# Create The Initial Database If Specified | |
mysql --user="root" --password="[!db_password!]" -e "CREATE DATABASE [!server!] CHARACTER SET utf8 COLLATE utf8_unicode_ci;" | |
# If MySQL Fails To Start, Re-Install It | |
service mysql restart | |
if [[ $? -ne 0 ]]; then | |
echo "Purging previous MySQL8 installation..." | |
sudo apt-get purge mysql-server mysql-community-server | |
sudo apt-get autoclean && sudo apt-get clean | |
# | |
# REQUIRES: | |
# - server (the forge server instance) | |
# - db_password (random password for mysql user) | |
# | |
# Set The Automated Root Password | |
export DEBIAN_FRONTEND=noninteractive | |
wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.12-1_all.deb dpkg --install mysql-apt-config_0.8.12-1_all.deb | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/data-dir select ''" | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/root-pass password [!db_password!]" | |
debconf-set-selections <<< "mysql-community-server mysql-community-server/re-root-pass password [!db_password!]" | |
apt-get update | |
# Install MySQL | |
apt-get install -y mysql-server | |
# Configure Password Expiration | |
echo "default_password_lifetime = 0" >> /etc/mysql/mysql.conf.d/mysqld.cnf | |
# Set Character Set | |
echo "" >> /etc/mysql/my.cnf echo "[mysqld]" >> /etc/mysql/my.cnf | |
echo "default_authentication_plugin=mysql_native_password" >> /etc/mysql/my.cnf | |
# Configure Max Connections | |
RAM=$(awk '/^MemTotal:/{printf "%3.0f", $2 / (1024 * 1024)}' /proc/meminfo) | |
MAX_CONNECTIONS=$(( 70 * $RAM )) | |
REAL_MAX_CONNECTIONS=$(( MAX_CONNECTIONS>70 ? MAX_CONNECTIONS : 100 )) | |
sed -i "s/^max_connections.*=.*/max_connections=${REAL_MAX_CONNECTIONS}/" /etc/mysql/my.cnf | |
# Configure Access Permissions For Root & Forge Users | |
sed -i '/^bind-address/s/bind-address.*=.*/bind-address = */' /etc/mysql/mysql.conf.d/mysqld.cnf | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'root'@'[!server_ip!]' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'root'@'%' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO root@'[!server_ip!]' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO root@'%' WITH GRANT OPTION;" service | |
mysql restart | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'forge'@'[!server_ip!]' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "CREATE USER 'forge'@'%' IDENTIFIED BY '[!db_password!]';" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO 'forge'@'[!server_ip!]' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "GRANT ALL PRIVILEGES ON *.* TO 'forge'@'%' WITH GRANT OPTION;" | |
mysql --user="root" --password="[!db_password!]" -e "FLUSH PRIVILEGES;" | |
# Create The Initial Database If Specified | |
mysql --user="root" --password="[!db_password!]" -e "CREATE DATABASE [!server!] CHARACTER SET utf8 COLLATE utf8_unicode_ci;" | |
fi | |
apt_wait | |
# Install & Configure Redis Server | |
apt-get install -y redis-server | |
sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf | |
service redis-server restart | |
systemctl enable redis-server yes '' | pecl install -f redis | |
# Ensure PHPRedis extension is available | |
if pecl list | grep redis >/dev/null 2>&1; | |
then | |
echo "Configuring PHPRedis" | |
echo "extension=redis.so" > /etc/php/7.4/mods-available/redis.ini yes '' | apt install php-redis | |
fi | |
apt_wait | |
# Install & Configure Memcached | |
apt-get install -y memcached | |
sed -i 's/-l 127.0.0.1/-l 0.0.0.0/' /etc/memcached.conf | |
service memcached restart | |
# Configure Supervisor Autostart | |
systemctl enable supervisor.service | |
service supervisor start | |
# Configure Swap Disk | |
if [ -f /swapfile ]; then | |
echo "Swap exists." | |
else | |
fallocate -l 1G /swapfile | |
chmod 600 /swapfile | |
mkswap /swapfile | |
swapon /swapfile | |
echo "/swapfile none swap sw 0 0" >> /etc/fstab | |
echo "vm.swappiness=30" >> /etc/sysctl.conf | |
echo "vm.vfs_cache_pressure=50" >> /etc/sysctl.conf | |
fi | |
# Disable protected_regular | |
sysctl fs.protected_regular=0 | |
apt_wait | |
# Setup Unattended Security Upgrades | |
apt-get install -y --force-yes unattended-upgrades | |
cat > /etc/apt/apt.conf.d/50unattended-upgrades << EOF | |
Unattended-Upgrade::Allowed-Origins { | |
"Ubuntu focal-security"; | |
}; | |
Unattended-Upgrade::Package-Blacklist { | |
// | |
}; | |
EOF | |
cat > /etc/apt/apt.conf.d/10periodic << EOF | |
APT::Periodic::Update-Package-Lists "1"; | |
APT::Periodic::Download-Upgradeable-Packages "1"; | |
APT::Periodic::AutocleanInterval "7"; | |
APT::Periodic::Unattended-Upgrade "1"; | |
EOF | |
# Callback that the server is installed | |
#curl --insecure --data "event_id=878&server_id=390&sudo_password=[!sudo_password!]&db_password=[!db_password!]&recipe_id=" https://forge.laravel.com/provisioning/callback/app |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment