PHP application in Satorix

A tutorial for getting a PHP application working in Satorix. For a description of the default environment variables managed by the Satorix Dashboard and using environment variables in your application check the application environment variables article.

Manual PHP configuration

In your application code we will be working with some files to get things running on your Satorix Hosting Cluster. Make sure your public PHP code is placed into a sub-folder called public/.

Files placed in the application root directory

Add a .gitlab-ci.yml into the root directory of your application. This is a basic setup to allow us to automatically deploy to your Satorix Hosting Cluster:

# We are using the Satorix base image from https://hub.docker.com/r/satorix/base/
image: 'satorix/base:18'

# Global caching directives.
cache:
  key: "$CI_PROJECT_ID"
  paths:
    - 'tmp/satorix/cache' # To cache buildpack output between runs.


.satorix: &satorix
  script:
    - gem install satorix --no-document
    - satorix


deploy_with_flynn:
  environment:
    name: $CI_COMMIT_REF_NAME
    url: "http://$CI_PROJECT_NAME.$CI_COMMIT_REF_SLUG.$SATORIX_HOSTING_NAMESPACE"
  stage: deploy
  only:
    - staging
    - production
  <<: *satorix

Create a Procfile in the root directory of your application. This file defines the processes that your Satorix Hosting Cluster will run:

# Procfile defines the types of process that Satorix will run.
# For more information, please see the documentation at https://www.satorix.com/docs

web: vendor/bin/heroku-php-nginx -C nginx-php.conf.php -i custom_php.ini public/

If you don’t already have one created. We recommend you use composer to manage your PHP packages. Satorix uses the PHP buildpack to host your application and works best if you use composer. In your application root directory if needed create a composer.json:

{
}

Create a custom_php.ini for any PHP configuration your application requires, here we are setting the timezone, change for your needs:

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = America/Chicago

A custom template nginx-php.conf.php is used to configure the PHP Buildpack Nginx for Satorix Dashboard customization:

gzip on;
gzip_comp_level 3;
gzip_min_length 150;
gzip_proxied any;
gzip_types text/plain text/css text/json text/javascript
    application/javascript application/x-javascript application/json
    application/rss+xml application/vnd.ms-fontobject application/x-font-ttf
    application/xml font/opentype image/svg+xml text/xml;

index index.php index.html index.htm;

<?php if(file_exists(dirname(__FILE__).'/config/page_level_redirects.php')) { ?>
<?php include(dirname(__FILE__).'/config/page_level_redirects.php') ?>
<?php } ?>

<?php if(getenv('SATORIX_CANONICAL_URI_PROTOCOL')) { ?>
# Redirect to default protocol
if ( $http_x_forwarded_proto != <?php echo getenv('SATORIX_CANONICAL_URI_PROTOCOL') ?> ) {
  return 301 <?php echo getenv('SATORIX_CANONICAL_URI_PROTOCOL') ?>://<?php echo getenv('SATORIX_CANONICAL_URI_HOST') ?>$request_uri;
}
<?php } ?>

<?php if(getenv('SATORIX_CANONICAL_URI_HOST')) { ?>
# Redirect to default domain
if ( $http_host != <?php echo getenv('SATORIX_CANONICAL_URI_HOST') ?> ) {
  return 301 <?php echo getenv('SATORIX_CANONICAL_URI_PROTOCOL') ?>://<?php echo getenv('SATORIX_CANONICAL_URI_HOST') ?>$request_uri;
}
<?php } ?>

<?php if(file_exists(dirname(__FILE__).'/config/proxy_configuration.php')) { ?>
<?php include(dirname(__FILE__).'/config/proxy_configuration.php') ?>
<?php } ?>

# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
  log_not_found off;
  access_log off;
}

location = /robots.txt {
  allow all;
  log_not_found off;
  access_log off;
}

location ~ /config {
  deny all;
}

<?php if(file_exists(dirname(__FILE__).'/config/authentication.php')) { ?>
<?php include(dirname(__FILE__).'/config/authentication.php') ?>
<?php } ?>

Files placed in the config/ directory

An include file config/page_level_redirects.php allows you to create redirects to be handled by the Nginx server directly:

# Page-level Redirects
#
#   Define your own custom page-level redirects below.
#
#   Examples:
#     Standard single page redirects:
#       location = /old-page-1 { return 301 /new-page-1; }
#       location = /old-page-2 { return 301 /new-page-2; }

# End Page-level Redirects

We create the include config/proxy_configuration.php to configure upstream proxies that you want to filter from the access logs. This allows you to see the actual requesting IP address of the client:

# Proxy Configuration
#
# Used to configure settings related to Flynn's interaction with proxies.
# Add your custom proxy configuration details below.

<?php if(getenv('SATORIX_PROXY_IPS')) { ?>
# Provide additional proxy IPs, as described at http://nginx.org/en/docs/http/ngx_http_realip_module.html.
#
# This is particularity useful for services like CloudFlare, using the example at:
# https://support.cloudflare.com/hc/en-us/articles/200170706-How-do-I-restore-original-visitor-IP-with-Nginx-
#
# If required, this variable should be populated with a space-separated list of proxy IPs. Example:
# 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 104.16.0.0/12 108.162.192.0/18 2c0f:f248::/32

real_ip_recursive on;

<?php $proxy_ips = preg_split('/\s+/', (string) getenv('SATORIX_PROXY_IPS')); ?>
<?php foreach($proxy_ips as $real_ip) { ?>
set_real_ip_from <?php echo $real_ip ?>;
<?php } ?>
<?php } ?>

# Use the internal Flynn network set X-Forwarded-For header for access IPs.
<?php $satorix_real_ip_from = getenv('SATORIX_REAL_IP_FROM', true) ? getenv('SATORIX_REAL_IP_FROM') : "100.100.0.0/16"; ?>
set_real_ip_from <?php echo $satorix_real_ip_from ?>;
real_ip_header X-Forwarded-For;

# End Proxy Configuration

The include file config/authentication.php is used to add HTTP Basic authentication into the Nginx configuration:

# Authentication
#
#   Allow `SATORIX_AUTHENTICATION_ALLOWED_IPS` networks to access without auth, otherwise require password
<?php if(getenv('SATORIX_AUTHENTICATION_HTPASSWDS')) {
  $htpasswd_contents = preg_split('/\s+/', (string) getenv('SATORIX_AUTHENTICATION_HTPASSWDS'));
  file_put_contents(dirname(__FILE__).'/.htpasswd', implode(PHP_EOL, $htpasswd_contents));
} ?>
location / {
  try_files $uri $uri/ /index.php?$args;
  satisfy any;
<?php $allowed_ips = preg_split('/\s+/',
    (string) getenv('SATORIX_AUTHENTICATION_ALLOWED_IPS', true) || file_exists(dirname(__FILE__).'/.htpasswd') ?
    getenv('SATORIX_AUTHENTICATION_ALLOWED_IPS') : "all"); ?>
<?php foreach($allowed_ips as $ip) { ?>
<?php ($ip == '') ?: print "  allow $ip;".PHP_EOL ?>
<?php } ?>
  deny all;
<?php if(file_exists(dirname(__FILE__).'/.htpasswd')) { ?>
  auth_basic "Please Log In";
  auth_basic_user_file <?php echo dirname(__FILE__).'/.htpasswd' ?>;
<?php } ?>
}

# End Authentication Configuration

Dashboard settings for HTTP Basic authentication

Add the environment variable SATORIX_AUTHENTICATION_HTPASSWDS to the environment you want to restrict access to. This sets the usernames and passwords to use for Nginx HTTP Basic authentication. Needs to be generated in the format created by the Apache tool htpasswd -nb username password or using an online generator. The ENVVAR should contain newline separated lists of username and hashed password. A use case for this is restricting access to your staging environment to only authorized users. Example input:

username:$apr1$vAxBKb8N$m0en1zabtHktHeFyT3j9y
alsoname:$apr1$vAxBKb8N$m0en1zabtHktHeFyT3j9y

If you want to skip HTTP authentication for an application set the Satorix default variable SATORIX_AUTHENTICATION_ALLOWED_IPS to all and do not create the SATORIX_AUTHENTICATION_HTPASSWDS variable. This is typically what you would do on the production environment.