> For the complete documentation index, see [llms.txt](https://docs.elentra.org/technical/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.elentra.org/technical/administrators/application-server.md).

# 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 %}
