1. Utils
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf install -y dnf-utils
sudo dnf module enable php:remi-8.3 -y
sudo dnf update -y
sudo dnf install -y unzip
2. Preparation - Create passwords to use further in the installation
yourJWTpassword
yourDBpassword
yourRISSecret
yourServerName - e.g. www.yourName.local
yourEmailSender - e.g. noreply@yourName.local
yourEmailAdmin - e.g. admin@yourName.local
yourEmailError - e.g. error@yourName.local
3. Nginx
sudo dnf install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Test
Test command:
sudo systemctl status nginx
Expected result:
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: di>
Active: active (running) since Sat 2024-04-27 07:50:21 UTC; 23s ago
Main PID: 69781 (nginx)
Tasks: 3 (limit: 22622)
Memory: 2.9M
CPU: 32ms
CGroup: /system.slice/nginx.service
├─69781 "nginx: master process /usr/sbin/nginx"
├─69782 "nginx: worker process"
└─69783 "nginx: worker process"
4. Firewall
sudo dnf install -y firewalld
sudo systemctl enable firewalld
sudo systemctl start firewalld
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo systemctl reload firewalld
5. PostgreSQL
sudo dnf module -y install postgresql:15
sudo postgresql-setup --initdb
sudo systemctl start postgresql
sudo systemctl enable postgresql
sudo vi /var/lib/pgsql/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident
sudo systemctl restart postgresql
Test
Test command:
postgres --version
Expected result:
postgres (PostgreSQL) 15.2
6. Redis
sudo dnf --enablerepo=remi install -y redis
sudo systemctl start redis
sudo systemctl enable redis
Test
Test command:
redis-server --version
Expected result:
Redis server v=6.2.7 ...
7 PHP v8.3
sudo dnf install -y php-fpm \
php-xml \
php-cli \
php-bcmath \
php-dba \
php-gd \
php-intl \
php-mbstring \
php-pgsql \
php-pdo \
php-soap \
php-pecl-apcu \
php-pecl-imagick \
php-opcache \
php-process \
php-redis
Test
Test command:
php -v
Expected result:
PHP 8.3.6 (cli) (built: Apr 10 2024 14:21:20) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.6, Copyright (c) Zend Technologies
with Zend OPcache v8.3.6, Copyright (c), by Zend Technologies
8 PHP ris.so
export DOWNLOAD_USER=
export DOWNLOAD_PASSWORD=
cd ~
sudo wget -q --http-user=$DOWNLOAD_USER --http-passwd=$DOWNLOAD_PASSWORD https://www.rillsoft.de/download/ris/centos9/php83/ris.so
sudo mv ris.so /usr/lib64/php/modules/
sudo chown root:root /usr/lib64/php/modules/ris.so
sudo chmod u=rwx,g=rx,o=rx /usr/lib64/php/modules/ris.so
sudo chcon system_u:object_r:lib_t:s0 /usr/lib64/php/modules/ris.so
echo "extension=ris.so" | sudo tee -a /etc/php.d/40-ris.ini
Test
Test command:
php -m
Expected result:
...
ris
...
9. user.ini (php.ini)
sudo vi /etc/php.d/00-user.ini
date.timezone = Europe/Berlin
engine = Off
output_buffering = 4096
realpath_cache_size = 4096k
realpath_cache_ttl = 600
expose_php = Off
max_execution_time = 900
max_input_time = 300
memory_limit = 256M
post_max_size = 30M
upload_max_filesize = 15M
max_file_uploads = 20
allow_url_fopen = on
user_agent="PHP"
mail.add_x_header = Off
cgi.fix_pathinfo = 0
log_errors_max_len = 8192
Test
Test command:
php -r "phpinfo();" | grep -i timezone
Expected result:
...
date.timezone => Europe/Berlin => Europe/Berlin
...
10. www.conf Replace content
sudo vi /etc/php-fpm.d/www.conf
[www]
user = nginx
group = nginx
listen = 9000
listen.owner = nginx
listen.group = nginx
listen.mode = 0666
pm = dynamic
pm.max_children = 20
pm.start_servers = 15
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests = 100
pm.status_path = /status
slowlog = /var/log/php-fpm/www-slow.log
php_flag[display_errors] = on
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
sudo systemctl enable php-fpm
sudo systemctl start php-fpm
11. Create DB
sudo -u postgres psql
CREATE DATABASE ris;
CREATE USER ris WITH ENCRYPTED PASSWORD 'yourDBpassword';
GRANT ALL PRIVILEGES ON DATABASE ris TO ris;
ALTER DATABASE ris OWNER TO ris;
12. RIS
export DOWNLOAD_USER=
export DOWNLOAD_PASSWORD=
cd ~
sudo rm -R -f /var/www/
sudo mkdir -p /var/www/
sudo wget -q --http-user=$DOWNLOAD_USER --http-passwd=$DOWNLOAD_PASSWORD https://www.rillsoft.de/download/ris/ris9_pgsql_on_premise.zip
sudo unzip -o ris9_pgsql_on_premise.zip -d /var/www >&-
rm -f ris9_pgsql_on_premise.zip
cd /var/www/
sudo openssl genrsa -passout pass:yourJWTpassword -out config/jwt/private.pem -aes256 4096
sudo openssl rsa -passin pass:yourJWTpassword -pubout -in config/jwt/private.pem -out config/jwt/public.pem
sudo vi /var/www/.env
###> symfony/framework-bundle ###
APP_ENV=prod
APP_SECRET=yourRISSecret
###< symfony/framework-bundle ###
###> skyfox/propel-bundle ###
DATABASE_DNS=pgsql:host=localhost;dbname=ris
DATABASE_DRIVER=pgsql
DATABASE_PASSWORD=yourDBpassword
DATABASE_USER=ris
###< skyfox/propel-bundle ###
###> lexik/jwt-authentication-bundle ###
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=yourJWTpassword
###< lexik/jwt-authentication-bundle ###
REDIS_HOST=localhost
REDIS_PORT=6379
EMAIL_SENDER=yourEmailSender
EMAIL_ADMIN=yourEmailAdmin
EMAIL_ERROR=yourEmailError
###> symfony/mailer ###
MAILER_DSN=smtp://localhost
#MAILER_DSN=smtp://user:pass@host:port/?timeout=60&encryption=ssl&auth_mode=login
#https://symfony.com/doc/5.x/mailer.html
###< symfony/mailer ###
###> symfony/amazon-mailer ###
# MAILER_DSN=ses://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
# MAILER_DSN=ses+smtp://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
###< symfony/amazon-mailer ###
###> symfony/messenger ###
MESSENGER_MAILER_TRANSPORT_DSN=redis://localhost:6379/mailer?delete_after_ack=true
###< symfony/messenger ###
## OpenLdap
LDAP_URI=ldaps://openldap
LDAP_BASE_DN=dc=rillsoft,dc=local
LDAP_LOGIN_DN=uid=%s,ou=people,dc=rillsoft,dc=local
LDAP_ATTRS=uid,givenName,sn,mail
LDAP_FILTER=(objectClass=person)
# # Micrisoft AD
# LDAP_URI=ldap://192.168.181.231
# LDAP_BASE_DN=dc=ldap,dc=jenkins,dc=local
# LDAP_LOGIN_DN=%s@ldap.jenkins.local
# LDAP_ATTRS=samAccountName,givenName,sn,mail,department,company,telephonenumber
# LDAP_FILTER=(objectClass=user)(samaccounttype=805306368)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))
In work LDAPS
? sudo echo "TLS_CACERT /etc/openldap/certs/cert.pem" >> /etc/openldap/ldap.conf
? export LDAPTLS_CACERT=/etc/ssl/certs/ca-certificates.crt.
Init
cd /var/www/
sudo php bin/console cache:clear --env=prod --no-debug
sudo php bin/console assets:install --env=prod --no-debug
sudo php bin/console propel:sql:insert --force
sudo php bin/console propel:fixtures:load --dir=data/fixtures --yml
sudo php bin/console rillsoft:update --env=prod
Update nginx conf
sudo vi /etc/nginx/conf.d/server.conf
server {
server_name yourServerName;
listen 80 default;
client_max_body_size 108M;
root /var/www/public;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/(service)\.php(/|$) {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 900;
fastcgi_send_timeout 900;
fastcgi_connect_timeout 900;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ ^/index\.php(/|$) {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 900;
fastcgi_send_timeout 900;
fastcgi_connect_timeout 900;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# optionally set the value of the environment variables used in the application
# fastcgi_param APP_ENV prod;
# fastcgi_param APP_SECRET <app-secret-id>;
# fastcgi_param DATABASE_URL "mysql://db_user:db_pass@host:3306/db_name";
# When you are using symlinks to link the document root to the
# current version of your application, you should pass the real
# application path instead of the path to the symlink to PHP
# FPM.
# Otherwise, PHP's OPcache may not properly detect changes to
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
# for more information).
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|bat|html?|git|ini|sh|svn[^.]*|txt|tpl|xml|conf|yml)|~)$ {
access_log off;
log_not_found off;
deny all;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}
Test
Test command:
sudo nginx -t
Expected result:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Permission
sudo chcon -R -t httpd_sys_content_t /var/www/
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/cache
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/log
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/blob
sudo setfacl -R -m u:nginx:rwX -m u:$(whoami):rwX /var/www/var
sudo setfacl -dR -m u:nginx:rwX -m u:$(whoami):rwX /var/www/var
sudo setsebool -P httpd_can_network_connect_db 1
sudo setsebool -P httpd_can_network_connect=1
sudo systemctl restart php-fpm
sudo systemctl restart nginx
sudo systemctl restart redis
Test
Test command:
sudo sestatus
Expected result:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
Update opcache.ini
sudo vi /etc/php.d/10-opcache.ini
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.preload_user=nginx
opcache.preload=/var/www/var/cache/prod/App_KernelProdContainer.preload.php
opcache.memory_consumption=1024
opcache.interned_strings_buffer=256
opcache.max_accelerated_files=30000
opcache.validate_timestamps=0
13. CronJobs
sudo vi /etc/cron.d/ris
*/5 * * * * root php /var/www/bin/console messenger:consume --time-limit=280 --memory-limit=512M >> /dev/null 2>&1
*/5 * * * * root php /var/www/bin/console rillsoft:notification --env=prod >> /var/www/var/log/notification.log
*/5 * * * * root php /var/www/bin/console rillsoft:timesheet:notification --env=prod >> /var/www/var/log/timesheet_notification.log
*/10 * * * * root php /var/www/bin/console rillsoft:globallink --env=prod >> /var/www/var/log/globallink.log
0 1 * * * root php /var/www/bin/console rillsoft:clear --env=prod >> /var/www/var/log/clear.log
sudo service cron restart
14. Restart
sudo systemctl restart php-fpm
sudo systemctl restart nginx
sudo systemctl restart redis
15. Diagnostic
Log
sudo less /var/log/nginx/access.log
sudo less /var/log/nginx/error.log
sudo less /var/log/php-fpm/error.log
sudo less /var/www/var/log/prod.log
Info
cd /var/www/
sudo php bin/console about
sudo php bin/console debug:container --env-vars
sudo php bin/console debug:router
SQL
sudo -u postgres psql
\c ris
\dt
SELECT * FROM rill_guard_client;
16. Update RIS
export DOWNLOAD_USER=
export DOWNLOAD_PASSWORD=
cd ~
sudo wget -q --http-user=$DOWNLOAD_USER --http-passwd=$DOWNLOAD_PASSWORD https://www.rillsoft.de/download/ris/ris9_pgsql_on_premise.zip
sudo unzip -o ris9_pgsql_on_premise.zip -d /var/www >&-
rm -f ris9_pgsql_on_premise.zip
cd /var/www/
sudo php bin/console cache:clear --env=prod --no-debug
sudo php bin/console assets:install --env=prod --no-debug
sudo php bin/console rillsoft:update --env=prod
sudo chcon -R -t httpd_sys_content_t /var/www/
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/cache
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/log
sudo chcon -R -t httpd_sys_rw_content_t /var/www/var/blob
sudo setfacl -R -m u:nginx:rwX -m u:$(whoami):rwX /var/www/var
sudo setfacl -dR -m u:nginx:rwX -m u:$(whoami):rwX /var/www/var
sudo systemctl restart php-fpm
sudo systemctl restart nginx
sudo systemctl restart redis