Skip to content

Instantly share code, notes, and snippets.

@AminulBD
Last active June 16, 2024 14:31
Show Gist options
  • Save AminulBD/9061f8a8c99e772249569aa1e6e5a362 to your computer and use it in GitHub Desktop.
Save AminulBD/9061f8a8c99e772249569aa1e6e5a362 to your computer and use it in GitHub Desktop.
Ubuntu Server LEMP Setup script
#!/bin/bash
DEBIAN_FRONTEND="noninteractive"
# Default values for parameters
DEFAULT_PHP_VERSION=8.3
DEFAULT_NODE_VERSION=20
DEFAULT_DOMAIN="example.test"
DEFAULT_USER="example"
DEFAULT_MYSQL_PASSWORD=$(openssl rand -base64 10)
# Initialize parameters with default values
PHP_VERSION=$DEFAULT_PHP_VERSION
NODE_VERSION=$DEFAULT_NODE_VERSION
MYSQL_PASSWORD=$DEFAULT_MYSQL_PASSWORD
DOMAIN=""
CUSTOM_USER=""
# Function to display help text
show_help() {
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " --domain= Specify the domain (default: $DEFAULT_DOMAIN)"
echo " --php= Specify the php version (default: $DEFAULT_PHP_VERSION)"
echo " --node= Specify the NodeJS version (default: $DEFAULT_NODE_VERSION)"
echo " --mysql-password= Specify the MySQL Password (default: Randomly generated)"
echo " --help Display this help and exit"
}
# Parse the command line arguments
for arg in "$@"; do
case $arg in
--php=*)
PHP_VERSION="${arg#*=}"
shift # Remove --php= from processing
;;
--node=*)
NODE_VERSION="${arg#*=}"
shift # Remove --node= from processing
;;
--mysql-password=*)
MYSQL_PASSWORD="${arg#*=}"
shift # Remove --mysql-password= from processing
;;
--domain=*)
DOMAIN="${arg#*=}"
shift # Remove --domain= from processing
;;
--user=*)
CUSTOM_USER="${arg#*=}"
shift # Remove --user= from processing
;;
--help)
show_help
exit 0
;;
*)
echo "Unknown option: $arg"
show_help
exit 1
;;
esac
done
if [ -z "$DOMAIN" ]; then
read -p "Enter domain [default: $DEFAULT_DOMAIN]: " DOMAIN
DOMAIN=${DOMAIN:-$DEFAULT_DOMAIN}
fi
if [ -z "$CUSTOM_USER" ]; then
read -p "Enter username [default: $DEFAULT_USER]: " CUSTOM_USER
CUSTOM_USER=${CUSTOM_USER:-$DEFAULT_USER}
fi
# configure mysql with random password
debconf-set-selections <<< "mysql-server mysql-server/root_password password $MYSQL_PASSWORD"
debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $MYSQL_PASSWORD"
echo $MYSQL_PASSWORD > /root/.mysql_password
# install common packages
apt update -q && apt install -yq \
apt-utils software-properties-common \
ca-certificates gnupg git zip unzip curl wget \
nginx certbot python3-certbot-nginx \
redis-server supervisor mysql-server
# Add system user with custom home directory
useradd -m -d /srv/$CUSTOM_USER -s /bin/bash $CUSTOM_USER
mkdir -p /srv/$CUSTOM_USER/{apps,logs,ssl}
mkdir -p /srv/$CUSTOM_USER/apps/$DOMAIN/releases
mkdir -p /srv/$CUSTOM_USER/logs/{nginx,php,mysql,supervisor,ssl}
chown -R $CUSTOM_USER:$CUSTOM_USER /srv/$CUSTOM_USER
chmod 755 /srv/$CUSTOM_USER
# install php and extensions
add-apt-repository -y ppa:ondrej/php
apt install -yq \
php$PHP_VERSION \
php$PHP_VERSION-fpm \
php$PHP_VERSION-mysql \
php$PHP_VERSION-mbstring \
php$PHP_VERSION-xml \
php$PHP_VERSION-curl \
php$PHP_VERSION-zip \
php$PHP_VERSION-gd \
php$PHP_VERSION-imagick \
php$PHP_VERSION-bcmath \
php$PHP_VERSION-redis \
php$PHP_VERSION-intl \
php$PHP_VERSION-soap \
php$PHP_VERSION-sqlite3
# create php-fpm pool
cat > /etc/php/$PHP_VERSION/fpm/pool.d/$CUSTOM_USER.conf <<EOF
[$CUSTOM_USER]
user = $CUSTOM_USER
group = $CUSTOM_USER
listen = /run/php/php$PHP_VERSION-fpm-$CUSTOM_USER.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
access.log = /srv/$CUSTOM_USER/logs/php/$CUSTOM_USER.access.log
slowlog = /srv/$CUSTOM_USER/logs/php/$CUSTOM_USER.slow.log
php_admin_value[error_log] = /srv/$CUSTOM_USER/logs/php/$CUSTOM_USER.error.log
EOF
systemctl restart php$PHP_VERSION-fpm
# install composer
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# install wp-cli
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp
# install nodejs
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
apt update -q && apt install -yq nodejs
# install yarn and pm2
npm install -g yarn pm2
# install laravel
cd /srv/$CUSTOM_USER/apps/$DOMAIN/releases
RELEASE_NAME=$(date +%s)
sudo -u $CUSTOM_USER composer create-project laravel/laravel $RELEASE_NAME
sudo -u $CUSTOM_USER ln -nfs /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME /srv/$CUSTOM_USER/apps/$DOMAIN/current
sudo -u $CUSTOM_USER mv /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME/storage /srv/$CUSTOM_USER/apps/$DOMAIN/storage
sudo -u $CUSTOM_USER mv /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME/.env /srv/$CUSTOM_USER/apps/$DOMAIN/.env
sudo -u $CUSTOM_USER ln -nfs /srv/$CUSTOM_USER/apps/$DOMAIN/.env /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME/.env
sudo -u $CUSTOM_USER ln -nfs /srv/$CUSTOM_USER/apps/$DOMAIN/storage /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME/storage
sudo -u $CUSTOM_USER ln -nfs /srv/$CUSTOM_USER/apps/$DOMAIN/storage/app/public /srv/$CUSTOM_USER/apps/$DOMAIN/releases/$RELEASE_NAME/public/storage
# create nginx config
cat > /etc/nginx/sites-available/$DOMAIN <<EOF
server {
listen 80;
listen [::]:80;
server_name $DOMAIN;
root /srv/$CUSTOM_USER/apps/$DOMAIN/current/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files \$uri \$uri/ /index.php?\$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_log /srv/$CUSTOM_USER/logs/nginx/$DOMAIN.error.log;
access_log /srv/$CUSTOM_USER/logs/nginx/$DOMAIN.access.log;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php$PHP_VERSION-fpm-$CUSTOM_USER.sock;
fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
EOF
# enable nginx config
ln -s /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/$DOMAIN
systemctl restart nginx
# install crontab
echo "* * * * * cd /srv/$CUSTOM_USER/apps/$DOMAIN/current && php artisan schedule:run >> /dev/null 2>&1" >> /var/spool/cron/crontabs/$CUSTOM_USER
chown $CUSTOM_USER:crontab /var/spool/cron/crontabs/$CUSTOM_USER
chmod 600 /var/spool/cron/crontabs/$CUSTOM_USER
systemctl restart cron
# install supervisor config
cat > /etc/supervisor/conf.d/$DOMAIN.conf <<EOF
[program:$DOMAIN]
process_name=%(program_name)s_%(process_num)02d
; if you are using horizon uncomment below line and comment queue worker line
;command=php /srv/$CUSTOM_USER/apps/$DOMAIN/current/artisan horizon
; if you are using queue worker uncomment below line and comment horizon line
command=php /srv/$CUSTOM_USER/apps/$DOMAIN/current/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=$CUSTOM_USER
numprocs=1
redirect_stderr=true
stdout_logfile=/srv/$CUSTOM_USER/logs/supervisor/$DOMAIN.log
EOF
supervisorctl reread
supervisorctl update
echo "127.0.0.1 $DOMAIN" >> /etc/hosts
@AminulBD
Copy link
Author

AminulBD commented May 31, 2024

curl -fsSL https://gist.githubusercontent.com/AminulBD/9061f8a8c99e772249569aa1e6e5a362/raw/bootstrap.sh | bash -s

@AminulBD
Copy link
Author

AminulBD commented Jun 5, 2024

How to use this:

  • Download this script as root: https://gist.githubusercontent.com/AminulBD/9061f8a8c99e772249569aa1e6e5a362/raw/bootstrap.sh
  • Make it executable as: chmod +x bootstrap.sh
  • Run the script: ./bootstrap.sh and follow the instructions.

Also, you can pass all info directly by: ./bootstrap.sh --domain=aminul.net --user=aminul

@AminulBD
Copy link
Author

AminulBD commented Jun 5, 2024

This script will generate mysql root password and will be stored in ~/.mysql_password file.

@AminulBD
Copy link
Author

AminulBD commented Jun 5, 2024

# This script will install LEMP (w/ composer & wp cli) and Node (w/ PM2 & Yarn).
# This setup is similar as laravel forge
# It will also setup fresh laravel application, cron and supervisor.
# FYI: This setup is my personalized setup with custom workflows.
# All files are located in: /srv/$USER/apps/$DOMAIN/


# Install LEMP and Node on your server just one click.
curl -fsSL amn.pw/lemp | bash -s -- --domain=example.com --user=example

# Or you can download and run
wget amn.pw/lemp
chmod +x lemp
./lemp --domain=example.com --user=example

# to see help
./lemp --help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment