# Application Server

{% hint style="info" %}
The hostnames referenced throughout this documentation will be `elentra.med.university.edu` and `staging.med.university.edu`, which must be replaced by your actual DNS hostnames.
{% endhint %}

{% tabs %}
{% tab title="Enterprise Linux 8" %}
This documentation can be used as a reference to create both your **Production Application Server** and/or **Staging Application Server** on a **Enterprise Linux 8** virtual machine.

1. SSH into server and `sudo` to root:

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   ```
2. Change the SELINUX variable in `/etc/selinux/config` to permissive to prevent unforeseen and difficult to diagnose issues:

   ```
   SELINUX=permissive
   ```
3. Add the following lines to `/etc/hosts` file:

   ```
   127.0.0.1   elentra.med.university.edu
   127.0.0.1   staging.med.university.edu
   ```
4. Edit the hostname of the virtual machine in the `/etc/hostname` file:

   ```
   elentra.med.university.edu
   ```
5. Install `screen`, update RHEL, and reboot:

   ```bash
   dnf install screen
   screen
   dnf update
   reboot
   ```
6. SSH back into server, and install the Inline with Upstream Stable (IUS Community) package.

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   screen

   dnf -y install http://rpms.remirepo.net/enterprise/remi-release-8.rpm \
   https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
   ```
7. Install Snapd and htmldoc:

   ```bash
   dnf -y install snapd
   systemctl enable --now snapd.socket
   ln -s /var/lib/snapd/snap /snap
   snap install htmldoc
   ```

   Note: You may have to wait a couple of minutes before running the snap install command, so that the snap database can initialize.
8. Install Apache, OpenSSL, PHP, Git, HTMLDoc, mariadb (client), ClamAV, and NTP packages:

   ```bash
   dnf module install php:remi-8.1 -y
   dnf -y install git \
                  curl \
                  wget \
                  unzip \
                  openssl \
                  httpd \
                  mod_ssl \
                  php-cli \
                  php-gd \
                  php-devel \
                  php-pdo \
                  php-mysqlnd \
                  php-intl \
                  php-mbstring \
                  php-bcmath \
                  php-ldap \
                  php-imap \
                  php-soap \
                  php-xml \
                  php-xmlrpc \
                  php-tidy \
                  php-opcache \
                  php-json \
                  php-sodium \
                  php-pecl-redis \
                  php-pecl-zip \
                  mariadb \
                  clamav \
                  chrony \
                  supervisor
   ```
9. Install `wkhtmltopdf` from the binary package because the yum package provided by EPEL is broken:

   ```
   curl -SL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz | tar -xJC /root && cp /root/wkhtmltox/bin/* /usr/bin
   dnf install xorg-x11-fonts-Type1
   dnf install xorg-x11-fonts-75dpi
   wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox-0.12.6.1-2.almalinux8.x86_64.rpm
   rpm -Uvh wkhtmltox-0.12.6.1-2.almalinux8.x86_64.rpm
   ```
10. Start Apache and Supervisor, and set to start on system startup:

    ```
    systemctl enable httpd
    systemctl start httpd
    systemctl enable supervisord
    systemctl start supervisord
    ```
11. Create a new file called `/etc/php.d/elentra.ini` and add the following:

    ```
    date.timezone = America/Toronto
    display_errors = Off
    error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT
    expose_php = Off
    memory_limit = 512M
    post_max_size = 512M
    session.cookie_secure = 1
    session.cookie_httponly = 1
    session.cookie_samesite = Strict
    upload_max_filesize = 512M
    ```
12. Create an Elentra system user called `production`, which is used for production deployments:

    ```
    useradd -m production
    passwd production
    usermod -G apache -a production
    usermod -G production -a apache
    ```
13. Create and permission the SSH `authorized_keys` file for the `production` user.

    ```
    cd /home/production
    mkdir /home/production/.ssh
    touch /home/production/.ssh/authorized_keys
    chown -R production:production /home/production/.ssh
    chmod 700 /home/production/.ssh
    chmod 600 /home/production/.ssh/authorized_keys
    ```
14. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your production environment to the new `authorized_keys` file.

    ```
    vim /home/production/.ssh/authorized_keys
    ```
15. Create an Elentra system user called `staging`, which is used for staging deployments:

    ```
    useradd -m staging
    passwd staging
    usermod -G apache -a staging
    usermod -G staging -a apache
    ```
16. Create and permission the SSH `authorized_keys` file for the `staging` user.

    ```
    cd /home/staging
    mkdir /home/staging/.ssh
    touch /home/staging/.ssh/authorized_keys
    chown -R staging:staging /home/staging/.ssh
    chmod 700 /home/staging/.ssh
    chmod 600 /home/staging/.ssh/authorized_keys
    ```
17. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your staging environment to the new `authorized_keys` file.

    ```
    vim /home/staging/.ssh/authorized_keys
    ```
18. Create and appropriately permission the Apache document root and Elentra storage directories for production.

    ```
    mkdir -p /var/www/vhosts/elentra.med.university.edu/storage/
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/cbe-uploads
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/cbe-uploads/learner-self-assessment-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/logs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/lor
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/tmp
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/user-photos
    chown -R production:production /var/www/vhosts/elentra.med.university.edu
    chmod -R 777 /var/www/vhosts/elentra.med.university.edu/storage/*
    ```
19. Create and appropriately permission the Apache document root and Elentra storage directories for staging.

    ```
    mkdir -p /var/www/vhosts/staging.med.university.edu/storage/
    mkdir /var/www/vhosts/staging.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/cbe-uploads
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/cbe-uploads/learner-self-assessment-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/staging.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/staging.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/staging.med.university.edu/storage/logs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/lor
    mkdir /var/www/vhosts/staging.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/staging.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/staging.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/staging.med.university.edu/storage/tmp
    mkdir /var/www/vhosts/staging.med.university.edu/storage/user-photos
    chown -R staging:staging /var/www/vhosts/staging.med.university.edu
    chmod -R 777 /var/www/vhosts/staging.med.university.edu/storage/*
    ```
20. Generate the SSL private keys required for each of your hostnames:

    ```
    mkdir -p /root/certificates/2023
    cd /root/certificates/2023
    openssl genrsa -out elentra.med.university.edu.key 2048
    openssl genrsa -out staging.med.university.edu.key 2048
    ```
21. Generate the SSL certificate signing requests (CSRs) for your certificate authority for each of your hostnames.

    ```
    openssl req -new -key elentra.med.university.edu.key -out elentra.med.university.edu.csr
    openssl req -new -key staging.med.university.edu.key -out staging.med.university.edu.csr
    ```

    * You will be asked a number of questions, answer accordingly, but **do not answer** enter anything for "Email Address", "A challenge password", or "An optional company name:

      ```
      You are about to be asked to enter information that will be incorporated
      into your certificate request.
      What you are about to enter is what is called a Distinguished Name or a DN.
      There are quite a few fields but you can leave some blank
      For some fields there will be a default value,
      If you enter '.', the field will be left blank.
      -----
      Country Name (2 letter code) [XX]:CA
      State or Province Name (full name) []:Ontario
      Locality Name (eg, city) [Default City]:Kingston
      Organization Name (eg, company) [Default Company Ltd]:Queen's University
      Organizational Unit Name (eg, section) []:Health Sciences Education Technology Unit
      Common Name (eg, your name or your server's hostname) []:elentra.med.university.edu
      Email Address []:
      Please enter the following 'extra' attributes
      to be sent with your certificate request
      A challenge password []:
      An optional company name []:
      ```
22. If you have a valid Certificate Authority certificate, you should create a .crt file foreach hostname and paste in the certificate text:

    ```
    vim /root/certificates/2023/elentra.med.university.edu.crt
    vim /root/certificates/2023/staging.med.university.edu.crt
    ```

    * You will also likely have a certificate authority root chain certificate. Also paste this into a file called `ca-certificate.crt`
23. If you are only creating self-signed certificates, you should do this for each hostname:

    ```
    openssl x509 -req -days 365 -in elentra.med.university.edu.csr -signkey elentra.med.university.edu.key -out elentra.med.university.edu.crt
    openssl x509 -req -days 365 -in staging.med.university.edu.csr -signkey staging.med.university.edu.key -out staging.med.university.edu.crt
    ```
24. Install the certificates in the Apache virtual host directory:

    ```
    mkdir /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.crt /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.key /var/www/vhosts/elentra.med.university.edu/cert/
    mkdir /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.crt /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.key /var/www/vhosts/staging.med.university.edu/cert/
    ```
25. Create the Apache VirtualHosts by creating a file named `000-elentra.conf` and placing it `/etc/httpd/conf.d/`.
    * For configurations where the web server is directly accessible from the internet, the file should contain the following:

      ```
      # This will limit what information Apache reveals about itself.
      ServerTokens Prod
      ServerSignature Off
      TraceEnable Off

      SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

      # Apache performance tuning options for more connections.
      #<IfModule mpm_prefork_module>
      #    MaxRequestWorkers 512
      #    ServerLimit 512
      #</IfModule>

      # Production
      <VirtualHost *:80>
          ServerName elentra.med.university.edu
          ServerAdmin sysadmin@med.university.edu

          RewriteEngine On
          RewriteCond %{HTTPS} off
          RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
      </VirtualHost>
      <VirtualHost *:443>
          ServerName elentra.med.university.edu:443
          ServerAdmin sysadmin@med.university.edu

          SSLEngine on
          SSLProtocol -all +TLSv1.2
          SSLHonorCipherOrder on
          SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

          SSLCertificateFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.crt
          SSLCertificateKeyFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.key
          #SSLCACertificateFile /var/www/vhosts/elentra.med.university.edu/cert/ca-certificate.crt

          SSLUseStapling on

          Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
          Header always set X-Frame-Options SAMEORIGIN

          DocumentRoot /var/www/vhosts/elentra.med.university.edu/current/www-root
          <Directory "/var/www/vhosts/elentra.med.university.edu/current/www-root">
              Options FollowSymLinks
              Require all granted
              AllowOverride all
          </Directory>
      	ProxyPass "/app/" "ws://localhost:6000/app/"
          ProxyPassReverse "/app/" "ws://localhost:6000/app/"
          ProxyPass "/apps/" "http://localhost:6000/apps/"
          ProxyPassReverse "/apps/" "http://localhost:6000/apps/"
      </VirtualHost>

      # Staging
      <VirtualHost *:80>
          ServerName staging.med.university.edu
          ServerAdmin sysadmin@med.university.edu

          RewriteEngine On
          RewriteCond %{HTTPS} off
          RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
      </VirtualHost>
      <VirtualHost *:443>
          ServerName staging.med.university.edu:443
          ServerAdmin sysadmin@med.university.edu

          SSLEngine on
          SSLProtocol -all +TLSv1.2
          SSLHonorCipherOrder on
          SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

          SSLCertificateFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.crt
          SSLCertificateKeyFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.key
          #SSLCACertificateFile /var/www/vhosts/staging.med.university.edu/cert/ca-certificate.crt

          SSLUseStapling on

          Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
          Header always set X-Frame-Options SAMEORIGIN

          DocumentRoot /var/www/vhosts/staging.med.university.edu/current/www-root
          <Directory "/var/www/vhosts/staging.med.university.edu/current/www-root">
              Options FollowSymLinks
              Require all granted
              AllowOverride all
          </Directory>
      	ProxyPass "/app/" "ws://localhost:6000/app/"
          ProxyPassReverse "/app/" "ws://localhost:6000/app/"
          ProxyPass "/apps/" "http://localhost:6000/apps/"
          ProxyPassReverse "/apps/" "http://localhost:6000/apps/"
      </VirtualHost>
      ```
    * For configurations where a load balancer sits in front of the web server and the load balancer communicates with the web server over http, the file should look like this:

      ```
      # This will limit what information Apache reveals about itself.
      ServerTokens Prod
      ServerSignature Off
      TraceEnable Off

      SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

      # Apache performance tuning options for more connections.
      #<IfModule mpm_prefork_module>
      #    MaxRequestWorkers 512
      #    ServerLimit 512
      #</IfModule>

      # Production
      <VirtualHost *:80>
          ServerName elentra.med.university.edu
          ServerAdmin sysadmin@med.university.edu

          DocumentRoot /var/www/vhosts/elentra.med.university.edu/current/www-root
          <Directory "/var/www/vhosts/elentra.med.university.edu/current/www-root">
              Options FollowSymLinks
              Require all granted
              AllowOverride all
          </Directory>

          ProxyPass "/app/" "ws://localhost:6000/app/"
          ProxyPassReverse "/app/" "ws://localhost:6000/app/"
          ProxyPass "/apps/" "http://localhost:6000/apps/"
          ProxyPassReverse "/apps/" "http://localhost:6000/apps/"
      </VirtualHost>

      # Staging
      <VirtualHost *:80>
          ServerName staging.med.university.edu
          ServerAdmin sysadmin@med.university.edu

          DocumentRoot /var/www/vhosts/staging.med.university.edu/current/www-root
          <Directory "/var/www/vhosts/staging.med.university.edu/current/www-root">
              Options FollowSymLinks
              Require all granted
              AllowOverride all
          </Directory>

          ProxyPass "/app/" "ws://localhost:6000/app/"
          ProxyPassReverse "/app/" "ws://localhost:6000/app/"
          ProxyPass "/apps/" "http://localhost:6000/apps/"
          ProxyPassReverse "/apps/" "http://localhost:6000/apps/"
      </VirtualHost>
      ```
26. Do a deployment to the new server.
27. Point the `app.json` in the storage folder to the corresponding file in the code

    ```
    ln -s /var/www/vhosts/host.name.edu/current/www-root/core/storage/app/modules/app.json /var/www/vhosts/host.name.edu/storage/app/modules/app.json
    ```
28. Create a new file in the `/etc/supervisord.d` directory called `elentra.ini`, and use the following template snippet as a reference to create your own file.\
    \
    Please make sure that you have the correct path in **`command`** and **`stdout_logfile`**, and that **`user`** is the correct system account that your existing cron jobs are run as.\\

    ```
    [program:elentra-queue-staging]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/staging.elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=staging
    autostart=true
    autorestart=true
    user=staging
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/staging.elentra.med.university.edu/storage/logs/worker.log

    [program:elentra-queue-production]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=production
    autostart=true
    autorestart=true
    user=production
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/elentra.med.university.edu/storage/logs/worker.log

    [program:elentra-websocket-staging]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/staging.elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan websockets:serve --port=6000 --env=staging
    autostart=true
    autorestart=true
    user=staging
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/staging.elentra.med.university.edu/storage/logs/websocket.log

    [program:elentra-websocket-production]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan websockets:serve --port=6000 --env=production
    autostart=true
    autorestart=true
    user=production
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/elentra.med.university.edu/storage/logs/websocket.log

    [group:elentra]
    programs=elentra-queue-staging,elentra-queue-production,elentra-websocket-staging,elentra-websocket-production
    ```
29. Test your new Apache configuration, then restart Apache and Supervisor.

    ```
    apachectl configtest
    systemctl restart httpd
    systemctl restart supervisord
    ```

{% endtab %}

{% tab title="Enterprise Linux 7" %}
This documentation can be used as a reference to create both your **Production Application Server** and/or **Staging Application Server** on a **Enterprise Linux 7** virtual machine.

1. SSH into server and `sudo` to root:

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   ```
2. Change the SELINUX variable in `/etc/selinux/config` to permissive to prevent unforeseen and difficult to diagnose issues:

   ```
   SELINUX=permissive
   ```
3. Add the following lines to `/etc/hosts` file:

   ```
   127.0.0.1   elentra.med.university.edu
   127.0.0.1   staging.med.university.edu
   ```
4. Edit the hostname of the virtual machine in the `/etc/hostname` file:

   ```
   elentra.med.university.edu
   ```
5. Install `screen`, update RHEL, and reboot:

   ```bash
   yum install screen
   screen
   yum update
   reboot
   ```
6. SSH back into server, and install the Inline with Upstream Stable (IUS Community) package.

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   screen

   yum -y install https://repo.ius.io/ius-release-el7.rpm \
   https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
   ```
7. Install Apache, OpenSSL, PHP, Git, HTMLDoc, mariadb (client), ClamAV, and NTP packages:

   ```bash
   yum -y install git \
               htmldoc \
               curl \
               wget \
               unzip \
               openssl \
               httpd \
               mod_ssl \
               mod_php74 \
               php74-cli \
               php74-gd \
               php74-devel \
               php74-pdo \
               php74-mysqlnd \
               php74-intl \
               php74-mbstring \
               php74-bcmath \
               php74-ldap \
               php74-imap \
               php74-soap \
               php74-xml \
               php74-xmlrpc \
               php74-tidy \
               php74-opcache \
               php74-json \
               php74-sodium \
               php74-pecl-redis \
               php74-pecl-zip \
               mariadb104 \
               clamav \
               ntp \
               supervisor
   ```
8. Install `wkhtmltopdf` from the binary package because the yum package provided by EPEL is broken:\
   `curl -SL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz | tar -xJC /root && cp /root/wkhtmltox/bin/* /usr/bin`
9. Start Apache and Supervisor, and set to start on system startup:

   ```
   systemctl enable httpd
   systemctl start httpd
   systemctl enable supervisord
   systemctl start supervisord
   ```
10. Create a new file called `/etc/php.d/elentra.ini` and add the following:

    ```
    date.timezone = America/Toronto
    display_errors = Off
    error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT
    expose_php = Off
    memory_limit = 512M
    post_max_size = 512M
    session.cookie_secure = 1
    session.cookie_httponly = 1
    session.cookie_samesite = Strict
    upload_max_filesize = 512M
    ```
11. Create an Elentra system user called `production`, which is used for production deployments:

    ```
    useradd -m production
    passwd production
    ```
12. Create and permission the SSH `authorized_keys` file for the `production` user.

    ```
    cd /home/production
    mkdir /home/production/.ssh
    touch /home/production/.ssh/authorized_keys
    chown -R production:production /home/production/.ssh
    chmod 700 /home/production/.ssh
    chmod 600 /home/production/.ssh/authorized_keys
    ```
13. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your production environment to the new `authorized_keys` file.

    ```
    vim /home/production/.ssh/authorized_keys
    ```
14. Create an Elentra system user called `staging`, which is used for staging deployments:

    ```
    useradd -m staging
    passwd staging
    ```
15. Create and permission the SSH `authorized_keys` file for the `staging` user.

    ```
    cd /home/staging
    mkdir /home/staging/.ssh
    touch /home/staging/.ssh/authorized_keys
    chown -R staging:staging /home/staging/.ssh
    chmod 700 /home/staging/.ssh
    chmod 600 /home/staging/.ssh/authorized_keys
    ```
16. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your staging environment to the new `authorized_keys` file.

    ```
    vim /home/staging/.ssh/authorized_keys
    ```
17. Create and appropriately permission the Apache document root and Elentra storage directories for production.

    ```
    mkdir -p /var/www/vhosts/elentra.med.university.edu/storage/
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/cbe-uploads
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/cbe-uploads/learner-self-assessment-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/logs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/lor
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/user-photos
    chown -R production:production /var/www/vhosts/elentra.med.university.edu
    chmod -R 777 /var/www/vhosts/elentra.med.university.edu/storage/*
    ```
18. Create and appropriately permission the Apache document root and Elentra storage directories for staging.

    ```
    mkdir -p /var/www/vhosts/staging.med.university.edu/storage/
    mkdir /var/www/vhosts/staging.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/cbe-uploads
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/cbe-uploads/learner-self-assessment-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/staging.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/staging.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/staging.med.university.edu/storage/logs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/lor
    mkdir /var/www/vhosts/staging.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/staging.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/staging.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/staging.med.university.edu/storage/user-photos
    chown -R staging:staging /var/www/vhosts/staging.med.university.edu
    chmod -R 777 /var/www/vhosts/staging.med.university.edu/storage/*
    ```
19. Point the app.json in the storage folder to the corresponding file in the code

    ```
    ln -s /var/www/vhosts/host.name.edu/current/www-root/core/storage/app/modules/app.json /var/www/vhosts/host.name.edu/storage/app/modules/app.json
    ```
20. Generate the SSL private keys required for each of your hostnames:

    ```
    mkdir -p /root/certificates/2023
    cd /root/certificates/2023
    openssl genrsa -out elentra.med.university.edu.key 2048
    openssl genrsa -out staging.med.university.edu.key 2048
    ```
21. Generate the SSL certificate signing requests (CSRs) for your certificate authority for each of your hostnames:

    ```
    openssl req -new -key elentra.med.university.edu.key -out elentra.med.university.edu.csr
    openssl req -new -key staging.med.university.edu.key -out staging.med.university.edu.csr
    ```

    You will be asked a number of questions, answer accordingly, but **do not** answer enter anything for "Email Address", "A challenge password", or "An optional company name":

    ```
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:CA
    State or Province Name (full name) []:Ontario
    Locality Name (eg, city) [Default City]:Kingston
    Organization Name (eg, company) [Default Company Ltd]:Queen's University
    Organizational Unit Name (eg, section) []:Health Sciences Education Technology Unit
    Common Name (eg, your name or your server's hostname) []:elentra.med.university.edu
    Email Address []:
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    ```
22. If you have a valid Certificate Authority certificate, you should create a .crt file foreach hostname and paste in the certificate text:

    ```
    vim /root/certificates/2023/elentra.med.university.edu.crt
    vim /root/certificates/2023/staging.med.university.edu.crt
    ```

    You will also likely have a certificate authority root chain certificate. Also paste this into a file called `ca-certificate.crt`.\\
23. If you are only creating self-signed certificates, you should do this for each hostname:

    ```
    openssl x509 -req -days 365 -in elentra.med.university.edu.csr -signkey elentra.med.university.edu.key -out elentra.med.university.edu.crt
    openssl x509 -req -days 365 -in staging.med.university.edu.csr -signkey staging.med.university.edu.key -out staging.med.university.edu.crt
    ```
24. Install the certificates in the Apache virtual host directory:

    ```
    mkdir /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.crt /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.key /var/www/vhosts/elentra.med.university.edu/cert/
    mkdir /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.crt /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.key /var/www/vhosts/staging.med.university.edu/cert/
    ```
25. Create the Apache VirtualHosts by creating a file named `000-elentra.conf` and placing it `/etc/httpd/conf.d/`.\
    \
    This file should contain the following:

    ```
    # This will limit what information Apache reveals about itself.
    ServerTokens Prod
    ServerSignature Off
    TraceEnable Off

    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

    # Apache performance tuning options for more connections.
    #<IfModule mpm_prefork_module>
    #    MaxRequestWorkers 512
    #    ServerLimit 512
    #</IfModule>

    # Production
    <VirtualHost *:80>
        ServerName elentra.med.university.edu
        ServerAdmin sysadmin@med.university.edu

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
    </VirtualHost>
    <VirtualHost *:443>
        ServerName elentra.med.university.edu:443
        ServerAdmin sysadmin@med.university.edu

        SSLEngine on
        SSLProtocol -all +TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

        SSLCertificateFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.crt
        SSLCertificateKeyFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.key
        #SSLCACertificateFile /var/www/vhosts/elentra.med.university.edu/cert/ca-certificate.crt

        SSLUseStapling on

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
        Header always set X-Frame-Options SAMEORIGIN

        DocumentRoot /var/www/vhosts/elentra.med.university.edu/current/www-root
        <Directory "/var/www/vhosts/elentra.med.university.edu/current/www-root">
            Options FollowSymLinks
            Require all granted
            AllowOverride all
        </Directory>
    </VirtualHost>

    # Staging
    <VirtualHost *:80>
        ServerName staging.med.university.edu
        ServerAdmin sysadmin@med.university.edu

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
    </VirtualHost>
    <VirtualHost *:443>
        ServerName staging.med.university.edu:443
        ServerAdmin sysadmin@med.university.edu

        SSLEngine on
        SSLProtocol -all +TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

        SSLCertificateFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.crt
        SSLCertificateKeyFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.key
        #SSLCACertificateFile /var/www/vhosts/staging.med.university.edu/cert/ca-certificate.crt

        SSLUseStapling on

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
        Header always set X-Frame-Options SAMEORIGIN

        DocumentRoot /var/www/vhosts/staging.med.university.edu/current/www-root
        <Directory "/var/www/vhosts/staging.med.university.edu/current/www-root">
            Options FollowSymLinks
            Require all granted
            AllowOverride all
        </Directory>
    </VirtualHost>
    ```
26. Create a new file in the `/etc/supervisord.d` directory called `elentra.ini`, and use the following template snippet as a reference to create your own file.\\

    Please make sure that you have the correct path in **`command`** and **`stdout_logfile`**, and that **`user`** is the correct system account that your existing cron jobs are run as.

    ```
    [program:staging]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/staging.elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=staging
    autostart=true
    autorestart=true
    user=staging
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/staging.elentra.med.university.edu/storage/logs/worker.log

    [program:production]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=production
    autostart=true
    autorestart=true
    user=production
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/elentra.med.university.edu/storage/logs/worker.log

    [group:elentra]
    programs=staging,production
    ```
27. Test your new Apache configuration, then restart Apache and Supervisor.

    ```
    apachectl configtest
    systemctl restart httpd
    systemctl restart supervisord
    ```

{% endtab %}

{% tab title="Ubuntu 22.04" %}
This documentation can be used as a reference to create both your **Production Application Server** and/or **Staging Application Server** on a **Ubuntu 22.04** virtual machine.

1. SSH into server and `sudo` to root:

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   ```
2. Add the following lines to `/etc/hosts` file:

   ```
   127.0.0.1   elentra.med.university.edu
   127.0.0.1   staging.med.university.edu
   ```
3. Edit the hostname of the virtual machine in the `/etc/hostname` file:

   ```
   elentra.med.university.edu
   ```
4. Install `screen`, update RHEL, and reboot:

   ```bash
   apt install screen
   screen
   apt update
   apt upgrade
   reboot
   ```
5. SSH back into server, and install the Ondrej PHP repository.

   ```bash
   ssh service@elentra.med.university.edu
   sudo -s
   screen

   add-apt-repository ppa:ondrej/php
   ```
6. Install Apache, OpenSSL, Git, HTMLDoc, mariadb (client), ClamAV, and NTP packages:

   <pre class="language-bash"><code class="lang-bash"><strong>apt install -y git \
   </strong>            htmldoc \
               curl \
               wget \
               unzip \
               openssl \
               apache2 \
               mariadb-client \
               clamav \
               ntp \
               supervisor
   </code></pre>
7. Install either PHP 8.0 or 7.4:\\

   **PHP 8.0 (Elentra 1.24+)**

   ```bash
   apt install -y libapache2-mod-php8.0 \
               php8.0-cli \
               php8.0-gd \
               php8.0-dev \
               php8.0-mysql \
               php8.0-curl \
               php8.0-intl \
               php8.0-mbstring \
               php8.0-bcmath \
               php8.0-ldap \
               php8.0-imap \
               php8.0-redis \
               php8.0-soap \
               php8.0-xml \
               php8.0-xmlrpc \
               php8.0-tidy \
               php8.0-opcache \
               php8.0-zip
   ```

   \
   **PHP 7.4**

   ```bash
   apt install -y libapache2-mod-php7.4 \
               php7.4-cli \
               php7.4-gd \
               php7.4-dev \
               php7.4-mysql \
               php7.4-curl \
               php7.4-intl \
               php7.4-mbstring \
               php7.4-bcmath \
               php7.4-ldap \
               php7.4-imap \
               php7.4-redis \
               php7.4-soap \
               php7.4-xml \
               php7.4-xmlrpc \
               php7.4-tidy \
               php7.4-opcache \
               php7.4-json \
               php7.4-zip
   ```
8. Install `wkhtmltopdf` from the binary package, as the apt package installs way too many dependencies:\
   `curl -SL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz | tar -xJC /root && cp /root/wkhtmltox/bin/* /usr/bin`
9. Start Apache and Supervisor, and set to start on system startup:

   ```bash
   a2enmod ssl rewrite headers proxy proxy_http proxy_balancer expires

   systemctl enable apache2
   systemctl start apache2
   systemctl enable supervisor
   systemctl start supervisor
   ```
10. Create a new file called `/etc/php/8.0/mods-available/elentra.ini` and add the following:

    ```
    date.timezone = America/Toronto
    display_errors = Off
    error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT
    expose_php = Off
    memory_limit = 512M
    post_max_size = 512M
    session.cookie_secure = 1
    session.cookie_httponly = 1
    session.cookie_samesite = Strict
    upload_max_filesize = 512M
    ```
11. Enable this new module by typing:

    ```bash
    phpenmod elentra
    ```
12. Create an Elentra system user called `production`, which is used for production deployments:

    ```
    useradd -m production
    passwd production
    ```
13. Create and permission the SSH `authorized_keys` file for the `production` user.

    ```
    cd /home/production
    mkdir /home/production/.ssh
    touch /home/production/.ssh/authorized_keys
    chown -R production:production /home/production/.ssh
    chmod 700 /home/production/.ssh
    chmod 600 /home/production/.ssh/authorized_keys
    ```
14. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your production environment to the new `authorized_keys` file.

    ```
    vim /home/production/.ssh/authorized_keys
    ```
15. Create an Elentra system user called `staging`, which is used for staging deployments:

    ```
    useradd -m staging
    passwd staging
    ```
16. Create and permission the SSH `authorized_keys` file for the `staging` user.

    ```
    cd /home/staging
    mkdir /home/staging/.ssh
    touch /home/staging/.ssh/authorized_keys
    chown -R staging:staging /home/staging/.ssh
    chmod 700 /home/staging/.ssh
    chmod 600 /home/staging/.ssh/authorized_keys
    ```
17. Add all developers' SSH public keys (i.e. `cat ~/.ssh/id_rsa.pub`) that are allowed to deploy Elentra to your staging environment to the new `authorized_keys` file.

    ```
    vim /home/staging/.ssh/authorized_keys
    ```
18. Create and appropriately permission the Apache document root and Elentra storage directories for production.

    ```
    mkdir -p /var/www/vhosts/elentra.med.university.edu/storage/
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/logs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/lor
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/elentra.med.university.edu/storage/user-photos
    chown -R production:production /var/www/vhosts/elentra.med.university.edu
    chmod -R 777 /var/www/vhosts/elentra.med.university.edu/storage/*
    ```
19. Create and appropriately permission the Apache document root and Elentra storage directories for staging.

    ```
    mkdir -p /var/www/vhosts/staging.med.university.edu/storage/
    mkdir /var/www/vhosts/staging.med.university.edu/storage/annualreports
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app
    mkdir /var/www/vhosts/staging.med.university.edu/storage/app/public
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads
    mkdir /var/www/vhosts/staging.med.university.edu/storage/cbme-uploads/advisor-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-discussions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-galleries
    mkdir /var/www/vhosts/staging.med.university.edu/storage/community-shares
    mkdir /var/www/vhosts/staging.med.university.edu/storage/eportfolio
    mkdir /var/www/vhosts/staging.med.university.edu/storage/event-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/exam-files
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/cache/data
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/sessions
    mkdir /var/www/vhosts/staging.med.university.edu/storage/framework/views
    mkdir /var/www/vhosts/staging.med.university.edu/storage/logs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/lor
    mkdir /var/www/vhosts/staging.med.university.edu/storage/msprs
    mkdir /var/www/vhosts/staging.med.university.edu/storage/resource-images
    mkdir /var/www/vhosts/staging.med.university.edu/storage/secure-access
    mkdir /var/www/vhosts/staging.med.university.edu/storage/syllabi
    mkdir /var/www/vhosts/staging.med.university.edu/storage/user-photos
    chown -R staging:staging /var/www/vhosts/staging.med.university.edu
    chmod -R 777 /var/www/vhosts/staging.med.university.edu/storage/*
    ```
20. Generate the SSL private keys required for each of your hostnames:

    ```
    mkdir -p /root/certificates/2023
    cd /root/certificates/2023
    openssl genrsa -out elentra.med.university.edu.key 2048
    openssl genrsa -out staging.med.university.edu.key 2048
    ```
21. Generate the SSL certificate signing requests (CSRs) for your certificate authority for each of your hostnames:

    ```
    openssl req -new -key elentra.med.university.edu.key -out elentra.med.university.edu.csr
    openssl req -new -key staging.med.university.edu.key -out staging.med.university.edu.csr
    ```

    You will be asked a number of questions, answer accordingly, but **do not** answer enter anything for "Email Address", "A challenge password", or "An optional company name":

    ```
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:CA
    State or Province Name (full name) []:Ontario
    Locality Name (eg, city) [Default City]:Kingston
    Organization Name (eg, company) [Default Company Ltd]:Queen's University
    Organizational Unit Name (eg, section) []:Health Sciences Education Technology Unit
    Common Name (eg, your name or your server's hostname) []:elentra.med.university.edu
    Email Address []:
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    ```
22. If you have a valid Certificate Authority certificate, you should create a .crt file foreach hostname and paste in the certificate text:

    ```
    vim /root/certificates/2023/elentra.med.university.edu.crt
    vim /root/certificates/2023/staging.med.university.edu.crt
    ```

    You will also likely have a certificate authority root chain certificate. Also paste this into a file called `ca-certificate.crt`.\\
23. If you are only creating self-signed certificates, you should do this for each hostname:

    ```
    openssl x509 -req -days 365 -in elentra.med.university.edu.csr -signkey elentra.med.university.edu.key -out elentra.med.university.edu.crt
    openssl x509 -req -days 365 -in staging.med.university.edu.csr -signkey staging.med.university.edu.key -out staging.med.university.edu.crt
    ```
24. Install the certificates in the Apache virtual host directory:

    ```
    mkdir /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.crt /var/www/vhosts/elentra.med.university.edu/cert/
    cp /root/certificates/2023/elentra.med.university.edu.key /var/www/vhosts/elentra.med.university.edu/cert/
    mkdir /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.crt /var/www/vhosts/staging.med.university.edu/cert/
    cp /root/certificates/2023/staging.med.university.edu.key /var/www/vhosts/staging.med.university.edu/cert/
    ```
25. Create the Apache VirtualHosts by creating a file named `000-elentra.conf` and placing it `/etc/apache2/sites-available/`.\
    \
    This file should contain the following:

    ```
    # This will limit what information Apache reveals about itself.
    ServerTokens Prod
    ServerSignature Off
    TraceEnable Off

    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

    # Apache performance tuning options for more connections.
    #<IfModule mpm_prefork_module>
    #    MaxRequestWorkers 512
    #    ServerLimit 512
    #</IfModule>

    # Production
    <VirtualHost *:80>
        ServerName elentra.med.university.edu
        ServerAdmin sysadmin@med.university.edu

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
    </VirtualHost>
    <VirtualHost *:443>
        ServerName elentra.med.university.edu:443
        ServerAdmin sysadmin@med.university.edu

        SSLEngine on
        SSLProtocol -all +TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

        SSLCertificateFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.crt
        SSLCertificateKeyFile /var/www/vhosts/elentra.med.university.edu/cert/elentra.med.university.edu.key
        #SSLCACertificateFile /var/www/vhosts/elentra.med.university.edu/cert/ca-certificate.crt

        SSLUseStapling on

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
        Header always set X-Frame-Options SAMEORIGIN

        DocumentRoot /var/www/vhosts/elentra.med.university.edu/current/www-root
        <Directory "/var/www/vhosts/elentra.med.university.edu/current/www-root">
            Options FollowSymLinks
            Require all granted
            AllowOverride all
        </Directory>
    </VirtualHost>

    # Staging
    <VirtualHost *:80>
        ServerName staging.med.university.edu
        ServerAdmin sysadmin@med.university.edu

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
    </VirtualHost>
    <VirtualHost *:443>
        ServerName staging.med.university.edu:443
        ServerAdmin sysadmin@med.university.edu

        SSLEngine on
        SSLProtocol -all +TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

        SSLCertificateFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.crt
        SSLCertificateKeyFile /var/www/vhosts/staging.med.university.edu/cert/staging.med.university.edu.key
        #SSLCACertificateFile /var/www/vhosts/staging.med.university.edu/cert/ca-certificate.crt

        SSLUseStapling on

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
        Header always set X-Frame-Options SAMEORIGIN

        DocumentRoot /var/www/vhosts/staging.med.university.edu/current/www-root
        <Directory "/var/www/vhosts/staging.med.university.edu/current/www-root">
            Options FollowSymLinks
            Require all granted
            AllowOverride all
        </Directory>
    </VirtualHost>
    ```
26. Enable this new site by typing:

    ```
    a2ensite 000-elentra
    systemctl reload apache2
    ```
27. Create a new file in the `/etc/supervisor/conf.d` directory called `elentra.conf`, and use the following template snippet as a reference to create your own file.\\

    Please make sure that you have the correct path in **`command`** and **`stdout_logfile`**, and that **`user`** is the correct system account that your existing cron jobs are run as.

    ```
    [program:staging]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/staging.elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=staging
    autostart=true
    autorestart=true
    user=staging
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/staging.elentra.med.university.edu/storage/logs/worker.log

    [program:production]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/vhosts/elentra.med.university.edu/current/www-root/core/library/vendor/elentrapackages/elentra-1x-api/artisan queue:work --queue=high,emails,default,low --env=production
    autostart=true
    autorestart=true
    user=production
    numprocs=1
    redirect_stderr=true
    stdout_logfile=/var/www/vhosts/elentra.med.university.edu/storage/logs/worker.log

    [group:elentra]
    programs=staging,production
    ```
28. Test your new Apache configuration, then restart Apache and Supervisor.

    ```
    apachectl configtest
    systemctl restart apache2
    systemctl restart supervisor
    ```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.elentra.org/technical/administrators/application-server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
