Skip to content

Instantly share code, notes, and snippets.

@fbouynot
Last active December 24, 2024 11:41
Show Gist options
  • Save fbouynot/e6c38194277976347c010deee70f474c to your computer and use it in GitHub Desktop.
Save fbouynot/e6c38194277976347c010deee70f474c to your computer and use it in GitHub Desktop.
Cachet 3.x installation
#!/usr/bin/env bash
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version. Please see LICENSE.txt at the top level of
# the source code distribution for details.
#
# @package install_cachet.sh
# @author <[email protected]>
# @link none
# @copyright <[email protected]>
#
# Install Cachet status page
#
# -e: When a command fails, bash exits instead of continuing with the rest of the script
# -u: This will make the script fail, when accessing an unset variable
# -o pipefail: This will ensure that a pipeline command is treated as failed, even if one command in the pipeline fails
set -euo pipefail
# Replace the Internal Field Separator ' \n\t' by '\n\t' so you can loop through names with spaces
IFS=$'\n\t'
# Enable debug mode by running your script as TRACE=1 ./script.sh instead of ./script.sh
if [[ "${TRACE-0}" == "1" ]]
then
set -o xtrace
fi
# Check the command is run as root
if [ "${EUID}" -ne 0 ]
then
echo -e "${RED}E:${NC} please run as root" >&2
return 1
fi
# Generate the database password
set +o pipefail
db_password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 128)
redis_password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 128)
admin_password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 128)
set -o pipefail
# Define constants
project_name='cachet'
project_git='https://github.com/cachethq/cachet.git'
git_branch='3.x'
readonly db_password redis_password project_name project_git git_branch
# Install prerequisite
dnf install -y nginx php-fpm php-gd php-simplexml php-xml php-mcrypt php-mysqlnd php-opcache php-cli php-mbstring php-intl php-zip php-pecl-redis mariadb mariadb-server git acl npm wget redis openssl
# Create the project user
useradd "${project_name}" -d /opt/"${project_name}" -M -r -s "$(which bash)"
# Clone the project
cd /opt/
git clone --single-branch --branch "${git_branch}" "${project_git}"
# Create the .env file
cat << EOF > /opt/"${project_name}"/.env
APP_ENV=production
APP_DEBUG=false
APP_URL=http://localhost
APP_TIMEZONE=UTC
APP_KEY=
DEBUGBAR_ENABLED=false
DB_DRIVER=mysql
DB_HOST=localhost
DB_UNIX_SOCKET=/var/lib/mysql/mysql.sock
DB_DATABASE=${project_name}
DB_USERNAME=${project_name}
DB_PASSWORD=${db_password}
CACHE_DRIVER=redis
SESSION_DRIVER=redis
REDIS_HOST=/run/redis/redis.sock
REDIS_PASSWORD=${redis_password}
REDIS_PORT=0
QUEUE_DRIVER=sync
cachet_BEACON=false
cachet_EMOJI=false
cachet_AUTO_TWITTER=false
EOF
# Configure project ownership
chown -R "${project_name}":"${project_name}" /opt/"${project_name}"
# Add nginx user to project_name group
sudo usermod -a -G "${project_name}" nginx
# Allow everyone to go through the project folder
chmod 771 /opt/"${project_name}"
# Grants project_name group all permissions on bootstrap/cache and storage folders
setfacl -d -m g::rwx /opt/"${project_name}"/bootstrap/cache/ /opt/"${project_name}"/storage/
setfacl -R -m g::rwx /opt/"${project_name}"/bootstrap/cache/ /opt/"${project_name}"/storage/
# Allow nginx to read files in public folder
semanage fcontext -a -t httpd_sys_content_t "/opt/${project_name}/public(/.*)?"
# Allow php to read and write in storage and bootstrap/cache folders
semanage fcontext -a -t httpd_sys_rw_content_t "/opt/${project_name}/(storage|bootstrap/cache)(/.*)?"
# Allow logrotate to rotate logs in storage/logs folder
semanage fcontext -a -t httpd_log_t "/opt/${project_name}/storage/logs(/.*)?"
# Allow nginx and php to read and write in cache folder
semanage fcontext -a -t httpd_cache_t "/opt/${project_name}/cache(/.*)?"
# Apply selinux labels
restorecon -RFvv /opt/"${project_name}"
# Allow php to execute writable memory (needed for opcache)
setsebool -P httpd_execmem 1
# Get ip address
server_address=$(ip a show dev eth0 | grep inet | cut -d ' ' -f 6 | cut -d '/' -f 1)
#Create certificates
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/nginx-selfsigned.key -out /etc/nginx/nginx-selfsigned.crt << EOF
$server_address
EOF
# Create nginx config file
cat << 'EOF' > /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 443 http2 ssl;
server_name _;
http2 on;
ssl_certificate /etc/nginx/nginx-selfsigned.crt;
ssl_certificate_key /etc/nginx/nginx-selfsigned.key;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
EOF
cat << EOF >> /etc/nginx/nginx.conf
root /opt/${project_name}/public;
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
EOF
cat << EOF >> /etc/redis/redis.conf
unixsocket /run/redis/redis.sock
unixsocketperm 770
requirepass ${redis_password}
EOF
usermod -a -G redis "${project_name}"
# Create php-fpm config file
cat << EOF > /etc/php-fpm.d/www.conf
[www]
user = ${project_name}
group = ${project_name}
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
EOF
# Enable and start LEMP
systemctl enable --now mariadb redis php-fpm nginx
# Secure mariadb
mysql_secure_installation << EOF
Y
n
Y
Y
Y
Y
EOF
# Create user and database for the project
mysql -u root --execute="CREATE DATABASE ${project_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root --execute="CREATE USER '${project_name}'@'localhost' IDENTIFIED BY '${db_password}';"
mysql -u root --execute="GRANT ALL PRIVILEGES ON ${project_name}.* TO '${project_name}'@'localhost';"
# Open http and https ports in the firewall
firewall-cmd --add-service={http,https} --permanent
firewall-cmd --reload
# Install composer
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && wget https://getcomposer.org/installer -O composer-setup.php"
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && php composer-setup.php --quiet"
# Install project dependencies (php)
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && /opt/${project_name}/composer.phar install --no-dev -o"
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && /opt/${project_name}/composer.phar update --with-all-dependencies"
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && /opt/${project_name}/composer.phar require laravel/tinker"
# Create an application key
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && php artisan key:generate"
# Run migrations
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && php artisan migrate --force"
# Install project dependencies (js)
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && npm install"
# Compile assets (js)
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && npm run build"
# Cache config, routes, views
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && php artisan optimize"
# Create admin user
sudo -u "${project_name}" bash -c "cd /opt/${project_name} && php artisan tinker" << EOF
DB::table('users')->insert(['name'=>'admin','email'=>'[email protected]','password'=>Hash::make('$admin_password')])
EOF
ip a
echo "admin password: ${admin_password}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment