Static website in Satorix
A tutorial for getting a static HTML website working in Satorix. For a description of the default environment variables managed by the Satorix Dashboard and using environment variables in your website check the application environment variables article.
Static website configuration
In your website code we will be working with some files to get things running on your Satorix Hosting Cluster. Make sure
your public HTML 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 website. 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
Files placed in the public/
directory
A public/nginx.conf
template to configure the Staticsite Nginx server. This setup has includes for web server level
redirects, proxy settings, and authentication.
<%
def include_custom_template(template, indent = 0, the_binding = binding)
path = File.join(File.dirname(__FILE__), 'includes', template)
erb = ERB.new(File.read(path), nil, "-", next_eoutvar)
erb.filename = path
result = erb.result(the_binding)
# Set indenting
result.gsub!(/^/, " " * indent)
result.gsub!(/\A +/, '')
result
end
def next_eoutvar
@next_eoutvar_index ||= 0
@next_eoutvar_index += 1
"_erbout#{@next_eoutvar_index}"
end
def use_canonical?
!canonical_domain.nil? &&
!canonical_domain.empty? &&
!canonical_domain_protocol.nil? &&
!canonical_domain_protocol.empty?
end
def canonical_domain
ENV['SATORIX_CANONICAL_URI_HOST']
end
def canonical_domain_protocol
ENV['SATORIX_CANONICAL_URI_PROTOCOL']
end
def canonical_uri
"#{ canonical_domain_protocol }://#{ canonical_domain }" if use_canonical?
end
%>
worker_processes 1;
daemon off;
error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
events { worker_connections 4096; }
http {
charset utf-8;
log_format cloudfoundry '$http_x_forwarded_for - $http_referer - [$time_local] "$request" $status $body_bytes_sent';
access_log <%= ENV["APP_ROOT"] %>/nginx/logs/access.log cloudfoundry;
default_type application/octet-stream;
include mime.types;
sendfile on;
gzip on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_proxied any;
gunzip on;
gzip_static always;
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;
gzip_vary on;
tcp_nopush on;
keepalive_timeout 30;
port_in_redirect off; # Ensure that redirects don't include the internal container PORT - <%= ENV["PORT"] %>
server_tokens off;
<% if use_canonical? %>
# Redirect all requests to the canonical domain.
server {
server_name _;
listen <%= ENV["PORT"] %> default_server;
return 301 <%= canonical_uri %>$request_uri;
}
<% else %>
# No canonical domain defined, passing all requests to the main server block.
<% end %>
# Main server block.
server {
<% if use_canonical? %>
server_name <%= canonical_domain %>;
<% else %>
server_name _;
<% end %>
listen <%= ENV["PORT"] %>;
root <%= ENV["APP_ROOT"] %>/public;
<%= include_custom_template('page_level_redirects.erb', 6, binding) %>
<%= include_custom_template('proxy_configuration.erb', 6, binding) %>
<%= include_custom_template('authentication.erb', 6, binding) %>
}
}
Files placed in the nginx/conf/includes/
directory
An include file nginx/conf/includes/page_level_redirects.erb
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 nginx/conf/includes/proxy_configuration.erb
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.
<% if ENV['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;
<% ENV['SATORIX_PROXY_IPS'].to_s.split(' ').each do |real_ip| %>
set_real_ip_from <%= real_ip %>;
<% end %>
<% end %>
# Use the internal Flynn network set X-Forwarded-For header for access IPs.
set_real_ip_from <%= ENV['SATORIX_REAL_IP_FROM'] || '100.100.0.0/16' %>;
real_ip_header X-Forwarded-For;
# End Proxy Configuration
The include file nginx/conf/includes/authentication.erb
is used to add HTTP Basic authentication into the Nginx
configuration and allows you to set an environment variable SATORIX_AUTHENTICATION_HTPASSWDS
the content of which will
be used to generate the htpasswd
file:
# Authentication
<%-
# The password_files hash defines which password files will be written out.
# The generated password files should be ignored from version control.
# Each desired password file should be specified as a key, with the value being a source for the file contents.
# The contents should include hashed username/password combinations, separated by whitespace.
# These can be generated using the htpasswd application, or an online tool like http://www.htaccesstools.com/htpasswd-generator/
# For more info, see: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
password_files = {
'htpasswd' => ENV['SATORIX_AUTHENTICATION_HTPASSWDS']
}
def password_file_location(filename)
includes_location = File.expand_path(File.dirname(__FILE__))
File.join( includes_location, filename )
end
password_files.each do |filename, raw_contents|
contents = raw_contents.to_s.split.join("\n")
File.open(password_file_location(filename), 'w') {|f| f.write(contents) } unless contents.empty?
end
allowed_without_auth = ENV['SATORIX_AUTHENTICATION_ALLOWED_IPS'].to_s.split
allowed_without_auth = ['all'] if allowed_without_auth.empty?
-%>
# Allow listed networks to access without auth, otherwise require password if defined
location / {
satisfy any;
<% allowed_without_auth.each do |target| -%>
allow <%= target %>;
<% end -%>
<% if File.file?(password_file_location('htpasswd')) -%>
auth_basic "Please Log In";
auth_basic_user_file <%= password_file_location('htpasswd') %>;
<% end -%>
deny all;
}
# End Authentication
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.