By Wael

Posted :

Install nginx , ipfw , php , ssl , mariadb , postgresql , mongodb , adminer , wordpress , java , tomcat , nodejs on FreeBSD

This article will show how to install nginx , how to enable ssl and http2 for nginx , and for the web frameworks for which nginx serves as a reverse proxy . It will use the IPFW firewall to block all incoming traffic beside http , https , and ssh .

It will install php , mariadb , Wordpress , and it will also install Postgresql , mongodb and adminer . It will also install nodejs and a wiki web application for nodejs , and it will install java and the tomcat server for which it will serve two web applications .

Before starting the installation of these software , we will install the nano editor to edit configuration files .

[root]$ pkg install nano 
# install nano on FreeBsd
install nginx ipfw php ssl mariadb postgresql mongodb adminer wordpress java tomcat nodejs on freebsd
Table of contents Configure The IPFW firewall Install and configure nginx Install and configure php Install and configure ssl Install and configure mariadb Install and configure postgresql Install and configure mongodb Install and configure adminer Install and configure wordpress Install and configure java Install and configure tomcat Install and configure nodejs and raneto wiki Other programming languages or web frameworks

1- Configure The IPFW firewall

Configure the IPFW firewall to disable all incoming traffic to the server besides : http , https and ssh .

[root]$ sysrc firewall_enable="YES"
# Make ipfw firewall starts , when 
# freebsd starts . 

[root]$ sysrc firewall_quiet="YES"
# Be quite executing commands .

[root]$ sysrc firewall_type="workstation"
# protect the machine using stateful rules .

[root]$ sysrc firewall_myservices="22/tcp 80/tcp 443/tcp"
# allow ssh http and https only 

[root]$ sysrc firewall_allowservices="any"
# any ip can access the allowed services.

[root]$ sysrc firewall_logdeny="YES"
# Log only the denied requests. 

[root]$ service ipfw start
# Load the firewall rules

2- Install and configure nginx

To install nginx , you can use :

[root]$ pkg install nginx-full 
# install nginx freebsd 

Nginx default www directory is located under /usr/local/www/nginx/ , the error logs can be found under /var/log/nginx/error.log , the access logs can be found under /var/log/nginx/access.log , the pid is found under /var/run/nginx.pid and the configuration file is found under /usr/local/etc/nginx/nginx.conf .

Make a backup of nginx.conf :

[root]$ cd /usr/local/etc/nginx
[root:/usr/local/etc/nginx/]$ mv nginx.conf nginx.conf.bk

Create a new nginx.conf file :

[root:/usr/local/etc/nginx/]$  nano nginx.conf
# paste the following content .


worker_processes auto; 

events {
    worker_connections 1024;
}

http { 
    server_tokens off;

    sendfile on; 
    tcp_nopush on; 
    tcp_nodelay on; 

    include mime.types; 
    default_type application/octet-stream;

    gzip on;    
    gzip_proxied any; 
    gzip_vary on; 
    gzip_http_version 1.1; 
    gzip_comp_level 6; 
    gzip_min_length 96; 
    gzip_types text/plain; 
    gzip_types text/css; 
    gzip_types text/xml; 
    gzip_types application/javascript; 
    gzip_types application/json;
    gzip_types font/woff; 
    gzip_types font/woff2; 
    gzip_types font/opentype; 
    gzip_types image/svg+xml; 
    gzip_types image/x-icon;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:nginx_SSL:1m;
    ssl_session_timeout 1440m;
    ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";

    map $sent_http_content_type $expires {
        default                         off;
        application/atom+xml            max;
        application/javascript          max;
        application/rss+xml             max;
        application/vnd.ms-fontobject   max;
        audio/ogg                       max;
        font/woff                       max;
        font/woff2                      max;
        font/opentype                   max;
        image/gif                       max;
        image/jpeg                      max;
        image/png                       max;
        image/svg+xml                   max;
        image/x-icon                    max;
        text/css                        max;
        text/html                       epoch;
        video/mp4                       max;
    }

    include servers.conf.d/*.conf;
}

Now create a directory in /usr/local/etc/nginx/ , named servers.conf.d :

[root:/usr/local/etc/nginx/]$ mkdir servers.conf.d

and create a configuration file for you website :

[root:/usr/local/etc/nginx/servers.conf.d/]$ nano dev-freebsd.difyel.com.conf
# create a configuration file , 
# name it as you like , the important
# is that it ends with .conf 

# paste the following content 

server {
    listen 80;
    listen [::]:80;

    server_name  dev-freebsd.difyel.com;

    root /usr/local/www/nginx/;
    
    client_max_body_size 512M;


    # blog 
    location /blog {
        expires $expires;
        index  index.php index.html index.htm;
        try_files $uri $uri/ /blog/index.php?$args;
    }

    location ~* ^/blog/.*.php$ {
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/php-74-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    # blog 
}

Test the configurations for any errors using :

[root]$ nginx -t
# output
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

Make nginx starts when freebsd starts :

[root]$ sysrc nginx_enable="YES"

Start nginx using :

[root]$ service nginx start

You can check if nginx is running , stop it , restart it , and reload its configuration using :

[root]$ service nginx status
# Check ig nginx is running . 
nginx is running as pid 7218.


[root]$ service nginx stop
# Stop nginx .
Stopping nginx.
Waiting for PIDS: 7218.


[root]$ service nginx start
# Start nginx .
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.


[root]$ service nginx restart
# restart nginx .
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Stopping nginx.
Waiting for PIDS: 7280.
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.


[root]$ service nginx reload
# reload nginx configuration 
root@freebsd:/usr/local/etc/nginx/servers.conf.d # service nginx reload
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

If you are running you website locally , make your server name resolve locally by adding the following line to /etc/hosts :

[root]$ echo '127.0.0.1 dev-freebsd.difyel.com' >> /etc/hosts
# Replace dev-freebsd.difyel.com with your servername 

3- Install and configure php

To install php on freebsd , use :

[root]$ pkg install php74 
# Install php version 7.4
# you can install other versions
# for example php73 php72 ...


[root]$ pkg search "^php74.*" | less 
# Search for extensions to use with php
# replace 74 with your installed php version
# for example , 73 72 . 


[root]$ pkg install php74-bcmath php74-bz2 php74-curl php74-dom php74-exif php74-fileinfo php74-filter php74-gd php74-gettext php74-intl php74-json php74-mbstring php74-session php74-soap php74-pecl-mcrypt php74-openssl php74-xmlrpc php74-zip php74-zlib php74-pdo_mysql php74-pdo_pgsql php74-pdo_sqlite php74-pdo_firebird php74-sqlite3 php74-pgsql php74-mysqli php74-pecl-mongodb-1.7.4 
# install extensions to be used with 
# php . 

Php configuration files are located under /usr/local/etc/php.ini and /usr/local/etc/php/ . php-fpm configuration files are located under /usr/local/etc/php-fpm.conf and /usr/local/etc/php-fpm.d/ . php-fpm pid is located under /var/run/php-fpm.pid.

To configure php on freebsd , first create a php.ini link :

# For production , create this link . 
[root]$ ln -s /usr/local/etc/php.ini-production /usr/local/etc/php.ini

# For development , create this link 
[root]$ ln -s /usr/local/etc/php.ini-development  /usr/local/etc/php.ini

Next edit /usr/local/etc/php-fpm.d/www.conf :

[root]$ nano /usr/local/etc/php-fpm.d/www.conf
# Open www.conf for editing .

# search using ctrl-w for 
listen = 127.0.0.1:9000
    
# and replace it with :
listen = /var/run/php-74-fpm.sock
# If you have installed another version
# of php , replace 74 with your version 
# for example 73 or 72 ...


# Uncomment the following three 
# lines by removing the semicolon.
listen.owner = www
listen.group = www
listen.mode = 0660

Create a secure-php.ini file :

[root]$ nano /usr/local/etc/php/secure-phi.ini
max_execution_time =  30
max_input_time = 30
cgi.force_redirect = 1
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
allow_url_fopen = Off
allow_url_include = Off
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
session.use_strict_mode = 1
session.cookie_secure = 1

Make the php-fpm service starts when FreeBSD boots , by issuing the following command :

[root]$ sysrc php_fpm_enable="YES"

Start the php-fpm service using :

[root]$ service php-fpm start

You can use service stop php-fpm to stop php-fpm .

Test if php is working correctly , create a blog directory under : /usr/local/www/

[root:/usr/local/www/]$ mkdir blog 
# create a blog directory under /usr/local/www/

and create a test.php file under /usr/local/www/nginx/blog/ :

[root:/usr/local/www/nginx/blog/]$ echo '<?php phpinfo();?>' > test.php

Visit http://yourdomain.com/blog/test.php , and you should have the following page .

php info

Remove the test.php file

[root:/usr/local/www/nginx/blog/]$ rm test.php

4- Install and configure ssl

Install certbot :

[root$] pkg install py37-certbot
# Install certbot under freebsd
# you can search for the certbot package
# using pkg search certbot .

If you are running your server locally , you must manually create and add ssl certificate using certbot .

[root]$ certbot certonly --manual --preferred-challenges dns -d dev-freebsd.difyel.com
# replace dev-freebsd.difyel.com with your server name .

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Enter email address (used for urgent renewal and security notices)
	(Enter 'c' to cancel): uremail@address.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for dev-freebsd.difyel.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.dev-freebsd.difyel.com with the following value:

qf67JA2BjjUdUsJEqjXCmTsKWHZ_KR4HZRTiNTBU33o

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

If you are using namecheap you can add the text record to your domain , by going to Domain list , then select manage under your domain , and advanced .

Namecheap domain list , manage advanced dns

Select add new record , for type select text , for host select _acme-challenge.dev-freebsd if you have a subdomain you are configuring like dev-freebsd.difyel.com , or _acme-challenge if this is your root domain like difyel.com .

You can check if the record has been updated by name cheap using the command :

#replace .dev-freebsd.difyel.com with your server name 

[root]$ host -t txt  _acme-challenge.dev-freebsd.difyel.com
Host _acme-challenge.dev-freebsd.difyel.com not found: 3(NXDOMAIN)
# In this case , the record has not been updated .


[root]$ host -t txt  _acme-challenge.dev-freebsd.difyel.com
_acme-challenge.dev-freebsd.difyel.com descriptive text "qf67JA2BjjUdUsJEqjXCmTsKWHZ_KR4HZRTiNTBU33o"
# In this case , the record has been updated . 

Once the record has been updated , press enter to continue verification .

Waiting for verification...
Cleaning up challenges
Subscribe to the EFF mailing list (email: uremail@address.com).

IMPORTANT NOTES:
	- Congratulations! Your certificate and chain have been saved at:
	/usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/fullchain.pem
	Your key file has been saved at:
	/usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/privkey.pem
	Your cert will expire on 2021-01-14. To obtain a new or tweaked
	version of this certificate in the future, simply run certbot
	again. To non-interactively renew *all* of your certificates, run
	"certbot renew"
	- Your account credentials have been saved in your Certbot
	configuration directory at /usr/local/etc/letsencrypt. You should
	make a secure backup of this folder now. This configuration
	directory will also contain certificates and private keys obtained
	by Certbot so making regular backups of this folder is ideal.
	- If you like Certbot, please consider supporting our work by:

	Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
	Donating to EFF:                    https://eff.org/donate-le

Now you must add the ssl configuration for your local domain , so replace your website configuration /usr/local/etc/nginx/servers.conf.d/dev-freebsd.difyel.com.conf with the following :

[root]$ nano /usr/local/etc/nginx/servers.conf.d/dev-freebsd.difyel.com.conf
# edit your website configuration , replace
# dev-freebsd.difyel.com.conf with your conf
# file name . and past the following code 

server {
	listen [::]:443 ssl http2 ; # Certbot
	listen 443 ssl http2 ; # Certbot
	
	ssl_certificate /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/fullchain.pem; # Certbot
	ssl_certificate_key /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/privkey.pem; # Certbot

	server_name  dev-freebsd.difyel.com;

	root /usr/local/www/nginx/;
	
	client_max_body_size 512M;


	# blog 
	location /blog {
		expires $expires;
		index  index.php index.html index.htm;
		try_files $uri $uri/ /blog/index.php?$args;
	}

	location ~* ^/blog/.*.php$ {
		include fastcgi_params;
		fastcgi_pass    unix:/var/run/php-74-fpm.sock;
		fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}
	# blog 
}

server {
	listen 80;
	listen [::]:80;
	server_name dev-freebsd.difyel.com;
	return 301 https://$host$request_uri;
}

Test the configuration and restart nginx :

[root]$ nginx -t 
[root]$ service nginx restart 

If you are not running your website locally , so like on a vps and can be accessed from the outside world , you can issue the following command in order to install ssl certificate .

[root]$ sudo certbot certonly --webroot -d difyel.com www.difyel.com
# generate and install certificate for difyel.com and 
# www.difyel.com 

[root]$ echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
# automatically renew the certificates 

For local website you must renew your certificates manually .

5- Install and configure mariadb

To install mariadb , issue the following command :

[root]$ pkg install mariadb105-server 
# Install mariadb server , you can
# install other versions by replacing
# 105 by the version number , for example
# 104 or 103

Configuration files for mariadb are found under /usr/local/etc/mysql/ .

After installation , make mariadb starts when freeBSD stars , by issuing the command :

[root]$ sysrc mysql_enable="YES"
# make mariadb starts when 
# freeBSD starts .

Start the mariadb server :

[root]$ service mysql-server start

You can stop the mariadb server by running service mysql-server stop .

Secure mariadb by running :

[root]$ mysql_secure_installation

You can choose a password for the root user , or you can use socket authentication , you can remove anonymous account , disallow root from logging remotely , remove the test database , and reload the privileges tables .

[root]$ mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
        SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we ll need the current
password for the root user. If you ve just installed MariaDB, and
haven t set the root password yet, you should just press enter here.

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] n
    ... skipping.

You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] n
    ... skipping.

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
    ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
    ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
    - Dropping test database...
    ... Success!
    - Removing privileges on test database...
    ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
    ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

Restart mariadb server using :

[root]$ service mysql-server restart

6- Install and configure postgresql

To install postgresql issue the command :

[root]$ pkg install postgresql12-server
# You can install other versions of postgresql 
# by changing the version number for example 
# 11 or 13

Make Postgresql start , when freebsd start by issuing :

[root]$ sysrc postgresql_enable="YES"

Initialize the database by running :

[root]$ service postgresql initdb

Start postgresql by running :

[root]$ service postgresql start
# start the postgresql server .

You can stop the postgresql server by running service postgresql stop

7- Install and configure mongodb

To install mongodb issue the following command :

[root]$ pkg install mongodb44
# Install mongoldb version 4.4 , 
# You can install other versions
# like 42 36 ..

Make monogdb starts when freeBSD starts by issuing the following command :

[root]$ sysrc mongod_enable="YES"

You can start and stop mongodb by using the service command . Start mongodb by issuing :

[root]$ service mongod start

8- Install and configure adminer

To install adminer issue the commands :

[root:/usr/local/www/nginx/]$ pkg install adminer
# install adminer 

[root:/usr/local/www/nginx/]$ ln -s /usr/local/www/adminer/index.php /usr/local/www/nginx/adminer.php
# create a symbolic link for 
# adminer inside nginx where 
# we are serving our website . 

Set up basic authentication on nginx , start by generating a username and a password to protect adminer.php :

[root:/usr/local/etc/nginx/]$  echo "username:`openssl passwd -apr1 password`" >> .htpasswd
# replace username by your username , and password with
# your password .

Edit nginx.conf and define a rate limiting zone , to protect from brute force attack :

[root:/usr/local/etc/nginx/]$ nano nginx.conf
# edit nginx.conf and add 

limit_req_zone $binary_remote_addr zone=shared:brute_force_protect:10m rate=1r/s;
# Create a zone named : brute_force_protect
# which will limit remote ip addresses 
# to only one http request per second . 

Your nginx.conf should look like this as such :

worker_processes auto; 

events {
	worker_connections 1024;
}

http { 
	server_tokens off;

	sendfile on; 
	tcp_nopush on; 
	tcp_nodelay on; 

	include mime.types; 
	default_type application/octet-stream;

	gzip on;    
	gzip_proxied any; 
	gzip_vary on; 
	gzip_http_version 1.1; 
	gzip_comp_level 6; 
	gzip_min_length 96; 
	gzip_types text/plain; 
	gzip_types text/css; 
	gzip_types text/xml; 
	gzip_types application/javascript; 
	gzip_types application/json;
	gzip_types font/woff; 
	gzip_types font/woff2; 
	gzip_types font/opentype; 
	gzip_types image/svg+xml; 
	gzip_types image/x-icon;

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;
	ssl_session_cache shared:nginx_SSL:1m;
	ssl_session_timeout 1440m;
	ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";

	map $sent_http_content_type $expires {
		default                         off;
		application/atom+xml            max;
		application/javascript          max;
		application/rss+xml             max;
		application/vnd.ms-fontobject   max;
		audio/ogg                       max;
		font/woff                       max;
		font/woff2                      max;
		font/opentype                   max;
		image/gif                       max;
		image/jpeg                      max;
		image/png                       max;
		image/svg+xml                   max;
		image/x-icon                    max;
		text/css                        max;
		text/html                       epoch;
		video/mp4                       max;
	}
	
	limit_req_zone $binary_remote_addr zone=brute_force_protect:10m rate=1r/s;

	include servers.conf.d/*.conf;
}

Edit your website configuration file , in my case it is dev-freebsd.difyel.com.conf , and add :

[root:/usr/local/etc/nginx/servers.conf.d/]$ nano dev-freebsd.difyel.com.conf
#adminer 
location =/adminer.php{
	limit_req zone=brute_force_protect burst=20 nodelay;
	auth_basic  "Adminer Admin Area";
	auth_basic_user_file .htpasswd;
	include fastcgi_params;
	fastcgi_pass    unix:/var/run/php-74-fpm.sock;
	fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
#adminer 

So your website configuration file will look like this :

server {
	listen [::]:443 ssl http2 ; # Certbot
	listen 443 ssl http2 ; # Certbot
	
	ssl_certificate /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/fullchain.pem; # Certbot
	ssl_certificate_key /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/privkey.pem; # Certbot

	server_name  dev-freebsd.difyel.com;

	root /usr/local/www/nginx/;
	
	client_max_body_size 512M;


	# blog 
	location /blog {
		expires $expires;
		index  index.php index.html index.htm;
		try_files $uri $uri/ /blog/index.php?$args;
	}

	location ~* ^/blog/.*.php$ {
		include fastcgi_params;
		fastcgi_pass    unix:/var/run/php-74-fpm.sock;
		fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}
	# blog 

	#adminer 
	location =/adminer.php{
		limit_req zone=brute_force_protect burst=20 nodelay;
		auth_basic  "Adminer Admin Area";
		auth_basic_user_file .htpasswd;
		include fastcgi_params;
		fastcgi_pass    unix:/var/run/php-74-fpm.sock;
		fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}
	#adminer 
}

server {
	listen 80;
	listen [::]:80;
	server_name dev-freebsd.difyel.com;
	return 301 https://$host$request_uri;
}

Test nginx configuration files using nginx -t and restart nginx using service nginx restart

Now when you try to access adminer you will be asked for a username and a password .

adminer authentication required adminer login page

To be able to connect to mariadb using adminer , create the user adminer and grant all privileges .

[root]$ mysql --user=root
# connect to mysql 

CREATE USER 'adminer'@'localhost' IDENTIFIED BY 'password';
# replace adminer and password , by your username and password .

GRANT ALL PRIVILEGES ON *.* TO 'adminer'@'localhost' WITH GRANT OPTION;
# replace adminer with your username 

FLUSH PRIVILEGES;

Now you can use adminer to connect to mysql :

adminer mysql login adminer mysql

To be able to connect to postgresql using adminer , create the user adminer .

[root]$ su - postgres
$ createuser --interactive --pwprompt
Enter name of role to add: adminer
Enter password for new role: 
Enter it again: 
Shall the new role be a superuser? (y/n) y

Now you can use adminer to connect to postgresql :

adminer postgresql login adminer postgresql

9- Install and configure wordpress

Download Wordpress to the blog directory on your website :

[root:/usr/local/www/nginx/blog/]$ wget https://wordpress.org/latest.tar.gz
# Download the latest version of 
# wordpress using wget .
# If you don't have wget installed ,
# you can install it using 
# pkg install wget 

Extract and move the extracted files to blog :

[root:/usr/local/www/nginx/blog/]$ tar -xzf latest.tar.gz
# extract Wordpress 

[root:/usr/local/www/nginx/blog/]$ mv wordpress/* .
# move the content of the wordpress
# folder to blog

[root:/usr/local/www/nginx/blog/]$ # rm -r wordpress/
# remove the Wordpress directory

[root:/usr/local/www/nginx/blog/]$ # rm latest.tar.gz
# remove the latest.tar.gz file . 

Create a database using adminer , go to your http://your.web.site/adminer.php , and make a connection to mysql , next choose create database , select a name for your database and a collation , it is recommended to set the collation to utf8mb4_general_ci if you don't find you language . Then click save .

adminer connect to mysql adminer mysql create database adminer mysql create database wordpress

On the next page click on privileges , and then click on create user , and choose a username and a password , and tick the all privileges box , then click on save .

adminer mysql privileges adminer mysql privileges create user adminer mysql privileges create user wordpress adminer mysql privileges user created

Next copy wp-config-sample.php into wp-config.php :

[root:/usr/local/www/nginx/blog/]$ cp wp-config-sample.php wp-config.php

And edit it to set up the database name , username and password as set earlier on , and to enable FS_METHOD direct , to enable the download of plugins , themes and updates without having an ftp server .

[root:/usr/local/www/nginx/blog/]$ nano wp-config.php

define( 'DB_NAME', 'wordpress_blog' );

define( 'DB_USER', 'wordpress_blog' );

define( 'DB_PASSWORD', 'password' );

define( 'DB_HOST', '127.0.0.1' );

define( 'FS_METHOD', 'direct' );
# save and exit

Change the ownership of wp-content/ to www :

[root:/usr/local/www/nginx/blog/]$ chown -R www wp-content/
# Change the ownership of wp-content to
# www 

Visit http://your.web.site/blog/wp-admin/install.php to finish installing Wordpress .

wordpress information needed

10- Install and configure java

To install java , issue the following commands :

[root]$ pkg install openjdk11
# install jdk under Freebsd 
# You can choose to install another
# version by substituting 11 , 
# for the version number you want
# to install . For example 
# openjdk8  , or openjdk13 .


root$ mount -t fdescfs fdesc /dev/fd
# mount fdesc on /dev/fd
root$ mount -t procfs proc /proc
# mount proc on /proc 

root$ echo 'fdesc   /dev/fd         fdescfs         rw      0       0' >> /etc/fstab
root$ echo 'proc    /proc           procfs          rw      0       0' >> /etc/fstab
# auto mount fdesc and proc on boot 

11- Install and configure tomcat

[root$] pkg install tomcat9
# Install tomcat under FreeBSD
# you can substitute 9 , for the version
# of tomcat you want to install , 
# for example tomcat8 . 

Tomcat will be installed to /usr/local/apache-tomcat-9.0/ . Make tomcat starts when freebsd starts by issuing the following command :

[root]$ sysrc tomcat9_enable="YES"

Edit your website configuration file , in my case it is dev-freebsd.difyel.com.conf , and add :

[root:/usr/local/etc/nginx/servers.conf.d/]$ nano dev-freebsd.difyel.com.conf 
# Edit website configuration , and add two locations ,
# for tomcat manager and host manager applications . 

    #tomcat webapps 
    location /manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/manager;
    }

    location /host-manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/host-manager;
    }
    #tomcat webapps 

Your website configuration file will look like this :

root:/usr/local/etc/nginx/servers.conf.d/]$ cat nano dev-freebsd.difyel.com.conf
# cat the content of dev-freebsd.difyel.com.conf 

server {
    listen [::]:443 ssl http2 ; # Certbot
    listen 443 ssl http2 ; # Certbot
    
    ssl_certificate /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/fullchain.pem; # Certbot
    ssl_certificate_key /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/privkey.pem; # Certbot

    server_name  dev-freebsd.difyel.com;

    root /usr/local/www/nginx/;
    
    client_max_body_size 512M;


    # blog 
    location /blog {
        expires $expires;
        index  index.php index.html index.htm;
        try_files $uri $uri/ /blog/index.php?$args;
    }

    location ~* ^/blog/.*.php$ {
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/php-74-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    # blog 

    #adminer 
    location =/adminer.php{
        limit_req zone=brute_force_protect burst=20 nodelay;
        auth_basic  "Adminer Admin Area";
        auth_basic_user_file .htpasswd;
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/php-74-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    #adminer 

    #tomcat webapps 
    location /manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/manager;
    }

    location /host-manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/host-manager;
    }
    #tomcat webapps 

}

server {
    listen 80;
    listen [::]:80;
    server_name dev-freebsd.difyel.com;
    return 301 https://$host$request_uri;
}

For each tomcat web app you would like to access using nginx , you must add a location block .

Test the nginx configuration , and restart nginx .

[root]$ nginx -t
[root]$ service nginx restart

Edit the tomcat-users.xml file , and add the line <user username ... , to enable access to the manager and host manager apps .

[root:/usr/local/apache-tomcat-9.0/conf/]$ nano tomcat-users.xml

<?xml version="1.0" encoding="UTF-8"?>

<tomcat-users xmlns="http://tomcat.apache.org/xml"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
                version="1.0">

    <user username="admin" password="password" roles="manager-gui , admin-gui"/>
</tomcat-users>

Replace username with your username , and password with your password.

Edit both context.xml in the manager and host-manager web apps and comment out the valve part to enable remote access to the manager and host manager apps .

[root:/usr/local/apache-tomcat-9.0/webapps/manager/META-INF/]$ nano context.xml
# edit manager context.xml 
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true" >
    <!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve"
            allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />-->
    <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>
[root:/usr/local/apache-tomcat-9.0/webapps/host-manager/META-INF/]$ nano context.xml
# edit host-manager context.xml 
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true" >
    <!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve"
            allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> -->
    <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>

Edit tomcat server.xmlfile and add a remote ip valve under host localhost , to enable correct passing of remote IP address and host information .

# Add a remote ip valve under 
# <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">

        <Valve
            className="org.apache.catalina.valves.RemoteIpValve"
            internalProxies="127\.0\.0\.1"
            remoteIpHeader="x-forwarded-for"
            protocolHeader="x-forwarded-proto"
            requestAttributesEnabled="true"
            />

So your server.xml file will look like this :

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

    <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
                type="org.apache.catalina.UserDatabase"
                description="User database that can be updated and saved"
                factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
                pathname="conf/tomcat-users.xml" />
    </GlobalNamingResources>


    <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
        <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                resourceName="UserDatabase"/>
        </Realm>
        <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
            <Valve
                className="org.apache.catalina.valves.RemoteIpValve"
                internalProxies="127\.0\.0\.1"
                remoteIpHeader="x-forwarded-for"
                protocolHeader="x-forwarded-proto"
                requestAttributesEnabled="true"
                />

            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                    prefix="localhost_access_log" suffix=".txt"
                    pattern="%h %l %u %t "%r" %s %b" />
        </Host>
    </Engine>
    </Service>
</Server>

You can start , stop , restart tomcat by using the service command . Start tomcat by issuing the command :

[root]$ service tomcat9 start

Go to your manager app , by visiting the address http://your.web.site/manager/

tomcat authentication required tomcat web application manager

12- Install and configure nodejs and raneto wiki

To install nodejs and npm issue the following commands :

[root]$ pkg instal node-14.13.0 npm-6.14.8
# You can substitute node version
# number by another one .

To install Raneto wiki issue the following commands :

[root]$ npm install git
# install git 

[root]$ npm install pm2 -g
# install process manager 
# to start stop and daemonize
# nodejs applications or other
# applications or scripts . 

[root]$ adduser
# create a user named node_pm2
# with home directory set to
# /usr/local/www/node_apps/
Username: node_pm2
Full name: 
Uid (Leave empty for default): 
Login group [node_pm2]: 
Login group is node_pm2. Invite node_pm2 into other groups? []: 
Login class [default]: 
Shell (sh csh tcsh bash rbash git-shell nologin) [sh]: bash
Home directory [/home/node_pm2]: /usr/local/www/node_apps/
Home directory permissions (Leave empty for default): 
Use password-based authentication? [yes]: 
Use an empty password? (yes/no) [no]: 
Use a random password? (yes/no) [no]: 
Enter password: 
Enter password again: 
Lock out the account after creation? [no]: 
Username   : node_pm2
Password   : *****
Full Name  : 
Uid        : 1002
Class      : 
Groups     : node_pm2 
Home       : /usr/local/www/node_apps/
Home Mode  : 
Shell      : /usr/local/bin/bash
Locked     : no
OK? (yes/no): y
adduser: INFO: Successfully added (node_pm2) to the user database.
Add another user? (yes/no): n
Goodbye!

[root]$ su - node_pm2
# change to user node_pm2


[node_pm2:/usr/local/www/]$ git clone https://github.com/gilbitron/Raneto.git && cd Raneto
# clone Raneto and cd into it 

[node_pm2:/usr/local/www/Raneto/]$ npm install && npm run gulp
# install the Raneto application 

[node_pm2:/usr/local/www/Raneto/]$ nano example/config.default.js  
# search for base_url: '' , and 
# replace it with : 
#  base_url: '/wiki'


[node_pm2:/usr/local/www/Raneto/]$ pm2 start npm --name "Raneto" -- start
# start the Raneto application using
# pm2 , it will be restarted if it 
# crashes .

[node_pm2:/usr/local/www/Raneto/] exit
# switch back to the root account 

[root]$ bash
# change to the bash shell .

[root]$ env PATH=$PATH:/usr/local/bin pm2 startup rcd -u node_pm2 --hp /usr/local/www/node_apps/
# execute the following command to make 
# node_pm2 starts when freebsd starts , 
# and startup any application.

[root]$ su - node_pm2
# change to user node_pm2

[node_pm2:/usr/local/www/]$ pm2 save 
# Save list of applications to 
# be started when freeBSD starts .

[node_pm2:/usr/local/www/]$ exit
# exit back to root 

Edit nginx website configuration files , to proxy the wiki application just installed by adding the #wiki raneto block :

[root:/usr/local/etc/nginx/servers.conf.d]$ nano dev-freebsd.difyel.com.conf 
# edit your website configuration 
# file and add the raneto block 

server {
    listen [::]:443 ssl http2 ; # Certbot
    listen 443 ssl http2 ; # Certbot
    
    ssl_certificate /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/fullchain.pem; # Certbot
    ssl_certificate_key /usr/local/etc/letsencrypt/live/dev-freebsd.difyel.com/privkey.pem; # Certbot

    server_name  dev-freebsd.difyel.com;

    root /usr/local/www/nginx/;
    
    client_max_body_size 512M;


    # blog 
    location /blog {
        expires $expires;
        index  index.php index.html index.htm;
        try_files $uri $uri/ /blog/index.php?$args;
    }

    location ~* ^/blog/.*.php$ {
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/php-74-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    # blog 

    #adminer 
    location =/adminer.php{
        limit_req zone=brute_force_protect burst=20 nodelay;
        auth_basic  "Adminer Admin Area";
        auth_basic_user_file .htpasswd;
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/php-74-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    #adminer 

    #tomcat webapps 
    location /manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/manager;
    }

    location /host-manager {
            limit_req zone=brute_force_protect burst=20 nodelay;
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080/host-manager;
    }
    #tomcat webapps 

    #wiki  raneto
    location /wiki {
            expires $expires;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:3000/wiki/;
    }
    #wiki raneto

}

server {
    listen 80;
    listen [::]:80;
    server_name dev-freebsd.difyel.com;
    return 301 https://$host$request_uri;
}

Test the configuration and restart nginx :

[root]$ nginx -t
# Test the configuration 

[root]$ service nginx restart
# Restart the nginx server .

Visit the wiki at the address your.website.com/wiki , and you will see the following page .

raneto wiki

13- Other programming languages or web frameworks

Can be added using the same method , by using nginx as reverse proxy .