Setup Ubuntu Server (2020)
If at all possible, use latest Ubuntu version that is on a LTS release, and setup SSH key access, instead of a master password.
Once created & can login, open
~/.bashrc
and put in the following:alias upgrade='sudo apt-get update && sudo apt-get upgrade && sudo apt-get dist-upgrade && sudo apt-get autoremove && sudo apt-get autoclean'
COMPOSER_PATH=~/.composer/vendor/bin
Then source it with
source ~/.bashrc
and run apt-get update
. Now we can run upgrade
.Note: When updating the kernel, a message may prompt that is pink/purple in the background, and gray with about seven options and the below text. Make sure keep the local version currently installed is chosen as the option, which is selected by default.
A new version of /boot/grub/menu.lst is available, but the version installed currently has been locally modified.
dpkg-reconfigure tzdata
Next, we'll install the PHP packages we need:
apt-get install php7.4 php7.4-bcmath php7.4-bz2 php7.4-cli php7.4-common php7.4-curl php-curl curl php7.4-dev php7.4-fpm php7.4-gd php7.4-intl php7.4-json php7.4-mbstring php7.4-mysql php7.4-sqlite3 php7.4-xml php7.4-zip php-pear php7.4-cgi php-mbstring php-cli php-intl
Now we setup the basic services we'll need for a running laravel application:
- Beanstalkd (queue)
- Redis (cache, queue)
- MySQL (client/server for DB)
- Supervisor (running queue/keeping it up)
- Nginx (http server)
- Lets Encrypt (ssl certificates)
- ImageMagick
- Misc Server Stuff (such as git, zip
apt-get install beanstalkd redis-server mysql-server mysql-client supervisor nginx certbot letsencrypt python-certbot-nginx php-imagick imagemagick zip unzip git php-redis
PHP FPM should be running already, but let's double-check:
service php7.4-fpm status
We'll first update the FPM
php.ini
file, located at - /etc/php/7.4/fpm/php.ini
memory_limit = 512M
upload_max_filesize = 256M
post_max_size = 256M
Let's do the same changes for the CLI configuration, except skip memory limit. The file is at -
/etc/php/7.4/cli/php.ini
After that's done, restart FPM with
service php7.4-fpm restart
and double-check that it's running fine with service php7.4-fpm status
curl -sS https://getcomposer.org/installer -o composer-setup.php
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
After setup, test that
composer
will run under root, and non-root. From that point on, it is much better to NOT run composer as root.Next, to speed up composer going forward, with global, and non-global packages, install this:
composer global require hirak/prestissimo
Nginx should be running already, but let's double check:
service nginx status
Let's open the default vhost in
/etc/nginx/sites-available/default
and replace it with the following:server {
listen 80 default_server;
listen [::]:80 ipv6only=on default_server;
root /var/www/vhosts;
index index.html index.php;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}
Run
nginx -t
to make sure nothing got messed up and set the root/sock path to match what you set up. By default it's /var/www/html
, and it depends for the sock file. To find out for sure, and to do further configuration (FPM) before setting up a staging vhost, open the following file:/etc/php/7.4/fpm/pool.d/www.conf
Look for
listen =
and you should see it being referenced now. Take that path and put it in the default vhost file.For this we will need to utilize Letsencrypt, enabling IPv6 on our machines, HTTP2, being able to see a hello world example, and running on PHP. First off, here's the vHost file with SSL being commented out. This will also redirect HTTP traffic to HTTPS.
server {
listen 80;
server_name sub.domain.com;
rewrite ^ https://sub.domain.com$request_uri? permanent;
}
server {
listen 443 ssl http2;
server_name sub.domain.com;
set $root_path '/var/www/vhosts/sub.domain.com/public';
root $root_path;
ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?_url=/$1;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
The above can go in
/etc/nginx/sites-available/sub.domain.com.vhost
, and create a symbolic link in sites-enabled
, by running:cd /etc/nginx/sites-enabled/ && ln -s ../sites-available/sub.domain.com.vhost
With Let's Encrypt installed, and the Nginx plugin for it, and vHost setup, let's create a certificate! When running these commands, be sure to choose the Nginx option specifically for it. Nginx should have a non-ssl vhost to read, just comment out the SSH lines before running this (and restart nginx).
letsencrypt certonly --agree-tos -m [email protected] -d sub.domain.com
If you need multiple domains, keep passing in
-d
param. Here's an example with multiple sub-domains, and doing a dry run with the flag:letsencrypt certonly --agree-tos -m [email protected] -d sub.domain.com -d www.domain.com -d domain.com --dry-run
If everything checks out okay, then you can remove the comments by the SSL keys info, above for Nginx.
MySQL should be running already, but let's double check:
service mysql status
mysql_secure_installation (recommended)
After installation you can secure a password & some recommended security improvement by running
mysql_secure_installation
via SSH. Skip the first one if you want, but create a new password, disable remote login, anonymous users, test databases, and definitely reload privileges.So root is not so depended on, why don't we create a non-root user that can be used when logging into MySQL, for the Laravel database type, and in general is a great idea.
Remember that root password that was set previously? We'll need it below. After logging in, copy/paste the commands after the first one, one by one.
mysql -u root -p
CREATE USER 'usernamehere'@'localhost' IDENTIFIED BY 'passwordhere';
GRANT ALL PRIVILEGES ON * . * TO 'usernamehere'@'localhost';
FLUSH PRIVILEGES;
service redis-server status
service redis-server restart
redis-cli
nano /etc/redis/redis.conf
(uncomment this line in the ^ file) bind 127.0.0.1 ::1
To improve security, we should have a password set in the aforementioned
.conf
file, and then we can easily set it in the laravel app. Due to the speediness of redis, we need a long, unrememberable, password. Run the following:(look for this line & add `requirepass yourpwd` after) # requirepass foobared
(to generate LONG pwd) openssl rand 60 | openssl base64 -A
service redis-server restart
service beanstalkd status
service beanstalkd restart
Create the file
/etc/supervisor/conf.d/siteorenvname.conf
and put the following in, with personalization:[program:staging]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/vhosts/staging/artisan queue:work --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/vhosts/staging/storage/logs/worker.log
After saving the file, run these commands:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start staging:*
composer require pda/pheanstalk
composer require aws/aws-sdk-php
composer require predis/predis
composer require league/flysystem-aws-s3-v3
composer require league/flysystem-cached-adapter
php artisan storage:link (if local filesystem driver)
sudo adduser usernameishere
sudo usermod -aG groupnamehere usernameishere (add existing user to existing group)
sudo rsync --archive --chown=usernameishere:usernameishere ~/.ssh /home/usernameishere
sudo groupadd devs
sudo usermod -g devs usernameishere (add new user to existing group)
sudo groups usernameishere (list groups for user)
sudo mkdir /var/www/vhosts (if needed)
(as root) cd ~/ && ln -s /var/www/vhosts Sites
(NOT as root) cd ~/ && ln -s /var/www/vhosts Sites
sudo chown -R www-data:devs /var/www/vhosts
sudo chown www-data:devs /usr/local/bin/composer
sudo chmod -vR g+w /var/www/vhosts
sudo usermod -a -G devs www-data
After creating project so files/folders are populated on disk, a git pull of a laravel project, whatever it is, below is what you want to run after composer. Right before development starts, make sure the permissions are right, locally, or on staging/production.
Please click on "laravel_permissions.sh" on the bottom left to see full instructions, and any feedback from the community.
Instead of using a local driver for storage, or Amazon S3, let's use the same stack of Digital Ocean, but this time use their S3 alternative, which uses the same exact driver.
Open up
config/filesystems.php
and add in a new disk
:'digitalocean' => [
'driver' => 's3',
'key' => env('DO_SPACES_KEY'),
'secret' => env('DO_SPACES_SECRET'),
'endpoint' => env('DO_SPACES_ENDPOINT'),
'region' => env('DO_SPACES_REGION'),
'bucket' => env('DO_SPACES_BUCKET'),
],
Create an API key, and Spaces bucket before proceeding any further. At the time of writing this, Spaces costs $5/month for unlimited buckets, besides further bandwidth costs. With a domain connected, it would be recommended to enable the CDN, and keep the other settings as is.
After updating the config file, lets set the values in our
.env
file:# Digital Ocean (file storage)
DO_SPACES_KEY="YOUR-API-KEY-HERE"
DO_SPACES_SECRET="YOUR-API-SECRET-HERE"
DO_SPACES_ENDPOINT="nyc3.digitaloceanspaces.com"
DO_SPACES_REGION="nyc3"
DO_SPACES_BUCKET="thenameofyourspacehere"
FILESYSTEM_DRIVER="digitalocean"
nyc3
is the name of the region for your space, which you can find by going to Dashboard -> Spaces -> Look at name of space in the list. Region names will look like sfo2
, nyc3
, and so on. As for FILESYSTEM_DRIVER
, this line makes Digital Ocean Spaces the default for any file storage usage, which is a good thing!With a New York example above, here's another example with San Fransisco:
https://thenameofyourspacehere.sfo2.digitaloceanspaces.com
Run
php artisan config:clear
, clear cache, and restart the queue just in case.With the above packages being installed, and configured, below is a sample
.env
file that can be loaded in. Adjust to your vHost location on your local/remote box, username changes - that sort of thing. In terms of drivers, testing that these things work - as of January 18th, 2020 - these all work with the newest Digital Ocean Ubuntu Server version.Away we go:
apt-get install gcc g++ make nodejs && node -v && npm -v
First, install NodeJS. After it completes running, two separate version numbers should popup. An example is below the install line:
apt-get install gcc g++ make nodejs && node -v && npm -v
(EXAMPLE RESULTS WHEN RUNNING CLI LINE ABOVE)
Reading package lists... Done
Building dependency tree
Reading state information... Done
make is already the newest version (4.1-9.1ubuntu1).
make set to manually installed.
g++ is already the newest version (4:7.4.0-1ubuntu2.3).
g++ set to manually installed.
gcc is already the newest version (4:7.4.0-1ubuntu2.3).
gcc set to manually installed.
The following NEW packages will be installed:
nodejs
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 24.0 MB of archives.
After this operation, 115 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 https://deb.nodesource.com/node_13.x bionic/main amd64 nodejs amd64 13.6.0-1nodesource1 [24.0 MB]
Fetched 24.0 MB in 2s (12.6 MB/s)
Selecting previously unselected package nodejs.
(Reading database ... 107907 files and directories currently installed.)
Preparing to unpack .../nodejs_13.6.0-1nodesource1_amd64.deb ...
Unpacking nodejs (13.6.0-1nodesource1) ...
Setting up nodejs (13.6.0-1nodesource1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
v13.6.0
6.13.4
With NPM, and NodeJS installed, we should install
yarn
next. This is simply a preference thing. A single version number, such as 1.21.1
, should popup at the end if all went well.curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list && sudo apt-get update && sudo apt-get install yarn && yarn -v
In an ideal world, we would be done at this point. Unfortunately, permissions are back as a necessary step to resolve. Run the below, in order, and change out
devs
, if you created a different group name:mkdir /home/devs
chown -R root:devs /home/devs
mkdir /home/devs/.npm-global
npm config set prefix "/home/devs/.npm-global"
Next, update your
~/.bashrc
file to include the following block - this will set the paths for NPM, Composer, Local Path & be ready to go! # custom paths
export MAIN_PATH=/usr/local/bin
export COMPOSER_PATH=~/.composer/vendor/bin
export NPM_BIN_PATH=/home/devs/.npm-global/bin
export PATH=${PATH}:${MAIN_PATH}:${COMPOSER_PATH}:${NPM_BIN_PATH}
Simply run
source ~/.bashrc
after saving the file. Running npm -v
, composer
, and yarn -v
should all work properly. Since you'll want to end up using it anyways, run yarn global add @vue/cli
to be 100% sure the front-end stuff is working alright.Run these commands after signing up for a free Pusher account:
composer require pusher/pusher-php-server
yarn add laravel-echo && yarn add pusher.js
yarn add sass sass-loader lodash (just to make things easier)
Update your
.env
file to use the new broadcast driver, and update the values for pusher. We should also pass the channel name so VueJS has access to everything it needs for broadcasting events.BROADCAST_DRIVER="pusher"
# Pusher Channel
PUSHER_APP_ID="YOURAPPID"
PUSHER_APP_KEY="YOURAPPKEY"
PUSHER_APP_SECRET="YOURAPPSECRET"
PUSHER_APP_CLUSTER="mt1"
PUSHER_APP_CHANNEL="YOURCHANNELNAMEHERE"
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
MIX_PUSHER_APP_CHANNEL="${PUSHER_APP_CHANNEL}"
apt-get install emacs25-nox php-elisp
composer global require laravel/installer
passwd usernameishere (set a new password for user)
groupadd groupnameishere (create new group)
usermod -g groupname username (assign existing user to group)
adduser username groupname (after group created, create new user to be assigned)
openssl rand 60 | openssl base64 -A (create long, complicated, basically impossible to crack, password)
Last modified 3yr ago