Changeset - 7727c37bce67
[Not reviewed]
0 1 4
Branko Majic (branko) - 9 years ago 2015-05-07 23:53:03
branko@majic.rs
MAR-5: Fixed some typos in role reference for web server. Added initial implementation of a role for deploying PHP websites (some common functionality).
5 files changed with 247 insertions and 3 deletions:
0 comments (0 inline, 0 general)
docs/rolereference.rst
Show inline comments
 
@@ -837,26 +837,26 @@ Here is an example configuration for setting-up the mail forwarder:
 

	
 
  smtp_relay_host: mail.example.com
 

	
 
  smtp_relay_truststore: /etc/ssl/certs/example_ca_chain.pem
 

	
 

	
 
Web Server
 
----------
 

	
 
The ``web_server`` role can be used for setting-up a web server on destination
 
machine.
 

	
 
The role is supposed very lightweight, providing a basis for deployment of web
 
applications.
 
The role is supposed to be very lightweight, providing a basis for deployment of
 
web applications.
 

	
 
The role implements the following:
 

	
 
* Installs and configures nginx with a single, default vhost with a small static
 
  index page.
 
* Deploys the HTTPS TLS private key and certificate (for default vhost).
 
* Configures firewall to allow incoming connections to the web server.
 
* Installs and configures supervisor, virtualenv, and virtualenvwrapper as a
 
  common base for Python apps.
 
* Installs and configures PHP FPM as a common base for PHP apps.
 

	
 

	
 
@@ -873,23 +873,143 @@ Parameters
 

	
 
**web_default_title** (string, mandatory)
 
  Title for the default web page shown to users (if no other vhosts were matched).
 

	
 
**web_default_message** (string, mandatory)
 
  Message for the default web page shown to users (if no other vhosts were
 
  matched).
 

	
 

	
 
Examples
 
~~~~~~~~
 

	
 
Here is an example configuration for setting-up XMPP server using Prosody:
 
Here is an example configuration for setting-up web server:
 

	
 
.. code-block:: yaml
 

	
 
  ---
 

	
 
  https_tls_key: "{{ inventory_dir }}/tls/web.example.com_https.key"
 
  https_tls_certificate: "{{ inventory_dir }}/tls/web.example.com_https.pem"
 

	
 
  web_default_title: "Welcome to Example Inc."
 
  web_default_message: "You are attempting to access the web server using a wrong name or an IP address. Please check your URL."
 

	
 

	
 
PHP Website
 
--------
 

	
 
The ``php_website`` role can be used for setting-up a website powered by PHP on
 
destination machine.
 

	
 
This role is normally not supposed to be used directly, but should instead serve
 
as the basis for writing website-specific roles. Therefore the role is written
 
in quite generic way, allowing the integrator to write his/her own logic for
 
deploying the necessary PHP applications, while still reusing a common base and
 
reducing the workload.
 

	
 
The role implements the following:
 

	
 
* Creates a dedicated user/group for running the PHP scripts.
 
* Creates a base directory where the website-specific code and data should be
 
  stored at.
 
* Adds nginx to website's group, so nginx could read the necessary files.
 
* Adds website administrator to website's group, so administrator could manage
 
  the code and data.
 
* Installs additional packages required for running the role (as configured).
 
* Configures PHP FPM and nginx to serve the website.
 

	
 
The role is implemented with the following layout/logic in mind:
 

	
 
* Website users are named after the ``FQDN`` (fully qualified domain name) of
 
  website, in format of ``web-ESCAPEDFQDN``, where ``ESCAPEDFQDN`` is equal to
 
  ``FQDN`` where dots have been replaced by underscores (for example,
 
  ``web-cloud_example_com``).
 
* All websites reside within a dedicated sub-directory in ``/var/www``. The
 
  sub-directory name is equal to the ``FQDN`` used for accessing the
 
  website. Owner of the directory is set to be the application administrator,
 
  while group is set to be the website group. Additionally, ``SGID`` bit is set
 
  on the directory. This allows admin, with correct umask, to create necessary
 
  files and directories that should be readable (and eventually writeable) by
 
  the website user (running the PHP scripts) without having to become root.
 
* All files placed in the website directory should be either created there
 
  directly, or copied to the directory in order to make sure the ``SGID`` gets
 
  honored. **Do not move the files, the permissions will not be set correctly.**
 
* Within the website directory, nginx/php5-fpm will expect to find the relevant
 
  files within the htdocs sub-directory (this can be symlink too).
 
* nginx communicates with PHP FPM over a dedicated Unix socket for each website.
 

	
 

	
 
Parameters
 
~~~~~~~~~~
 

	
 
**admin** (string, mandatory)
 
  Name of the operating system user in charge of maintaining the website. This
 
  user is capable of making modifications to website configuration anda data
 
  stored within the website directory.
 

	
 
**deny_files_regex** (list, optional)
 
  List of regular expressions for matching files/locations to which the web
 
  server should deny access. This is useful to block access to any sensitive
 
  files that should not be served directly by the web server. The format must be
 
  compatible with regular expressions used by ``nginx`` for ``location ~``
 
  syntax.
 

	
 
**fqdn** (string, mandatory)
 
  Fully-qualified domain name where the website is reachable. This value is used
 
  for calculating the user/group name for dedicated website user, as well as
 
  home directory of the website user (where data/code should be stored at).
 

	
 
**php_rewrite_url** (string, optional)
 
  If implementing some form of clean URL schema, this parameter can be used for
 
  defining how the clean URLs should be mapped onto actual PHP scripts. When
 
  specifying this parameter, one special variable is available - ``$suburi``
 
  (which is the URI requested by HTTP client, usually in clean URL form). This
 
  is in addition to any other variables provided out of the box by ``nginx``
 
  (like ``$args`` and such).
 

	
 
**rewrites** (list, optional)
 
  A list of rewrite rules that are applied to incoming requests. Each element of
 
  the list should be a string value compatible with the format of ``nginx``
 
  option ``rewrite``. The keyword ``rewrite`` itself should be omitted, as well
 
  as trailing semi-colon (``;``).
 

	
 
**packages** (list, optional)
 
  A list of additional packages to install for this particular PHP
 
  appliction. This is usually going to be different PHP extensions.
 

	
 
**uid** (integer, mandatory)
 
  UID/GID (they are set-up to be the same) of the dedicated website
 
  user/group.
 

	
 

	
 
Examples
 
~~~~~~~~
 

	
 
Here is an example configuration for setting-up a (base) PHP website (for running
 
``ownCloud`` application):
 

	
 
.. code-block:: yaml
 

	
 
    ---
 

	
 
    - role: php_website
 
      fqdn: cloud.example.com
 
      uid: 2001
 
      admin: admin
 
      php_rewrite_url: /index.php
 
      rewrites:
 
        - ^/\.well-known/host-meta /public.php?service=host-meta
 
        - ^/\.well-known/host-meta\.json /public.php?service=host-meta-json
 
        - ^/\.well-known/carddav /remote.php/carddav/ redirect
 
        - ^/\.well-known/caldav /remote.php/caldav/ redirect
 
        - ^/apps/calendar/caldav\.php /remote.php/caldav/
 
        - ^/apps/contacts/carddav\.php /remote.php/carddav/
 
        - ^/remote/(.*) /remote.php
 
      deny_files_regex:
 
        - ^(\.|autotest|occ|issue|indie|db_|console|build/|tests/|config/|lib/|3rdparty/|templates/).*
 
      packages:
 
        # For ownCloud
 
        - php5-gd
 
        - php5-json
 
        - php5-mysql
 
        - php5-curl
roles/php_website/defaults/main.yml
Show inline comments
 
new file 100644
 
---
 

	
 
deny_files_regex: []
 
packages: []
 
php_rewrite_url: ""
 
rewrites: []
roles/php_website/tasks/main.yml
Show inline comments
 
new file 100644
 
---
 

	
 
- set_fact:
 
    user: "web-{{ fqdn | replace('.', '_') }}"
 
    home: "/var/www/{{ fqdn }}"
 

	
 
- name: Create PHP website group
 
  group: name="{{ user }}" gid="{{ uid }}" state=present
 

	
 
- name: Create home directory for the user (avoid populating with skeleton)
 
  file: path="{{ home }}" state=directory
 
        owner="{{ admin }}" group="{{ user }}" mode=2750
 

	
 
- name: Create PHP website user
 
  user: name="{{ user }}" uid="{{ uid }}" group="{{ user }}"
 
        system=yes createhome=no state=present
 

	
 
- name: Add nginx user to site group
 
  user: name="www-data" groups="{{ user }}" append="yes"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Add admin to site group
 
  user: name="{{ admin }}" groups="{{ user }}" append="yes"
 

	
 
- name: Install extra packages for site
 
  apt: name="{{ item }}" state=installed
 
  with_items: packages
 

	
 
- name: Deploy PHP FPM configuration file for site
 
  template: src="fpm_site.conf.j2" dest="/etc/php5/fpm/pool.d/{{ fqdn }}.conf" validate="php5-fpm -t -y %s"
 
  notify:
 
    - Restart php5-fpm
 

	
 
- name: Deploy nginx configuration file for site
 
  template: src="nginx_site.j2" dest="/etc/nginx/sites-available/{{ fqdn }}"
 
            owner=root group=root mode=640
 
  notify:
 
    - Restart nginx
 

	
 
- name: Enable site
 
  file: src="/etc/nginx/sites-available/{{ fqdn }}" dest="/etc/nginx/sites-enabled/{{ fqdn }}"
 
        state=link
 
  notify:
 
    - Restart nginx
roles/php_website/templates/fpm_site.conf.j2
Show inline comments
 
new file 100644
 
; Start a new named pool.
 
[{{ fqdn }}]
 

	
 
; Set the user and group that should execute the scripts.
 
user = {{ user }}
 
group = {{ user }}
 

	
 
; Listen on a dedicated UNIX socket.
 
listen = /var/run/php5-fpm/{{ fqdn }}.sock
 

	
 
; Set-up UNIX socket permissions (allow web server to connect).
 
listen.owner = www-data
 
listen.group = www-data
 
listen.mode = 0660
 

	
 
; Configure how processes are managed and how many are launched.
 
pm = dynamic
 
pm.max_children = 5
 
pm.start_servers = 2
 
pm.min_spare_servers = 1
 
pm.max_spare_servers = 3
 

	
 
; Chdir to this directory at the start.
 
chdir = /
 

	
 
; Redirect worker stdout/stder into main error log. This will also allow Nginx
 
; to log errors in site-specific log file.
 
catch_workers_output = yes
roles/php_website/templates/nginx_site.j2
Show inline comments
 
new file 100644
 
server {
 
    listen 80;
 

	
 
    root {{ home }}/htdocs/;
 

	
 
    index index.php;
 

	
 
    server_name {{ fqdn }};
 

	
 
    # Site rewrites.
 
    {% for rewrite in rewrites -%}
 
    rewrite {{ rewrite }};
 
    {% endfor %}
 

	
 
    # Interpret PHP files via FastCGI.
 
    location ~ \.php($|/) {
 
        include snippets/fastcgi-php.conf;
 
        fastcgi_pass unix:/var/run/php5-fpm/{{ fqdn }}.sock;
 
    }
 

	
 
    # Deny access to all hidden files (this will prevent access to
 
    # .htaccess too).
 
    location ~ /\. {
 
        deny all;
 
    }
 

	
 
    {% for regex in deny_files_regex -%}
 
    # Deny access to user-specified files.
 
    location ~ {{ regex }} {
 
        deny all;
 
    }
 
    {% endfor %}
 

	
 
    {% if php_rewrite_url -%}
 
    # Serve the remaining files directly or rewrite request for PHP processing
 
    # (clean URLs).
 
    location ~ /(.*) {
 
        set $suburi $1;
 
	try_files $uri $uri/ {{ php_rewrite_url }};
 
    }
 
    {% endif %}
 

	
 
    access_log /var/log/nginx/{{ fqdn }}-access.log;
 
    error_log /var/log/nginx/{{ fqdn }}-error.log;
 
}
0 comments (0 inline, 0 general)