Last active
December 24, 2024 11:41
-
-
Save fbouynot/e6c38194277976347c010deee70f474c to your computer and use it in GitHub Desktop.
Cachet 3.x installation
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
#!/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