Skip to content

Instantly share code, notes, and snippets.

@itinerare
Last active October 3, 2024 15:01
Show Gist options
  • Save itinerare/42baa02dd076091db4525d664013f173 to your computer and use it in GitHub Desktop.
Save itinerare/42baa02dd076091db4525d664013f173 to your computer and use it in GitHub Desktop.
Laravel Setup on Linux

Webserver / Laravel Setup on Linux

Assumes Linux env for all parts. Notes are included on:

  • Ubuntu (22.04 LTS/24.04 LTS)
  • Arch

Locally, consider using Valet Linux. This mostly replaces using serve, and brings the local environment more in line with a server (uses nginx, php-fpm, etc.)

Server-Specific: User Setup

adduser username
usermod -aG sudo username
apt update
apt upgrade
  • nano /etc/ssh/sshd_config
    • PasswordAuthentication yes temporarily
  • Log out
  • Locally, ssh-copy-id username@hostname
    • or ssh-copy-id -i ~/.ssh/KEY -o PubkeyAuthentication=no USERNAME@DOMAIN
  • Log in as username
  • sudo nano /etc/ssh/sshd_config
    • PasswordAuthentication no
    • PubkeyAuthentication yes
  • (DO) May also need:
    • sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf
    • PasswordAuthentication no
    • Or sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf if it contains no other settings
  • sudo systemctl restart ssh

Webserver Setup

# Ubuntu:
sudo apt install nginx curl wget mariadb-server mariadb-client

# Arch:
sudo pacman -S nginx curl wget mariadb

MariaDB

sudo systemctl status mariadb
sudo systemctl start mariadb # If not already running
sudo systemctl enable mariadb # on Arch

# Additionally, on Arch:
sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql

Setup

  • sudo mysql_secure_installation

    • sudo mariadb-secure-installation on Arch
  • Enter for none

  • DON'T switch to unix_socket authentication

  • DO

    • change root password
    • remove anon users
    • disable root login remotely
    • remove test database,
    • reload privilege tables
  • sudo mysql -u root -p

  • CREATE DATABASE database_name;

  • GRANT ALL PRIVILEGES ON  database_name.* TO 'user'@'localhost' IDENTIFIED BY 'password';

  • FLUSH PRIVILEGES;

  • \q

(Optional, Server-Specific) Dedicated DB Droplet

  • Try optimizing memory use first (use nginx, adjust php-fpm config)
  • Perform mariaDB setup on a different droplet (1GB recommended)
    • !! Works best in the same data center !!
  • sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
    • bind-address = 0.0.0.0
  • sudo systemctl restart mysql
  • sudo ufw allow from SERVER.IP.ADDRESS.HERE to any port 3306
  • Create mysql users as user@server.ip.address

PHP

# Ubuntu:
# For current version (8.1 as of 22.04 LTS, 8.3 as of 24.04):
sudo apt install php-fpm php-bcmath php-json php-mbstring php-mysql php-tokenizer php-xml php-zip php-curl php-gd php-intl php-imagick imagemagick
# optional/for dev env, handles code coverage calc: php-pcov

sudo update-alternatives --config php
# can be used if need be to switch PHP version being used. Good esp for dev envs where multiple are present

# Arch:
# Legacy (8.2):
sudo pacman -S php-legacy-fpm php-legacy-gd php-legacy-intl php-imagick imagemagick
sudo nano /etc/php-legacy/php.ini
# Enable bcmath, zip, pdo_mysql, mysqli, gd, intl, curl, iconv
sudo systemctl enable php-legacy-fpm
sudo systemctl start php-legacy-fpm

# Current (8.3):
sudo pacman -S php-fpm php-gd php-intl php-imagick imagemagick
sudo nano /etc/php/php.ini
# Enable bcmath, zip, pdo_mysql, mysqli, gd, intl, curl, iconv
sudo systemctl enable php-fpm
sudo systemctl start php-fpm

Composer

  • Ubuntu:
    • sudo apt install composer
  • Arch:
    • sudo pacman -S composer

Arch: nginx setup

sudo mkdir /etc/nginx/sites-available
sudo mkdir /etc/nginx/sites-enabled
sudo nano /etc/nginx/nginx.conf
sudo systemctl enable nginx
sudo systemctl restart nginx

PHPMyAdmin

# Ubuntu:
sudo apt install phpmyadmin
sudo phpenmod mbstring

# Arch:
sudo pacman -S phpmyadmin

Add PHPMyAdmin as a subdomain

Valet (Recommended locally)

  • link:
    • Ubuntu: /usr/share/phpmyadmin
    • Arch: /usr/share/webapps/phpMyAdmin

Nginx

sudo nano /etc/nginx/sites-available/mysql.your_domain
  • (Server-Specific) Alternately replace /etc/nginx/sites-available/default if on a dedicated droplet

Ubuntu:

server {
    listen       80;
    server_name  mysql.your_domain;

    root /usr/share/phpmyadmin;
    index index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

}

Arch:

server {
    server_name mysql.your_domain;
    listen 80;
    index index.php;
    access_log /var/log/nginx/pma.access.log;
    error_log /var/log/nginx/pma.error.log;

    root /usr/share/webapps/phpMyAdmin;
    location / {
        try_files $uri $uri/ =404;
    }

    error_page 404 /index.php;

    location ~ \.php$ {
        try_files $uri $document_root$fastcgi_script_name =404;

        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;

        fastcgi_param HTTP_PROXY "";
        fastcgi_param HTTPS on;
        fastcgi_request_buffering off;
   }
}
sudo ln -s /etc/nginx/sites-available/mysql.your_domain /etc/nginx/sites-enabled/
sudo systemctl restart nginx
  • (Local) Edit /etc/hosts to point at 127.0.0.1 and the desired local URL

PHP Configuration

  • Ubuntu:
    • Local (if using serve): sudo nano /etc/php/8.1/cli/php.ini
    • Server: sudo nano /etc/php/8.1/fpm/php.ini
  • Arch:
    • Current: sudo nano /etc/php/php.ini
    • Legacy: sudo nano /etc/php-legacy/php.ini
  • Adjust post_max_size and upload_max_filesize as desired
  • Restart serve (local) or sudo systemctl restart php8.1-fpm (server/vagrant)

Configuration

php-fpm

# Ubuntu:
sudo nano /etc/php/8.1/fpm/php-fpm.conf
# Substitute with relevant version as necessary

# Arch:
sudo nano /etc/php/php-fpm.conf
emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s
# Ubuntu:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
# Substitute with relevant version as necessary

# Arch:
sudo nano /etc/php/php-fpm.d/www.conf

For low-traffic sites /shared servers(/multiple php-fpm pools) /situations where memory use must be optimized:

pm = ondemand
pm.max_children = 80
pm.process_idle_timeout = 10s
pm.max_requests = 200

Else use dynamic and configure to suit traffic needs/memory limitations

sudo systemctl restart php8.1-fpm

nginx

sudo nano /etc/nginx/nginx.conf
  • Add client_max_body_size 10M; (set to desired value)
  • sudo systemctl restart nginx

Server-Specific:

Setting Up Virtual Hosts

sudo mkdir /var/www/your_domain
sudo mkdir /var/www/your_domain/www
sudo mkdir /var/www/your_domain/www/public
sudo chown -R $USER:$USER /var/www/your_domain
sudo chmod -R 755 /var/www/your_domain
ln -s /var/www/your_domain /home/$USER/your_domain # For convenience
git config --global --add safe.directory /var/www/your_domain/www
sudo nano /etc/nginx/sites-available/your_domain

Config contents:

server {
    server_name your_domain www.your_domain;
    root /var/www/your_domain/www/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_page 404 /index.php;
 
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }
 
    location ~ /\.(?!well-known).* {
        deny all;
    } 
}

From https://laravel.com/docs/11.x/deployment#nginx

sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo nginx -t # Test for config errors
sudo service nginx restart

ufw

sudo ufw app list # Ensure this contains both nginx and OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw allow 'OpenSSH'
sudo ufw enable
sudo ufw status # Should contain nginx and OpenSSH

Fail2Ban

  • sudo apt install fail2ban
  • sudo systemctl start fail2ban && sudo systemctl enable fail2ban
    • At the time of writing, see fail2ban #3487 wrt an issue on Ubuntu 24.04.
  • sudo fail2ban-client status to view status
    • sudo fail2ban-client status sshd to view SSH bans

Certbot/SSL

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx
sudo systemctl status certbot.timer # verify no error/service running
sudo certbot renew --dry-run # can use to test renewal process

Unattended Upgrades

# Ubuntu 22.04:
sudo apt install apt-config-auto-update
sudo dpkg -i --force-overwrite /var/cache/apt/archives/apt-config-auto-update_2.1+nmu1_all.deb
# replace with relevant version/archive path

# Ubuntu 24.04:
sudo apt install unattended-upgrades

sudo systemctl enable unattended-upgrades
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
  • Uncomment allowed-origins
  • Unattended-Upgrade::AutoFixInterruptedDpkg "true";
  • Unattended-Upgrade::MinimalSteps "true";
  • Unattended-Upgrade::InstallOnShutdown "false";
  • Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
  • Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
  • Unattended-Upgrade::Remove-Unused-Dependencies "true";
  • Unattended-Upgrade::Automatic-Reboot "true";
  • Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
sudo systemctl restart unattended-upgrades
sudo unattended-upgrades
sudo crontab -e
  • Add 0 0 * * * /usr/bin/unattended-upgrade -d

Server-Specific: Laravel Setup

  • Git should already be installed, if not, sudo apt install git
    • Set the default branch name to main: git config --global init.defaultBranch main
cd ~/your_domain/www
git init
cd ../ && mkdir site_hub.git && cd site_hub.git
git --bare init
  • Push to ssh://username@hostname/~/your_domain/site_hub.git
cd ../www && git remote add hub ../site_hub.git
git pull hub main
cd .git/hooks && nano post-commit
#!/bin/sh

echo
echo "**** Pushing changes to Hub [Prime's post-commit hook]"
echo

git push hub
chmod +x post-commit
cd ../../../site_hub.git/hooks && nano post-update
#!/bin/sh

echo
echo "**** Pulling changes into Prime [Hub's post-update hook]"
echo

cd $HOME/your_domain/www || exit
unset GIT_DIR
git pull hub main

exec git-update-server-info
chmod +x post-update
crontab -e
  • Add * * * * * cd ~/your_domain/www && php artisan schedule:run >> /dev/null 2>&1

Initialize Laravel

cd ~/your_domain/www # or wherever you have your project
composer install #/ php composer.phar install if using PHP 7.4 on 22.04
php artisan key:generate
php artisan migrate

Fix permissions:

#apache
cd ../ && wget https://gist.githubusercontent.com/itinerare/ca00d05b9c0a43c7763df113623c4f2d/raw/04ca6429f26b8ade656e4a9e559e1b292bd603bb/fixfolderperms.sh && sudo chmod +x fixfolderperms.sh && sudo sh fixfolderperms.sh

#nginx
cd ../ && wget https://gist.githubusercontent.com/itinerare/cbb0cc8b58918908c18959a6f691dff7/raw/3d8d99b7d708c2c163b5cd7502d3f5b2a4367ed4/fixfolderperms.sh && sudo chmod +x fixfolderperms.sh && sudo sh fixfolderperms.sh
# may also need to refer to https://stackoverflow.com/a/37266353

Local: Create a New Laravel Project

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