commit b9e20ca0302d20ba945deecc5b3df96f176d9f06 Author: Knut Ahlers Date: Sun Sep 7 00:27:17 2014 +0200 Initial version of luzifer/php5-nginx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8000dd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vagrant diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1db1859 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:14.04 + +MAINTAINER Knut Ahlers + +RUN \ + apt-get -y update && \ + apt-get install -y ansible python-apt + +ADD . /tmp/ansible + +RUN \ + cd /tmp/ansible && \ + ansible-playbook playbook.yml -c local -i /tmp/ansible/inventory && \ + apt-get purge -y ansible python-apt && \ + apt-get autoremove -y && \ + echo "\ndaemon off;" >> /etc/nginx/nginx.conf && \ + cd / && rm -rf /tmp/ansible && \ + rm -rf /var/lib/apt/lists/* + +EXPOSE 80 + +CMD ["nginx"] diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..a67f1b3 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,122 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "ubuntu/trusty64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # If true, then any SSH connections made will enable agent forwarding. + # Default value: false + # config.ssh.forward_agent = true + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider "virtualbox" do |vb| + # # Don't boot with headless mode + # vb.gui = true + # + # # Use VBoxManage to customize the VM. For example to change memory: + # vb.customize ["modifyvm", :id, "--memory", "1024"] + # end + # + # View the documentation for the provider you're using for more + # information on available options. + + # Enable provisioning with CFEngine. CFEngine Community packages are + # automatically installed. For example, configure the host as a + # policy server and optionally a policy file to run: + # + # config.vm.provision "cfengine" do |cf| + # cf.am_policy_hub = true + # # cf.run_file = "motd.cf" + # end + # + # You can also configure and bootstrap a client to an existing + # policy server: + # + # config.vm.provision "cfengine" do |cf| + # cf.policy_server_address = "10.0.2.15" + # end + + # Enable provisioning with Puppet stand alone. Puppet manifests + # are contained in a directory path relative to this Vagrantfile. + # You will need to create the manifests directory and a manifest in + # the file default.pp in the manifests_path directory. + # + # config.vm.provision "puppet" do |puppet| + # puppet.manifests_path = "manifests" + # puppet.manifest_file = "site.pp" + # end + + # Enable provisioning with chef solo, specifying a cookbooks path, roles + # path, and data_bags path (all relative to this Vagrantfile), and adding + # some recipes and/or roles. + # + # config.vm.provision "chef_solo" do |chef| + # chef.cookbooks_path = "../my-recipes/cookbooks" + # chef.roles_path = "../my-recipes/roles" + # chef.data_bags_path = "../my-recipes/data_bags" + # chef.add_recipe "mysql" + # chef.add_role "web" + # + # # You may also specify custom JSON attributes: + # chef.json = { :mysql_password => "foo" } + # end + + # Enable provisioning with chef server, specifying the chef server URL, + # and the path to the validation key (relative to this Vagrantfile). + # + # The Opscode Platform uses HTTPS. Substitute your organization for + # ORGNAME in the URL and validation key. + # + # If you have your own Chef Server, use the appropriate URL, which may be + # HTTP instead of HTTPS depending on your configuration. Also change the + # validation key to validation.pem. + # + # config.vm.provision "chef_client" do |chef| + # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" + # chef.validation_key_path = "ORGNAME-validator.pem" + # end + # + # If you're using the Opscode platform, your validator client is + # ORGNAME-validator, replacing ORGNAME with your organization name. + # + # If you have your own Chef Server, the default validation client name is + # chef-validator, unless you changed the configuration. + # + # chef.validation_client_name = "ORGNAME-validator" +end diff --git a/files/cgi_pool b/files/cgi_pool new file mode 100644 index 0000000..c0df767 --- /dev/null +++ b/files/cgi_pool @@ -0,0 +1,6 @@ +-a 127.0.0.1 +-p 9000 +-C 10 +-u www-data +-g www-data +-- /usr/bin/php-cgi diff --git a/files/fastcgi_params.inc b/files/fastcgi_params.inc new file mode 100644 index 0000000..281c7b0 --- /dev/null +++ b/files/fastcgi_params.inc @@ -0,0 +1,22 @@ +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; + +# PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; diff --git a/files/init-spawn-fcgi.sh b/files/init-spawn-fcgi.sh new file mode 100644 index 0000000..000bc3c --- /dev/null +++ b/files/init-spawn-fcgi.sh @@ -0,0 +1,223 @@ +#! /bin/bash +### BEGIN INIT INFO +# Provides: spawn-fcgi +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Description: initscript to manage a pool of workers +# configured in $POOL_DIR +### END INIT INFO + +# Author: Lars Fronius +# + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="FCGI Worker Pools" +NAME=spawn-fcgi +DAEMON=/usr/bin/$NAME +POOL_DIR=/etc/spawn-fcgi +POOLS=$(find $POOL_DIR -type f -printf "%f\n") +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + if [[ -n "$1" ]]; then + POOLS=$1 + fi + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + for POOL in $POOLS; do + POOL_ARGS=$(<$POOL_DIR/$POOL) + PIDFILE=/var/run/${POOL}_spawn-fcgi.pid + ARGS_FILE=/var/run/${POOL}_spawn-fcgi.args + echo "$POOL_ARGS" > $ARGS_FILE + start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --exec $DAEMON --pidfile $PIDFILE -- \ + -P $PIDFILE $POOL_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. + done +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + if [[ -n "$1" ]]; then + POOLS=$1 + fi + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + for POOL in $POOLS; do + PIDFILE=/var/run/${POOL}_spawn-fcgi.pid + ARGS_FILE=/var/run/${POOL}_spawn-fcgi.args + for pid in $(<$PIDFILE); do + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile <(echo ${pid}) + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + start-stop-daemon --stop --quiet --retry=0/30/KILL/5 --pidfile <(echo ${pid}) + [ "$?" = 2 ] && return 2 + done + rm -f $PIDFILE + rm -f $ARGS_FILE + done +} + +# +# Function that reloads spawn-fcgi which have changed configs +# +do_reload() { + local action=0 + for POOL in $POOLS; do + POOL_ARGS=$(<$POOL_DIR/$POOL) + PIDFILE=/var/run/${POOL}_spawn-fcgi.pid + ARGS_FILE=/var/run/${POOL}_spawn-fcgi.args + if ! [ "$(<$ARGS_FILE)" = "$POOL_ARGS" ]; then + log_daemon_msg "Restarting $DESC $POOL" "$NAME" + do_stop $POOL + case "$?" in + 0|1) + do_start $POOL + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + let "action+=1" + fi + done + if [ $action -eq 0 ]; then + log_daemon_msg "No $DESC configuration has changed, not restarting" "$NAME" + log_end_msg 0 + fi + return 0 +} + +check_pools() { + local count=0 + local check=0 + local procs=0 + for POOL in $POOLS; do + if [ -f /var/run/${POOL}_spawn-fcgi ]; then + PIDFILE=/var/run/${POOL}_spawn-fcgi.pid + for pid in $(<$PIDFILE); do + let "count++" + ps -p ${pid} 2>&1 > /dev/null + if [ $? -eq 0 ]; then + let "check++" + fi + done + let "procs++" + fi + done + if [ $procs -ne 0 ]; then + if [ $count -eq $check ]; then + return 0 + else + return 3 + fi + else + return 1 + fi +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + check_pools + case "$?" in + 0) + log_daemon_msg "All $DESC running" "$NAME" && log_end_msg 0 ;; + 1) + log_daemon_msg "All $DESC stopped" "$NAME" && log_end_msg 0 ;; + *) + log_daemon_msg "Something wrong with $DESC" "$NAME" && log_end_msg 1 ;; + esac + ;; + reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + do_reload + ;; + restart) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/files/nginx.conf b/files/nginx.conf new file mode 100644 index 0000000..8e0032e --- /dev/null +++ b/files/nginx.conf @@ -0,0 +1,20 @@ +server { + listen 80; + access_log /var/log/nginx/phpframework_app; + root /application/; + + location / { + try_files $uri /index.php?$args; + } + + location /index.php { + fastcgi_pass_header Authorization; + fastcgi_pass 127.0.0.1:9000; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include /etc/nginx/includes/fastcgi_params.inc; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/handlers/nginx.yml b/handlers/nginx.yml new file mode 100644 index 0000000..65220c1 --- /dev/null +++ b/handlers/nginx.yml @@ -0,0 +1,6 @@ +--- +- name: restart nginx + service: name=nginx state=restarted + +- name: restart spawn_fcgi + service: name=spawn-fcgi state=restarted diff --git a/inventory b/inventory new file mode 100644 index 0000000..8bb7ba6 --- /dev/null +++ b/inventory @@ -0,0 +1,2 @@ +[local] +localhost diff --git a/playbook.yml b/playbook.yml new file mode 100644 index 0000000..af43586 --- /dev/null +++ b/playbook.yml @@ -0,0 +1,8 @@ +--- +- hosts: all + sudo: yes + tasks: + - include: tasks/nginx.yml + + handlers: + - include: handlers/nginx.yml diff --git a/tasks/nginx.yml b/tasks/nginx.yml new file mode 100644 index 0000000..e3cdcbb --- /dev/null +++ b/tasks/nginx.yml @@ -0,0 +1,43 @@ +--- +- name: ensure required packages are installed + apt: name={{ item }} update_cache=yes + with_items: + - nginx + - php5-cgi + - php5-curl + - spawn-fcgi + notify: + - restart spawn_fcgi + - restart nginx + +- name: Remove default nginx configuration + file: path=/etc/nginx/sites-enabled/default state=absent + +- name: Configure nginx + copy: src=files/nginx.conf dest=/etc/nginx/sites-enabled/phpframework_app + notify: + - restart nginx + +- name: Create includes directory + file: path=/etc/nginx/includes state=directory + +- name: Configure fastcgi params + copy: src=files/fastcgi_params.inc dest=/etc/nginx/includes/fastcgi_params.inc + notify: + - restart nginx + +- name: Create spawn-fcgi directory + file: path=/etc/spawn-fcgi state=directory + +- name: Configure spawn-fcgi + copy: src=files/cgi_pool dest=/etc/spawn-fcgi/phpframework_app + notify: + - restart spawn_fcgi + +- name: Set up init script for spawn-fcgi + copy: src=files/init-spawn-fcgi.sh dest=/etc/init.d/spawn-fcgi owner=root group=root mode=0755 + notify: + - restart spawn_fcgi + +- name: Enable spawn-fcgi service + service: name=spawn-fcgi enabled=yes