Setup Ashwini
Running documentation for the server setup in Ashwini. Here are some Linux references which I find useful:
- Linux from Scratch main book – Stable version | All releases. There are many helpful installation notes in the subprojects, e.g. BLFS or Beyond Linux from Scratch.
Internet Connection
For overview see, Configuring Networks on Ubuntu Server.
- Check ethernet name:
ip -d address
- Create configuration in
/etc/netplan/01-netcfg.yaml
.
network:
version: 2
renderer: networkd
ethernets:
# interface name
ens18:
dhcp4: false
# IP address / subnet mask
# removed exact numbers for security
addresses:
- xxx.xxx.xxx.xxx/25
# default gateway
routes:
- to: default
via: xxx.xxx.xxx.xxx
nameservers:
addresses:
- 1.1.1.1
- 8.8.8.8
- 8.8.4.4
dhcp6: false
- Apply configuration
sudo netplan --debug apply
- Ping local IP and external IP to check
ping xxx.xxx.xxx.xxx
ping google.com
- I like to see what is happening!
ip -s link show ens18
ip route show
Update OS
sudo apt update
sudo apt upgrade
sudo reboot
sudo apt install vim build-essential git
Purge snap
I do not like things happening in the background without my consent. Therefore, I remove snap after a fresh Ubuntu install. I list the snap
packages, stop the snap
daemon service(s), and remove each snap package individually, starting with non-canonical packages. I remove the snapd
package and all the related directories.
sudo snap list
sudo systemctl disable snapd.service
sudo systemctl disable snapd.socket
sudo systemctl disable snapd.seeded.service
sudo snap remove --purge lxd
sudo snap remove --purge core20
sudo snap list # check this does not list anything else
sudo apt remove --autoremove snapd
sudo rm -rf ~/snap /snap /var/snap /var/lib/snapd /root/snap
The last command complained about “read-only file system”. So, I had to reboot and rerun the command. Some systemd services were still blocking the mount points. I manually obliterated snap related systemd services, following this Stackoverflow answer.
cd /etc/systemd/system
sudo systemctl stop snap-snapd-18357.mount
sudo systemctl disable snap-snapd-18357.mount
sudo rm -f snap-snapd-18357.mount
sudo systemctl daemon-reload
sudo systemctl reset-failed
I did the same thing for all these services:
- snap-snapd-20092.mount
- snapd.aa-prompt-listener.service
- snapd.apparmor.service
- snapd.autoimport.service
- snapd.core-fixup.service
- snapd.snap-repair.timer
- snapd.system-shutdown.service - snapd.recovery-chooser-trigger.service
To-Do: snapd.seeded.service
is still being listed by systemctl list-units -a
. How to remove?
Prevent snap from re-installing. Create the file /etc/apt/preferences.d/nosnap.pref
with the following content and save.
Package: snapd
Pin: release a=*
Pin-Priority: -10
Add User For Tasks
user minion
, group minion
(not in sudoer list)
sudo groupadd minion
sudo usermod -a -G minion banskt
sudo useradd -g minion -m -c "User account for webstack" -s /bin/bash minion
sudo passwd minion
SSH Security
- Select a port to change the default SSH Port. Do not choose a port already in use. Ports from 0 to 1023 are reserved and should not be used. Choose a port greater than 1023 and less than 65535. Check using:
ss
ss - tulpn
- Change the following relevant lines in
/etc/ssh/sshd_config
# Change protocol
Protocol 2
#
Port xxxxx
LogLevel VERBOSE
PermitRootLogin no
# trusted hosts are still considered a security risk
HostbasedAuthentication no
IgnoreRhosts yes
# do not allow eavesdropping
PermitEmptyPasswords no
# better to not allow TCP forwarding, but required for SSH tunnels
AllowTcpForwarding yes
# don't have X11 on server
X11Forwarding no
# last login info can provide available users to hackers
PrintLastLog no
Save the file and restart SSH service.
sudo systemctl restart ssh
sudo systemctl status ssh
- Open the port in firewall
sudo apt install ufw
sudo ufw app list
sudo ufw status verbose
sudo ufw allow xxxxx/tcp # enter the SSH port here
sudo ufw enable
sudo ufw status verbose
- Set up
~/.ssh/config
and SSH key on the client side. - Check if SSH is working!
Add Swap Memory
sudo -i
dd if=/dev/zero of=/swapfile bs=1024 count=1048576 #1GB: 1024 x 1024 = 1048576
chmod 0600 /swapfile
mkswap /swapfile
swapon /swapfile
echo "/swapfile none swap sw 0 0" >> /etc/fstab
swapon -s
free -m
Mount Hard Disks
- Check existing partitions and harddisks
sudo lsblk
sudo fdisk -l
sudo lshw -C disk
- Partition using
parted
. - Create entry in
etc/fstab
. You can check all uuid fromls -lh /dev/disk/by-uuid/
or individually fromsudo blkid /dev/sdb1
.
# /dev/sdb1 --> /opt
/dev/disk/by-uuid/xxxx /opt ext4 defaults 0 2
# /dev/sdb2 --> ~/local
/dev/disk/by-uuid/xxxx /home/banskt/local ext4 user,rw,suid,dev,exec,auto,async 0 2
# /dev/sdb3 --> ~/data
/dev/disk/by-uuid/xxxx /home/banskt/data ext4 user,rw,suid,dev,exec,auto,async 0 2
The sequence of options are important. - After mounting you have to change the ownership of the directories, if required. - Reboot and check if the partitions are mounted automatically.
Bash
Install dotfiles from Github. But, I did not want to install everything from .dotfiles
. So, I made a dryrun
to import the functions and link individual dotfiles.
git clone https://github.com/banskt/dotfiles.git ~/.dotfiles
source ~/.dotfiles/install dryrun
DRYRUN=false
backup_and_link .bashrc bash/bashrc
backup_and_link .vimrc vim/vimrc
backup_and_link .vim vim/dotvim
cp ~/.dotfiles/git/gitconfig ~/.gitconfig
cp ~/.dotfiles/ssh/config ~/.ssh/
chmod 600 ~/.ssh/config
I edited the .ssh/config
file and kept configurations for Github and my other servers (vultr and feral). I edited the .gitconfig
to include my email. Logout and login for the changes to take effect.
Finally, create SSH key for Github and add that key to the Github account!
cd ~/.ssh
ssh-keygen -t ed25519 -f github_key
git remote set-url origin git@github.com:banskt/dotfiles.git
git remote show origin
Note: Any custom bash script for this server must go to ~/.custom_dotfiles/bashrc
. Common bash scripts go to the ~/.dotfiles
.
To-Do: Include a server
flag for installation.
Reduce Automatic Network Usage
There are some default packages or services that connects to the internet without my consent. AskUbuntu Question.
Environment Modules
I love modules to manage my shell environment. For a dedicated server, it may not be necessary, but it helps me to manage versions and updates.
First, install the dependencies.
# use apt-cache search for the latest version
sudo apt install tcl8.6-dev
# dejagnu provides runtest. Only install if you want to run `make test`, skip otherwise
# without dejagnu, configure produces this -->
## WARNING: Install `dejagnu' if you want to run the testsuite
sudo apt install dejagnu
Note: I have not installed dejagnu
.
Next, install the package.
wget github.com/cea-hpc/modules/releases/download/v5.3.1/modules-5.3.1.tar.gz
tar -zxf modules-5.3.1.tar.gz
./configure --prefix=/opt/modules --modulefilesdir=/opt/modulefiles --with-tcl-ver=8.6
make -j 2
sudo make install
Finally, configure. Initialize modules in ~/.custom_dotfiles/bashrc
: This has to be included in bashrc of each user who need to access modulefiles. Alternative is to include it in /etc/bash.bashrc
or /etc/profile
but those are not guranteed to be invoked (see decision tree for loading config files in different shell environments).
# Environment modules
source /opt/modules/init/bash
Also, put all the example dotfiles in a separate directory so that do not show up in module avail
.
sudo mkdir -p /opt/modules/examples
cd /opt/modulefiles
sudo mv dot module-git module-info modules null use.own /opt/modules/examples/
Webtack (nginx, SSL, PHP)
Previously, I installed a webstack in Kalindi.
Install nginx from source
Compiling nginx from source affords more flexibility than prebuilt packages: I can add particular modules (from nginx or third parties), and apply latest security patches. See official documentation for help.
1. Install prerequisites.
PCRE2
I prefer to manage the library files in the OS using apt
. So, I use apt install
.
sudo apt install libpcre2-dev
Surprise: pcre3
is older than pcre2
. Do not install pcre3
.
If you want to configure, build and install PCRE2 from scratch, it can be done as:
sudo apt install zlib1g-dev libbz2-dev libreadline-dev libedit-dev
wget github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.tar.gz
tar -zxf pcre2-10.42.tar.gz
cd pcre2-10.42
./configure --prefix /opt/pcre2/10.42 --enable-unicode --enable-jit --enable-pcre2-16 --enable-pcre2-32 --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-pcre2test-libreadline --disable-static
make -j 2
make check
sudo make install
Zlib
sudo apt install zlib1g-dev
OpenSSL
nginx requires libssl-dev
package. But before installing anything, I checked the distribution of current OpenSSL package:
openssl version -a
I have version 3.0.2 installed by default. I wanted the latest version of OpenSSL, hence I configured myself (see documentation) using the configuration options of Linux from Scratch. Run ./Configure LIST
to see a list of configuration options.
wget https://www.openssl.org/source/openssl-3.1.3.tar.gz
tar -zxf openssl-3.1.3.tar.gz
mkdir openssl-3.1.3-build
cd openssl-3.1.3-build/
../openssl-3.1.3/Configure linux-x86_64 --prefix=/opt/openssl/3.1.3/ zlib-dynamic shared
make -j 2
make test
sudo make install
I created a module file to load/unload the required OpenSSL version easily.
module load openssl/3.1.3
module unload openssl/3.1.3
2. Install nginx
Configure
Download the source files from nginx.org. I used the latest stable release.
wget https://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxf nginx-1.24.0.tar.gz
There are many configuration options for nginx – official docs | open source project.
Other resources include:
- Erick T. Hitter discusses compiling nginx with custom OpenSSL support – mirror on waybackmachine.
- Stackoverflow: Can’t compile nginx with SSL support, OpenSSL not found
- nginx forum: build nginx with OpenSSL shared library not using the system OpenSSL library but using the shared library in a specific path.
Here are the configuration options I used which can also be checked later using nginx -V
.
./configure \
--prefix=/opt/nginx/1.24.0 \
--builddir=../nginx-1.24.0-build \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-mail \
--with-mail_ssl_module \
--with-pcre \
--with-threads \
--with-file-aio \
--with-cc-opt="-I /opt/openssl/3.1.3/include" \
--with-ld-opt="-L /opt/openssl/3.1.3/lib64 -ldl -Wl,-rpath,/opt/openssl/3.1.3/lib64"
One liner (for copy/paste):
./configure --prefix=/opt/nginx/1.24.0 --builddir=../nginx-1.24.0-build --with-http_ssl_module --with-pcre --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-cc-opt="-I /opt/openssl/3.1.3/include" --with-ld-opt="-L /opt/openssl/3.1.3/lib64 -ldl -Wl,-rpath,/opt/openssl/3.1.3/lib64"
Here is the configuration output which may be helpful later:
Configuration summary
+ using threads
+ using system PCRE2 library
+ using system OpenSSL library
+ using system zlib library
nginx path prefix: "/opt/nginx/1.24.0"
nginx binary file: "/opt/nginx/1.24.0/sbin/nginx"
nginx modules path: "/opt/nginx/1.24.0/modules"
nginx configuration prefix: "/opt/nginx/1.24.0/conf"
nginx configuration file: "/opt/nginx/1.24.0/conf/nginx.conf"
nginx pid file: "/opt/nginx/1.24.0/logs/nginx.pid"
nginx error log file: "/opt/nginx/1.24.0/logs/error.log"
nginx http access log file: "/opt/nginx/1.24.0/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"
Build
Build nginx in the new build directory.
make -f ../nginx-1.24.0-build/Makefile -j 2
sudo make -f ../nginx-1.24.0-build/Makefile install
3. Post-install configuration
I initially considered using custom ports for HTTP and HTTPS (instead of the default 80 and 443) but I rejected the idea because Let’s Encrypt requires port 80 for generating and renewing certificates. These articles also helped in making the decision:
nginx.conf
Modify the configuration file for external access. Here is my initial nginx configuration in /opt/nginx/1.24.0/conf/nginx.conf
.
user minion;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name 127.0.0.1 <ipv4_address>;
location / {
root html;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
} }
Open port in firewall
To register nginx
as an ufw
application, create a file /etc/ufw/applications.d/nginx
. Replace xx
with port numbers for HTTP and HTTPS. If you are running nginx as a non-root user, then you have to change the accessible port because the default port 80 is not available to non-root users. Therefore, it’s necessary to use a port > 1000.
[Nginx HTTP]
title=Web Server (Nginx, HTTP)
description=Small, but very powerful and efficient web server
ports=80/tcp
[Nginx HTTPS]
title=Web Server (Nginx, HTTPS)
description=Small, but very powerful and efficient web server
ports=443/tcp
[Nginx Full]
title=Web Server (Nginx, HTTP + HTTPS)
description=Small, but very powerful and efficient web server
ports=80,443/tcp
Check the registered app and allow nginx HTTP.
sudo ufw app info 'Nginx HTTP'
sudo ufw allow 'Nginx HTTP'
Log files should be accessible by the user minion
.
chown -R root:minion /opt/nginx/1.24.0/logs
chown minion:minion /opt/nginx/1.24.0/logs/access.log
chown minion:minion /opt/nginx/1.24.0/logs/error.log
chmod 775 /opt/nginx/1.24.0/logs
Useful commands
Check nginx configuration and start nginx.
# check configuration
sudo /opt/nginx/1.24.0/sbin/nginx -t
# start
sudo /opt/nginx/1.24.0/sbin/nginx
# stop
sudo /opt/nginx/1.24.0/sbin/nginx -s stop
# restart
sudo /opt/nginx/1.24.0/sbin/nginx -s reload
systemd
Create a systemd service file to control nginx using systemctl
as described in the official documentation. In Ubuntu 22.04, the file is /lib/systemd/system/nginx.service
.
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/opt/nginx/1.24.0/logs/nginx.pid
ExecStartPre=/opt/nginx/1.24.0/sbin/nginx -t
ExecStart=/opt/nginx/1.24.0/sbin/nginx
ExecReload=/opt/nginx/1.24.0/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Now, I can use systemctl
commands to control nginx.
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
Check
Fire up the browser and check both links:
- http://127.0.0.1
- http://<ipv4_address>
If you are installing on the server and you do not have access to the localhost (127.0.0.1)
of the remote server, then you can ssh-tunnel to the remote server from your local machine. For example, I defined ashwini
in ssh/config
of the local machine and installed ssh-localportfwd
from here.
ssh-localportfwd open ashwini 80 <local_port>
Then, I can access the localhost
of the remote machine using http://127.0.0.1:xx
where xx
is the local_port
of my local machine through which I tunneled. The second IPv4 address should work from external network.
The SSL connection will still not work. Do not worry yet.
Modular control
Once everything was working, I removed the external IP from the base configuration of nginx and created server configurations in ~/local/etc/nginx/sites-available/
For example, here is my 000-default-server.conf
:
server {
listen 80 default_server;
server_name <ipv4_address>;
location / {
root /path/to/webdata/base;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /path/to/webdata/base;
}
# produce a directory listing using ngx_http_autoindex_module
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
# Deny access to anything starting with .ht
location ~ /\.ht {
deny all;
} }
I added the following line to /opt/nginx/1.24.0/conf/nginx.conf
:
include /home/banskt/local/etc/nginx/sites-enabled/*
And then created the sites-enabled
directory:
mkdir -p ~/local/etc/nginx/sites-enabled
cd ~/local/etc/nginx/sites-enabled
ln -s /home/banskt/local/etc/nginx/sites-available/000-default-server.conf ./default
This way, I can manage adding domains, sub-domains, sub-directories on my server directly from my sites-available
and sites-enabled
directories.
At this point, 127.0.0.1
should serve the nginx welcome message and <ipv4_address>
should serve the HTML files from /path/to/webdata/base
. Again, check they are working with ssh-localportfwd
.
Link domain name
I had purchased several domain names. Now, it is time to put one of them to use. You can skip this step and access the server using IPv4 address instead.
- Login to namesilo.com
- Manage DNS
- Use default nameservers of
namesilo.com
- Change
A
record pointing to the VPS IPv4 address. You can point different subdomains to different IP addresses. If you want to point every subdomain to the same IP, you can use an asterisk (*
) as your subdomain. - Update
nginx.conf
, change IPv4 address tomydomain.com
.
Alias www to non-www
I want to redirect all traffic from www
to non-www
. Easiest way is to define an A
entry for www.mydomain.com
and use 301 redirect from nginx configuration. However, when my IP changes then I have to change the A
record for both mydomain.com
and www.mydomain.com
. Another solution is to use CNAME
entry in the DNS zone file and redirect in the server nginx configuration. Both of them are required as explained in this Stackoverflow answer.
A CNAME record does not function the same way as a URL redirect. A CNAME record directs web traffic for a particular domain to the target domain’s IP address. Once the visitor reaches that IP address, the web server’s configuration will determine how the domain is handled. If that domain is not configured on the server, the server will simply display its default web page (if any). This may or may not be the web page for the target domain in the CNAME record, depending on how the server is configured.
- Add
CNAME
entry in zonefile. - Add 301 redirect in
nginx.conf
server {
listen 80;
server_name www.mydomain.com;
return 301 $scheme://mydomain.com$request_uri; }
Check DNS
There are many DNS lookups, but I like intoDNS.
SSL
I did not use certbot
because it enforced installation using snap
.
- Install acme. The options used for the installation are explained in the documentation.
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh/
./acme.sh --install --home /home/banskt/local/apps/acme --accountemail banskt.saikat@gmail.com
Delete the entry in ~/.bashrc
and add it to ~/.custom_dotfiles/bashrc
.
# Source acme.sh for SSL certificates
source "/home/banskt/local/apps/acme/acme.sh.env"
After sourcing, acme.sh
will be available on commandline. Check.
- Create the acme-challenge directory in the document root.
cd /path/to/webdata/base
mkdir -p .well-known/acme-challenge/
sudo chown -R minion:minion .well-known
sudo chmod -R 770 .well-known
and give permissions according to your setup.
- Create directory to store SSL certificates
cd /home/banskt/local/etc/nginx/
mkdir -p ssl/mydomain.com/
- Generate dhparams file
cd /home/banskt/local/etc/nginx/ssl/
module load openssl/3.1.3
openssl dhparam -out dhparams.pem 4096
- Issue certificates. Optionally, use DNS API. You can either issue certificate for a single domain,
acme.sh --issue -d foo.mydomain.com -w /path/to/webdata/base -k 4096
or have multiple domains in the same certificate.
acme.sh --issue -d mydomain.com -d www.mydomain.com -w /path/to/webdata/base -k 4096
Here, -w
specifies the document root of the website where the acme-challenge is created, -k
specifies the domain key length.
- Generate SSL configurations from Mozilla SSL Configuration Generator. Write the configuration in
/opt/nginx/1.24.0/conf/ssl_params.conf
so that it can be included for all servers. Remember to update your DNS resolver from/etc/resolv.conf
. For each server, create the SSL nginx configuration, for example,
ssl_certificate /home/banskt/local/etc/nginx/ssl/sbanerjee.in/fullchain.pem;
ssl_certificate_key /home/banskt/local/etc/nginx/ssl/sbanerjee.in/privkey.pem;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /home/banskt/local/etc/nginx/ssl/sbanerjee.in/fullchain.pem; include /opt/nginx/1.24.0/conf/ssl_params.conf;
- Install the issued certificate to nginx server
acme.sh --install-cert -d mydomain.com \
--fullchain-file /home/banskt/local/etc/nginx/ssl/mydomain.com/fullchain.pem \
--key-file /home/banskt/local/etc/nginx/ssl/mydomain.com/privkey.pem \
--reloadcmd ""
#
acme.sh --install-cert -d foo.mydomain.com \
--fullchain-file /home/banskt/local/etc/nginx/ssl/foo.mydomain.com/fullchain.pem \
--key-file /home/banskt/local/etc/nginx/ssl/foo.mydomain.com/privkey.pem \
--reloadcmd "sudo systemctl restart nginx"
- Check everything is working! Use browser and Qualys SSL server test.
acme.sh --help
acme.sh --list
Improve speed and performance
- Tuning nginx can improve speed and performance.
- Better SSL configuration
- Let’s Encrypt without port 80
- nginx full example config
I modified my nginx.conf
to improve speed, performance and security.
I also setup custom locations for the worker process in home/banskt/local/etc/nginx
and setup proper access.
mkdir -p /home/banskt/local/etc/nginx/worker
sudo chown -R minion:minion /home/banskt/local/etc/nginx/worker
# use ssh port to login for user minion
ssh minion@localhost -p xxxxx
cd /home/banskt/local/etc/nginx
sudo mkdir worker && cd worker
mkdir client_body fastcgi uwscgi scgi proxy logs
chmod -R 700 client_body/ fastcgi/ proxy/ scgi/ uwscgi/
cd logs
touch access.log error.log
chmod 644 access.log error.log
cd ..
# exit and change owner of logs to root
exit
sudo chown -R root:minion /home/banskt/local/etc/nginx/worker/logs
Specify the new directories in nginx.conf
and /lib/systemd/system/nginx.service
. The PID file location must be same in both. After changing systemd file, we need to reload daemon.
sudo systemctl stop nginx
sudo systemctl daemon-reload
sudo systemctl reset-failed
sudo systemctl start nginx
Bug: nginx -t
still tries to open the default error log file with which it was compiled. It throws an alert if it does not find the file. I do not like alerts. Therefore, I created a dummy file at the compilation location.
Update: My nginx configuration files are now backed up here.
Install MySQL
Installing MySQL from source is mildly convoluted and risk non-optimal settings leading to reduced functionality, performance, or security (see here). So, I installed a generic binary as explained here.
wget https://dev.mysql.com/get/Downloads/MySQL-8.1/mysql-8.1.0-linux-glibc2.28-x86_64.tar.xz --no-check-certificate
sudo mkdir -p /opt/mysql/
sudo tar xf mysql-8.1.0-linux-glibc2.28-x86_64.tar.xz -C /opt/mysql/
sudo ln -s /opt/mysql/mysql-8.1.0-linux-glibc2.28-x86_64 /opt/mysql/8.1.0
cd /opt/mysql/8.1.0
sudo chown -R root:root *
sudo mkdir etc
Post-install setup and testing
- Create an initial configuration file in
/opt/mysql/8.1.0/etc/my.cnf
.
[mysqld]
basedir=/opt/mysql/mysql-8.1.0-linux-glibc2.28-x86_64
datadir=/opt/mysql/mysql-8.1.0-linux-glibc2.28-x86_64/data
# Enable error log
[mysqld_safe]
log_error=/home/banskt/local/etc/mysql/logs/mysql_error.log
[mysqld]
log_error=/home/banskt/local/etc/mysql/logs/mysql_error.log
# General query log
general_log_file = /home/banskt/local/etc/mysql/logs/mysql.log
general_log = 1
# Slow Query Log
slow_query_log = 1
slow_query_log_file = /home/banskt/local/etc/mysql/logs/mysql_slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
#
secure_file_priv = /home/banskt/local/etc/mysql/mysql-files
- Initialize the data directory and create the MySQL grant tables. See detailed instructions.
cd /home/banskt/local/etc/
mkdir mysql && cd mysql
mkdir logs mysql-files
sudo chown minion:minion logs mysql-files
sudo chmod 750 logs mysql-files
sudo /opt/mysql/8.1.0/bin/mysqld --defaults-file=/opt/mysql/8.1.0/etc/my.cnf --initialize --user=minion
# Note the temporary password created in the log file logs/mysql_error.log
- Create systemd file
/lib/systemd/system/mysql.service
.
[Unit]
Description=MySQL Community Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=minion
Group=minion
# Have mysqld write its state to the systemd notify socket
Type=notify
# PermissionsStartOnly=true
# ExecStartPre=/mysql-systemd-start pre
# Start main service
ExecStart=/opt/mysql/mysql-8.1.0-linux-glibc2.28-x86_64/bin/mysqld --defaults-file=/opt/mysql/mysql-8.1.0-linux-glibc2.28-x86_64/etc/my.cnf $MYSQLD_OPTS
# Disable service start and stop timeout logic of systemd for mysqld service.
TimeoutSec=0
# Sets open_files_limit
LimitNOFILE = 10000
Restart=on-failure
RestartPreventExitStatus=1
# Always restart when mysqld exits with exit code of 16. This special exit code
# is used by mysqld for RESTART SQL.
RestartForceExitStatus=16
# Set enviroment variable MYSQLD_PARENT_PID. This is required for restart.
Environment=MYSQLD_PARENT_PID=1
There are multiple ways to specify environment variable values for use by the MySQL server process managed by systemd. To specify options for mysqld without modifying systemd configuration files directly, set or unset the MYSQLD_OPTS
systemd variable. For example:
systemctl set-environment MYSQLD_OPTS="--general_log=1"
systemctl unset-environment MYSQLD_OPTS
MYSQLD_OPTS
can also be set in the /etc/sysconfig/mysql
file.
- Start the server and secure installation.
sudo systemctl daemon-reload
sudo systemctl reset-failed
sudo systemctl start mysql
sudo systemctl status mysql
/opt/mysql/8.1.0/bin/mysql -u root -p
# Enter password from the error log
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'rootpassword';
mysql> FLUSH PRIVILEGES;
mysql> SELECT user,authentication_string,plugin,host FROM mysql.user; mysql> exit;
Install PHP from source
- Download latest package and untar.
wget https://www.php.net/distributions/php-8.2.10.tar.gz
tar -zxf php-8.2.10.tar.gz
- Install prerequisites
sudo apt install pkg-config libxml2-dev libxmlrpc-epi-dev libsqlite3-dev libcurl4-openssl-dev libjpeg-dev libpng-dev libonig-dev libxslt-dev libzip-dev
sudo apt install autoconf
- Create configuration bash script
#!/bin/bash
module load openssl/3.1.3
export OPENSSL_CFLAGS='-I/opt/openssl/3.1.3/include -L/opt/openssl/3.1.3/lib64 -lssl -lcrypto -Wl,-rpath,/opt/openssl/3.1.3/lib64'
export OPENSSL_LIBS='/opt/openssl/3.1.3/lib64'
./configure \
--prefix=/opt/php/8.2.10 \
--enable-mbstring \
--with-curl \
--with-openssl \
--enable-opcache \
--with-zip \
--enable-gd \
--with-jpeg \
--enable-fpm \
--enable-cli \
--enable-xml \
--with-xmlrpc \
--enable-intl \
--with-xsl \
--with-zlib \
--with-mysql=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-mysqli=mysqlnd
- Configure and build. Compilation takes a long time, better to use
tmux
orscreen
.
source config.sh
make
make test
sudo make install
- Setup a development environment.
cd /opt/php/8.2.10/var/run/ && sudo mkdir php-fpm
cd -
sudo cp php.ini-development /opt/php/8.2.10/lib/php.ini
sudo cp sapi/fpm/php-fpm.conf /opt/php/8.2.10/etc/php-fpm.conf
sudo cp sapi/fpm/www.conf /opt/php/8.2.10/etc/php-fpm.d/www.conf
sudo vim /opt/php/8.2.10/etc/php-fpm.d/www.conf
# edit the following:
# user = minion
# group = minion
# listen.owner = minion
# listen.group = minion
# listen = /opt/php/8.2.10/var/run/php-fpm/php-fpm.sock
sudo mkdir -p /opt/php/8.2.10/etc/conf.d
sudo vim /opt/php/8.2.10/etc/conf.d/modules.ini
# zend_extension=opcache.so
To-Do: Change it to production environment.
- Create systemd file
/lib/systemd/system/php-fpm.service
[Unit]
Description=The PHP FastCGI Process Manager
After=syslog.target network.target
[Service]
Type=simple
PIDFile=/opt/php/8.2.10/var/run/php-fpm/php-fpm.pid
ExecStart=/opt/php/8.2.10/sbin/php-fpm --nodaemonize --fpm-config /opt/php/8.2.10/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
- Start PHP. Check socket and version
sudo systemctl daemon-reload
sudo systemctl reset-failed
sudo systemctl start php-fpm
/opt/php/8.2.10/bin/php -v
ls -lh /opt/php/8.2.10/var/run/php-fpm/
- Create modulefile
/opt/modulefiles/php/8.2.10
and load module.
#%Module
proc ModulesHelp { } {
global version prefix
puts stderr "\tLoads PHP bin directory in PATH."
}
"loads PHP bin directory in PATH"
module-whatis
# for Tcl script use only
set version 8.2.10
set prefix {/opt/php/8.2.10}
$prefix/bin prepend-path PATH
- Install xmlrpc extension (required by rtorrent)
wget https://pecl.php.net/get/xmlrpc-1.0.0RC3.tgz --no-check-certificate
tar zxf xmlrpc-1.0.0RC3.tgz
cd xmlrpc-1.0.0RC3/
module load php/8.2.10
phpize
./configure
make
Move the extension to the PHP extension directory.
php -i | grep "extension_dir"
extension_dir => /opt/php/8.2.10/lib/php/extensions/no-debug-non-zts-20220829 => /opt/php/8.2.10/lib/php/extensions/no-debug-non-zts-20220829
sudo cp modules/xmlrpc.so /opt/php/8.2.10/lib/php/extensions/no-debug-non-zts-20220829/
Edit the php.ini
file to include the line:
extension=xmlrpc.so
Restart the php-fpm
service. To verify the installation, you can use something like this (should at least return the line “xmlrpc”):
php -i | grep xmlrpc | grep -v "xmlrpc_error"
- Configure the nginx server to use the php-fpm socket.