Skip to content

Instantly share code, notes, and snippets.

@rolandstarke
Last active April 2, 2024 20:42
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save rolandstarke/51f1eedad6e7ed5d355a0c3123e5d127 to your computer and use it in GitHub Desktop.
Save rolandstarke/51f1eedad6e7ed5d355a0c3123e5d127 to your computer and use it in GitHub Desktop.
Server setup bash script for Laravel
# Ubuntu 20 LTS Server Setup for Laravel
# Login as root user
sudo su -
# Update list of available packages
apt update
# Install node.js
curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -
apt install nodejs
# Install MySQL
apt install mysql-server
# Configure MySQL
mysql -u root <<-EOF
CREATE DATABASE databasename;
CREATE USER 'example_laravel'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
GRANT ALL PRIVILEGES ON databasename.* TO 'example_laravel'@'localhost';
EOF
# Install nginx
apt install nginx
# Configure nginx
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com
nano /etc/nginx/sites-available/example.com
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t
service nginx restart
# 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
service nginx restart
# Configure HTTPS
sudo apt install certbot python3-certbot-nginx
certbot --nginx
# after installing ssl you can enable http2. add "http2"
# in the file /etc/nginx/sites-available/example.com near the bottom:
# listen 443 ssl http2; # managed by Certbot
# Install php
apt install php-fpm
apt install php-mysql php-common php-mbstring php-xml php-zip php-bcmath zip unzip php-curl
curl -sS https://getcomposer.org/installer -o ~/composer-setup.php
php ~/composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm ~/composer-setup.php
# Configure php
sed -i 's/^upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php/7.4/fpm/php.ini
sed -i 's/^post_max_size.*/post_max_size = 10M/' /etc/php/7.4/fpm/php.ini
service php7.4-fpm restart
# Install supervisor
apt install supervisor
# Configure supervisor
nano /etc/supervisor/conf.d/example-laravel.conf
supervisorctl reread
supervisorctl update
supervisorctl start example-laravel-worker:*
# Configure crons
crontab -e
# Add known hosts
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
# Setup ssh key
ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N ""
# Output the public ssh key in the console
# In order for this maschine to gain read-only access to your repositories you need to copy this key to
# - Bitbucket: under Project -> Settings -> Access keys
cat ~/.ssh/id_rsa.pub
# /etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
root /var/www/example.com/current/public;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
server_name www.example.com example.com;
client_max_body_size 10M;
# force www in URL
if ($host = example.com) {
return 301 $scheme://www.$host$request_uri;
}
# remove /index.php/ from URL
if ($request_uri ~* "^(.*/)index\.php(/?)(.*)") {
return 301 $1$3;
}
index index.html index.php;
location / {
location / {
try_files $uri /index.php?$query_string;
}
# don't cache the service worker
location = /service-worker.js {
try_files $uri /index.php?$query_string;
}
# cache static files
location ~* ^.+\.(ico|css|js|gif|jpe?g|png|woff|woff2|eot|svg|ttf|webp|mp3|midi?)$ {
try_files $uri /index.php?$query_string;
add_header Cache-Control "public, max-age=31536000";
# optinaly you can disable the other cache headers
# etag off;
# if_modified_since off;
# add_header Last-Modified "";
}
# pass PHP scripts to FastCGI server
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
}
# proxy Laravel Websockets server
location /app/ {
proxy_pass http://localhost:6001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
# send every request on this location to a specific php script
location /myapi/ {
include fastcgi.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/myapi.php;
}
}
# /etc/supervisor/conf.d/example-laravel.conf
[program:example-laravel-worker]
process_name=%(program_name)s_%(process_num)02d
directory=/var/www/example.com/current
command=php artisan queue:work --sleep=3 --tries=1 --quiet
autostart=true
autorestart=true
user=www-data
numprocs=1
[program:example-laravel-echo]
directory=/var/www/example.com/current
command=php artisan websockets:serve --host 127.0.0.1 --quiet
autostart=true
autorestart=true
user=www-data
numprocs=1
* * * * * cd /var/www/example.com/current && php artisan schedule:run >> /dev/null 2>&1
#certbot renew ssl certificates each day at 06:47
47 6 * * * certbot renew --post-hook "systemctl reload nginx"
<?php
/**
* deploy.php
* https://deployer.org/
*
* composer require deployer/deployer --dev
* composer require deployer/recipes --dev
*
* Deploy your project
* vendor/bin/dep deploy
*
* Note that the this does not work in the windows shell. I personaly use the windows subsystem for linux for it.
*
* The first deploy will fail, you need to ssh into the server and create your .env with
* nano /var/www/example.com/shared/.env
*
* Connect to host through ssh
* vendor/bin/dep ssh
*/
namespace Deployer;
require 'recipe/laravel.php';
require 'recipe/cachetool.php';
require 'recipe/npm.php';
// Project name
set('application', 'example');
// Project repository
set('repository', 'git@domain.com:username/repository.git');
// Shared files/dirs between deploys
add('shared_files', []);
add('shared_dirs', []);
// Writable dirs by web server
add('writable_dirs', []);
// Hosts
host('example.com')
->user('root')
->set('deploy_path', '/var/www/example.com');
task('artisan:optimize', function() {
writeln('skipping artisan:opzimize');
// skipping because view:cache and config:cache is already in the default queue from deployer.php
// and we added route:cache ourself
});
task('cachetool:clear:opcache', function() {
run("service php7.4-fpm reload", ['timeout' => 600]);
});
desc('Restarting Echo Server');
task('echo-server:restart', function () {
run('supervisorctl restart example-laravel-echo');
});
desc('Execute npm run production');
task('build', function () {
run("cd {{release_path}} && {{bin/npm}} run production", ['timeout' => 600]);
});
after('deploy:writable', 'npm:install');
after('deploy:writable', 'build');
before('deploy:symlink', 'artisan:route:cache');
before('deploy:symlink', 'artisan:migrate');
after('deploy:symlink', 'cachetool:clear:opcache');
after('deploy:symlink', 'artisan:queue:restart');
after('deploy:symlink', 'echo-server:restart');
// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');
after('rollback', 'cachetool:clear:opcache');
after('rollback', 'artisan:config:cache');
after('rollback', 'artisan:view:cache');
after('rollback', 'artisan:route:cache');
after('rollback', 'artisan:queue:restart');
after('rollback', 'echo-server:restart');

Bonus Tipps

Running out of space on the server

I run out of space on my 20GB server once in a while. You can check your free storage with df -h

Finding the biggest files

I recommend to install ncdu with apt install ncdu it shows you the size of every folder and lets you navigate through them.

/var/log/journal

The journals size was multible GB in my case. I run journalctl to look what's inside it and there where a bunch of failed ssh login attempts. I delete everything thats over 100MB in my crontab now daily.

0 8 * * * journalctl --vacuum-size=100M

/var/lib/mysql/binlog.000001

The database binlog has reached multible GB on my server. My laravel project uses telescope which inserts 1GB a day. thats probably why. I changed my mysql config in /etc/mysql/mysql.conf.d/mysqld.cnf to reduce the size. The settings already exist at the end of the file just uncommend it and change the values.

binlog_expire_logs_seconds = 86400
max_binlog_size   = 100M

after that restart the mysql service service mysql restart

Specify the php version for composer

I have php 8 installed localy but my server runs with php 7. to prevent composer to install packages that only work in php 8 you can specify the php version you have in your composer.json. I also had problems installing deployer with php 8 as the latest release only runs on php 7. so composer installed a very old version of deployer.

"config": {
    "platform": {
        "php": "7.4.3"
    }
},
@insign
Copy link

insign commented Mar 17, 2020

Did you forget gzip on;?

@rolandstarke
Copy link
Author

rolandstarke commented Mar 17, 2020

Hey, thanks, I added it. It was enabled in /etc/nginx/nginx.conf by default for me. Explicy adding it makes sense. edit: I removed it again, as one gets an error when its activated twice.

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