Skip to content

manual_installation_process

Slava Semushin edited this page Dec 1, 2024 · 68 revisions

Step by step installation guide of production server

This instruction is an example of setting up production server on Ubuntu 16.04. from scratch.

Creating unprivileged user for accessing the server

root@my-server# useradd coder --create-home --shell /bin/bash --comment 'Slava Semushin'
root@my-server# passwd coder
root@my-server# vim /etc/sudoers.d/01_coder
coder ALL=(ALL) NOPASSWD: ALL
root@my-server# chmod 0440 /etc/sudoers.d/01_coder

Creating unprivileged user for running application

OUTDATED: use mystamps-user and mystamps-app Ansible roles instead.

root@my-server# mkdir /data
root@my-server# useradd mystamps --comment 'MyStamps' --home /data/mystamps --create-home
root@my-server# vim /etc/sudoers.d/10_mystamps
mystamps my-stamps.ru=(root) NOPASSWD: /bin/systemctl stop mystamps,/bin/systemctl start mystamps,/bin/systemctl restart mystamps
root@my-server# chmod 0440 /etc/sudoers.d/10_mystamps

Configuring hostname

This step is optional. You just need to be sure that your host has correct name and you can ping my-stamps.ru from the server.

coder@my-server$ sudo vim /etc/hostname
-vm97429.local
+my-stamps.ru
coder@my-server$ sudo vim /etc/hosts
-127.0.1.1       ubuntu-20140330.flops.ru        ubuntu-20140330
-10.7.40.29      vm97429.local
+127.0.1.1       my-stamps.ru

Configuring SSH

Attention: before proceed you must create and copy certificates for users coder and mystamps.

For example:

coder@my-server$ mkdir .ssh
coder@my-server$ chmod 700 .ssh
coder@my-server$ vim .ssh/authorized_keys
coder@my-server$ chmod 600 .ssh/authorized_keys
coder@my-server$ sudo vim /etc/ssh/sshd_config
-PermitRootLogin yes
+PermitRootLogin no
+DebianBanner no
-#PasswordAuthentication yes
+PasswordAuthentication no
+PubkeyAuthentication yes
+AllowUsers coder mystamps
+UseDNS no
coder@my-server$ sudo service ssh reload

Note that since 16.04. UseDns has no by default.

Upgrading operating system

coder@my-server$ sudo apt-get update
coder@my-server$ sudo apt-get upgrade
coder@my-server$ sudo apt-get clean
coder@my-server$ sudo apt-get remove -y nano

And if reboot is required:

coder@my-server$ sudo reboot

Configuring timezone (optional)

coder@my-server$ timedatectl
coder@my-server$ sudo timedatectl set-timezone Europe/Moscow
coder@my-server$ timedatectl

See also How To Set Up Timezone

Installing logwatch

coder@my-server$ sudo apt-get install -y logwatch
coder@my-server$ sudo touch /etc/logwatch/conf/logwatch.conf
coder@my-server$ sudoedit /etc/logwatch/conf/logwatch.conf
Detail = High
Service = "-sshd"

Installing MySQL server

coder@my-server$ sudo apt-get install -y mysql-server-5.7
coder@my-server$ sudo mysql -u root -p
mysql> CREATE DATABASE mystamps CHARACTER SET utf8;
mysql> CREATE USER mystamps@localhost IDENTIFIED BY 'p@assword';
mysql> GRANT ALL PRIVILEGES ON mystamps.* TO mystamps@localhost;
mysql> FLUSH PRIVILEGES;

The following steps is not needed anymore:

coder@my-server$ sudo vim /etc/mysql/conf.d/utf8.cnf
[mysqld]
character_set_server=utf8
coder@my-server$ sudo service mysql restart

Restoring database backup (optional)

user@home$ scp /path/to/backups/mysql_backup_mystamps_20140430-231001.sql.bz2 coder@my-server:~
coder@my-server$ bzcat mysql_backup_mystamps_20140430-231001.sql.bz2 |  mysql -u mystamps -p mystamps
coder@my-server$ rm -fv mysql_backup_mystamps_20140430-231001.sql.bz2

Installing JDK

OUTDATED: use php-coder.oraclejdk Ansible role instead.

coder@my-server$ sudo apt-get install -y software-properties-common
coder@my-server$ sudo add-apt-repository ppa:webupd8team/java
coder@my-server$ sudo apt-get update
coder@my-server$ sudo apt-get install -y oracle-java8-installer oracle-java8-set-default

Installing nginx

OUTDATED: use php-coder.nginx Ansible role instead.

coder@my-server$ echo "deb http://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
coder@my-server$ curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -
coder@my-server$ sudo apt-get update
coder@my-server$ sudo apt-get install nginx
coder@my-server$ sudo rm -fv /etc/nginx/conf.d/*
removed ‘/etc/nginx/conf.d/default.conf’
removed ‘/etc/nginx/conf.d/example_ssl.conf’

Setting up application

Building application

user@home$ git clone https://github.com/php-coder/mystamps.git
user@home$ cd mystamps
user@home$ mvn clean package

Copying application

OUTDATED: use mystamps-app Ansible role instead.

user@home$ scp target/mystamps.war coder@my-server:/tmp
coder@my-server$ sudo mv /tmp/mystamps.war /data/mystamps
coder@my-server$ sudo chown mystamps:mystamps /data/mystamps/mystamps.war
coder@my-server$ sudo chmod 700 /data/mystamps/mystamps.war

Setting up log directories

OUTDATED: use mystamps-app and mystamps-nginx Ansible roles instead.

coder@my-server$ sudo mkdir /data/logs
coder@my-server$ sudo chown mystamps:mystamps /data/logs
coder@my-server$ sudo chgrp nginx /data/logs
coder@my-server$ sudo chmod 775 /data/logs

Setting up upload directory

OUTDATED: use mystamps-app Ansible role instead.

coder@my-server$ sudo mkdir /data/uploads
coder@my-server$ sudo chown mystamps:mystamps /data/uploads

Restoring uploaded files (optional)

If you have backup of uploaded files:

user@home$ scp -r /path/to/uploads coder@my-server:/tmp
coder@my-server$ sudo mv /tmp/uploads/* /data/uploads
coder@my-server$ rm -rfv /tmp/uploads
coder@my-server$ sudo chown -R mystamps:mystamps /data/uploads

Setting up init script

OUTDATED: use mystamps-app Ansible role instead.

Create /data/mystamps/mystamps.conf:

user@home$ scp /path/to/mystamps/repo/infra/ansible/roles/mystamps-app/templates/mystamps.conf coder@my-server:/tmp
coder@my-server$ sed 's|{{ profile }}|prod|' mystamps.conf | sudo tee /data/mystamps/mystamps.conf
coder@my-server$ sudo rm mystamps.conf
coder@my-server$ sudo chown mystamps:mystamps /data/mystamps/mystamps.conf

Create /data/mystamps/config/application-prod.properties

user@home$ scp /path/to/mystamps/repo/infra/ansible/roles/mystamps-app/templates/application-prod.properties coder@my-server:/tmp
coder@my-server$ sed 's|{{ user_db_password }}|p@ss1|;s|{{ user_mail_password }}|p@ss2|' application-prod.properties | sudo tee /data/mystamps/config/application-prod.properties
coder@my-server$ sudo rm application-prod.properties 
coder@my-server$ sudo chown mystamps:mystamps /data/mystamps/config/application-prod.properties
coder@my-server$ sudo chmod 600 mystamps:mystamps /data/mystamps/config/application-prod.properties

Create /etc/systemd/system/mystamps.service

user@home$ scp /path/to/mystamps/repo/infra/ansible/roles/mystamps-app/files/mystamps.service coder@my-server:/tmp
coder@my-server$ sudo mv mystamps.service /etc/systemd/system/mystamps.service
coder@my-server$ sudo chown root:root /etc/cron.d/mystamps

Running application

OUTDATED: use mystamps-app Ansible role instead.

coder@my-server$ sudo systemctl start mystamps
coder@my-server$ sudo systemctl enable mystamps

Getting the SSL certificates from LetsEncrypt

Install and run certbot:

user@home$ brew install letsencrypt
user@home$ sudo certbot certonly --manual -d my-stamps.ru -d www.my-stamps.ru -d stamps.filezz.ru

Create special file on the server:

coder@my-server$ sudoedit /etc/nginx/conf.d/mystamps-http.conf
-  server_name my-stamps.ru www.my-stamps.ru;
+  server_name my-stamps.ru www.my-stamps.ru stamps.filezz.ru;
...
- return 301 https://$host$request_uri;
+ location /.well-known/acme-challenge {
+   default_type text/plain;
+   root /tmp;
+ }
+ location / {
+   return 301 https://$host$request_uri;
+ } 
coder@my-server$ mkdir -p /tmp/.well-known/acme-challenge
coder@my-server$ sudo systemctl reload nginx
coder@my-server$ cd /tmp/.well-known/acme-challenge
# create files for each domain
coder@my-server$ echo -n 'mli87lFDUgUeAPRW1lJ6RxuGx0UfBJrs674vgJQ6194.alBg2nvuo5oIztKkLw1FzktggLSaYt33skyUrw2dv4g' > mli87lFDUgUeAPRW1lJ6RxuGx0UfBJrs674vgJQ6194
coder@my-server$ curl -v 'https://my-stamps.ru/.well-known/acme-challenge/mli87lFDUgUeAPRW1lJ6RxuGx0UfBJrs674vgJQ6194'

Finishing SSL keys fetching procedure and install them to the server:

user@home$ cd infra/ansible
user@home$ mkdir roles/mystamps-nginx/files/prod
user@home$ sudo ls -l /etc/letsencrypt/live/my-stamps.ru/{fullchain,privkey}.pem
user@home$ sudo cp -v /etc/letsencrypt/live/my-stamps.ru/privkey.pem roles/mystamps-nginx/files/prod/my-stamps.ru.key
user@home$ sudo cp -v /etc/letsencrypt/live/my-stamps.ru/fullchain.pem roles/mystamps-nginx/files/prod/my-stamps.ru.crt
user@home$ sudo chown coder roles/mystamps-nginx/files/prod/my-stamps.ru.*
user@home$ ansible-galaxy role install -r requirements.galaxy.yml -p roles # only if never run ansible before
user@home$ ansible-playbook prod.yml -i prod.inventory --private-key=$HOME/.ssh/mystamps_rsa --tags ssl --check
user@home$ ansible-playbook prod.yml -i prod.inventory --private-key=$HOME/.ssh/mystamps_rsa --tags ssl
user@home$ sudo chown root roles/mystamps-nginx/files/prod/my-stamps.ru.*

Ansible will upload certificates and also reset the state of /etc/nginx/conf.d/mystamps-http.conf file (so you don't need to roll back your modifications manually).

Cleanup on the server:

coder@my-server$ cd
coder@my-server$ rm -rfv /tmp/.well-known

Detail at information:

Configuring nginx

OUTDATED: use mystamps-nginx Ansible role instead.

TBD (create /data/nginx, copy vhost files, copy 503.*.html files, copy ssl keys)

Configuring database backup

OUTDATED: use mystamps-backup Ansible role instead.

coder@my-server$ sudo mkdir /data/backups
coder@my-server$ sudo chown mystamps:mystamps /data/backups
coder@my-server$ sudo chmod 750 /data/backups

mystamps@my-stamps:~$ vim /data/mystamps/.my.cnf
[client]
user = mystamps
password = p@assword
mystamps@my-stamps:~$ chmod 600 .my.cnf

user@home$ scp /path/to/mystamps/repo/src/main/config/cron/mystamps coder@my-server:/tmp
coder@my-server$ sudo mv /tmp/mystamps /etc/cron.d
coder@my-server$ sudo chown root:root /etc/cron.d/mystamps

Installing Apticron

coder@my-server$ sudo apt-get install -y apticron
coder@my-server$ sudoedit /etc/apticron/apticron.conf
-#EMAIL="root"
+EMAIL='[email protected]'
SYSTEM='my-stamps.ru'
CUSTOM_FROM='[email protected]'

Installing/configuring Exim

coder@my-server$ sudo apt-get install -y exim4
coder@my-server$ sudo dpkg-reconfigure exim4-config
# choose type "internet"
coder@my-server$ echo "This is a test." | mail -s Testing [email protected]

See also How To Install the Send-Only Mail Server "Exim"

Now, in order to fix errors like 2018-12-30 05:00:01 H=gmail-smtp-in.l.google.com [2a00:1450:400c:c07::1b] Network is unreachable do the following:

coder@my-server$ sudo netstat -nlp | grep :25
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1490/exim4
tcp6       0      0 ::1:25                  :::*                    LISTEN      1490/exim4
coder@my-server$ sudoedit /etc/exim4/update-exim4.conf.conf
-dc_local_interfaces='127.0.0.1 ; ::1'
+dc_local_interfaces='127.0.0.1'
coder@my-server$ sudo systemctl restart exim4
coder@my-server$ sudo netstat -nlp | grep :25
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      16502/exim4

See for details: https://askubuntu.com/questions/927056/disable-ipv6-in-exim4/944419#944419

Installing NewRelic agent for application monitoring

TBD

Installing NewRelic agent for server monitoring

Follow the instructions from official site:

coder@my-server$ echo 'deb http://apt.newrelic.com/debian/ newrelic non-free' | sudo tee /etc/apt/sources.list.d/newrelic.list
coder@my-server$ wget -O- https://download.newrelic.com/548C16BF.gpg | sudo apt-key add -
coder@my-server$ sudo apt-get update
coder@my-server$ sudo apt-get install -y newrelic-sysmond
coder@my-server$ sudo vim /etc/newrelic/nrsysmond.cfg
-#license_key=REPLACE_WITH_REAL_KEY
+license_key=xxxxxxxxxxxxxxxxxxxx
-#disable_nfs=false
+disable_nfs=true
-#disable_docker=false
+disable_docker=true
coder@my-server$ sudo rm -fv /var/log/newrelic/php_agent.log /var/log/newrelic/newrelic-daemon.log

Installing Logentries agent for centralized logging

coder@my-server$ echo 'deb http://rep.logentries.com/ trusty main' | sudo tee /etc/apt/sources.list.d/logentries.list
coder@my-server$ gpg --keyserver pgp.mit.edu --recv-keys C43C79AD && gpg -a --export C43C79AD | sudo apt-key add -
coder@my-server$ sudo apt-get update
coder@my-server$ sudo apt-get install -y logentries
coder@my-server$ sudo le register
Account key is required. Enter your Logentries login credentials or specify the account key with --account-key parameter.
Email: [email protected]
Password:
Registered yyyy (yyyy.org)
coder@my-server$ sudo apt-get install -y logentries-daemon
coder@my-server$ sudo le follow /data/logs/mystamps.log
coder@my-server$ sudo le follow /data/logs/nginx.log
coder@my-server$ sudo le follow /data/logs/nginx-static.log
coder@my-server$ sudo le follow /var/log/auth.log
coder@my-server$ sudo le follow /var/log/kern.log
coder@my-server$ sudo le follow /var/log/mysql.err
coder@my-server$ sudo le follow /var/log/mysql.log
coder@my-server$ sudo le follow /var/log/newrelic/nrsysmond.log
coder@my-server$ sudo le follow /var/log/ufw.log
coder@my-server$ sudo le follow /var/log/syslog
coder@my-server$ sudo le follow /var/log/mail.log
coder@my-server$ sudo le follow /var/log/mail.err
coder@my-server$ sudo le follow /var/log/nginx/access.log
coder@my-server$ sudo le follow /var/log/nginx/error.log
coder@my-server$ sudo le follow /var/log/mysql/error.log --name mysql-error.log
coder@my-server$ sudo service logentries restart

Other

Adding swap a file

TODO: add more details

coder@my-server$ sudoedit /etc/fstab
+/swap1	none	swap	sw	0	0
+/swap2	none	swap	sw	0	0
$ grep swap /etc/sysctl.conf
vm.swappiness = 30

See also: https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04

Comment out all deb-src sources

coder@my-server$ sudoedit /etc/apt/sources.list
# comment out all deb-src sources

Disable automatic updates

coder@my-server$ sudo systemctl disable apt-daily.service
coder@my-server$ sudo systemctl disable apt-daily.timer
coder@my-server$ sudo systemctl disable apt-daily-upgrade.timer # I'm not sure that it's required
coder@my-server$ sudo apt-get remove -y unattended-upgrades

See also: