Anytime I'm to provision a fresh Ubuntu server I find myself Googling the same things all over. So I put together this guide as a reference. We wil go over the initial server setup, install nginx, PHP, PostgreSQL, PostGIS, MySQL, Redis, Nodejs etc. and configure our server to able to deploy a Laravel and Nodejs applications.
This guide is tested on Ubuntu server v18
- Autentication and Users
- Configure firewall rules
- Install Nginx
- Install Apache
- Setup Nginx server blocks
- SSL Certificates with Letsencrypt
- Install Composer
- Install PHP
- Install and Configure PostgreSQL
- Allow remote access to PostgreSQL
- Install and enable PostGIS
- Install MySQL
- Allow remote access to MySQL
- Install Redis
- Install Nodejs
- Laravel
- Useful links
This section shows how to connect to a server for the first time. Before logging onto the server, generate ssh keys on your local machine if yo haven't already.
- Generate ssh keys with:
$ ssh-keygen -t rsa -b 4096 -C "[email protected]"
- Login with default user:
$ ssh root@server_ip
- Add new user:
$ sudo adduser ultrasamad
. Replace ultrasamad with name of user - Create a copy .ssh directory for the new user:
$ rsync --archive --chown=ultrasamad:ultrasamad ~/.ssh /home/ultrasamad
- Grant administrative privileges to user:
$ usermod -aG sudo ultrasamad
- Disable root login by setting
PermitRootLogin no
directive in/etc/ssh/sshd_config
and restart SSH process withsudo systemctl restart sshd
- Enable firewall:
sudo ufw enable
- Allow ssh connection:
$ sudo ufw allow openSSH
- Check status:
$ sudo ufw status
- View list of registered applications:
$ sudo ufw app list
- Update packages repositories:
$ sudo apt update
- Install Nginx:
$ sudo apt install nginx
- Allow Firewall rules for http & https:
$ sudo ufw allow 'Nginx Full'
- Verify rule was added:
$ sudo ufw status
- Restart Nginx:
$ sudo service nginx restart
- Create new directory for your site:
$ sudo mkdir -p /var/www/example.com
- Give directory ownership to current user:
$ sudo chown -R $USER:$USER /var/ww/example.com
- Chage permissions of web root:
$ sudo chmod 755 -R /var/www
- Create test file:
$ sudo vim /var/www/example.com/index.html
- Cope over default server block to new site:
$ cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com
- Update
server_name
in new site file:server_name example.com www.example.com;
- Enable new site server block:
$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled
- Uncomment
server_names_hash_bucket_size 64
in /etc/nginx/nginx.conf file - Verify syntax of Nginx configurations:
$ sudo nginx -t
- Restart Nginx:
$ sudo service nginx restart
- Vist your new site at example.com or www.example.com
Incase you choose to go with apache instead of nginx, these are the steps.
- Installation:
$ sudo apt update
$ sudo apt install apache2
- Enable firewall rules:
sudo ufw allow in "Apache"
orsudo ufw allow in "Apache Full"
- Verify status:
sudo ufw status
- Enable site:
$ sudo a2ensite example.com
- Check Syntax of conf file:
sudo apache2ctl configtest
- Reload apache:
sudo systemctl reload apache2
Before doing anything check to make sure you have listen 80
directive in your Nginx config file
- Install certbot:
$ sudo apt install certbot python3-certbot-nginx
- Verify the server_name is set to your owned domain in the /etc/ngix/sites-available/example.com file
- Make sure firewall rules for http & https is allowed
- Obtain SSL Certificate for your domain:
$ sudo certbot --nginx -d example.com -d www.example.com
. Add any other subdomains you will like to enable ssl for. - Verify certbot auto renewal:
$ sudo certbot renew --dry-run
If auto renew is not working, you can manually set acron
job.- Open crontab file:
$ crontab -e
- Add the cronjob command to run daily:
0 12 * * * /usr/bin/certbot renew --quiet
The above command will run every day at noon
- Open crontab file:
- Adding new subdomains:
$ sudo certbot certbotonly --nginx -d blog.example.com, projects.example.com
$ cd ~ && sudo curl -sS https://getcomposer.org/installer | sudo php
- Move executable:
$ sudo mv composer.phar /usr/local/bin/composer
- Add installation to path:
$ sudo ln -s /usr/local/bin/composer /usr/bin/composer
- Confirm installation with:
$ composer --version
- Add a repository for latest PHP version:
$ sudo add-apt-repository ppa:ondrej/php
orppa:ondrej/apache2
for apache2 - Update repo packages list:
$ sudo apt update
- Check the version of PHP available:
$ sudo apt-cache show php
- Install PHP and all necessary packages: \
$ sudo apt install libapache2-mod-php php8.0-fpm php8.0-common php8.0-intl php8.0-mysql php8.0-pgsql php8.0-xml php8.0-xmlrpc php8.0-curl php8.0-gd php8.0-imagick php8.0-cli php8.0-dev php8.0-imap php8.0-mbstring php8.0-soap php8.0-zip php8.0-bcmath zip unzip -y
- Check PHP version:
$ php --version
- Check status of php7.4-fpm:
$ sudo service php7.4-fpm status
- Configure php7.4-fpm gateway.
Addfastcgi_pass unix:/run/php/php7.4-fpm.sock;
to the location server block in/etc/ngix/sites-available/example.com
- Reload Nginx:
$ sudo service nginx reload
- Restart php7.4-fpm:
$ sudo service php7.4-fpm restart
- Remove any old installation:
$ sudo apt remove postgresql && sudo apt-get --purge remove postgresql\*
- Reboot server:
$ sudo reboot
- Create the repository configuration file:\
$ sudo sh -c 'echo "deb http:https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
- Import the repository signing key:\
$ sudo wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
- Update repository package list:
$ sudo apt update
- Install PostSQL:
$ sudo apt install postgresql-12
- Check port of postgres installation:
$ sudo netstat -plunt | grep postgres
- Confirm installation:
$ sudo psql --version
- Login with default user:
$ sudo -u postgres psql
- Exit out of psql shell:
$ exit
- Create mew role called demo:
$ sudo -u postgres createuser --interactive
- Create database for the new user:
$ sudo createdb demo
- Login with new user:
$ sudo -u demo psql
- Change passowrd of the user:
$ sudo -u demo psql -c "ALTER USER demo PASSWORD 'secret123'"
- Allow Firewall rule:
$ sudo ufw allow 5432/tcp
- Update listen_address in /etc/postgresql/12/main/postgresql.conf to
listen_addresses = '*'
- Add allowed IP entry to /etc/postgresql/12/main/pg_hba.conf:
host all all 0.0.0.0/0 md5
- Restart PostgreSQL:
$ sudo service postgresql restart
- Install:
$ sudo apt install postgis postgresql-12-postgis-3
- Enable PostGIS on current database:
# CREATE EXTENSION postgis;
- Verify PostGIS installation:
# SELECT Postgis_Version();
- Download config:
$ sudo wget https://repo.mysql.com/mysql-apt-config_0.8.13-1_all.deb
- Extract archive:
$ sudo dpkg -i mysql-apt-config_0.8.13-1_all.deb
- Update repository packages list:
$ sudo apt update
- Install MySQL server:
$ sudo apt install mysql-server
- Enable secure installation:
$ sudo mysql_secure_installation utility
- Enable firewal rule for MySQL:
$ sudo ufw enable mysql
- Allow MySQL firewall rule:
$ sudo ufw allow mysql
- Login as root user:
$ mysql -uroot -p
- Check authentication methods used by users:
SELECT user,authentication_string,plugin,host FROM mysql.user;
- Change password of user:
# ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'secret123';
OR
# UPDATE mysql.user SET authentication_string = PASSWORD('password') WHERE user = 'root';
- Flush privileges:
# FLUSH PRIVILEGES;
- Create new user:
# CREATE USER 'ultrasamad'@'localhost' IDENTIFIED BY 'password';
- Grant privileges to user:
# GRANT ALL PRIVILEGES ON dbname.* TO 'user'@'localhost';
- Update bind_address in /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 0.0.0.0
- Change the host of the connecting user from localhost to %:
UPDATE mysql.user SET host='%' WHERE user='username' AND host='localhost';
- Enable Node source repository:
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
- Install nodejs:
$ sudo apt install nodejs
- Verify installation:
$ node --version
- Install PM2:
$ sudo npm install pm2@latest -g
- Start pm2 process:
pm2 start app.js --name myapp --watch
- Save pm2 process to auto run after restart:
pm2 save
- Update repository packages list:
$ sudo apt update
- Install redis server:
$ sudo apt install redis-server
- Update supervised in /etc/redis/redis.conf to
supervised systemd
- Invoke redis cli to confirm installation:
$ redis-cli
- Type ping and you should get back pong
You need to make the storage and bootstrap directory writeable\
- Change permission
$ chmod -R 775 storage bootstrap/cache
- Change ownership of storage and cache directory
$ chown -R $USER:www-data storage bootstrap/cache
- Check webserver user group (apache)
ps aux | egrep '(apache|httpd)'
- Check webserver user group (nginx)
ps aux|grep nginx|grep -v grep