diff --git a/nginx/passenger/README.md b/nginx/passenger/README.md new file mode 100644 index 0000000..3d7cea4 --- /dev/null +++ b/nginx/passenger/README.md @@ -0,0 +1,40 @@ +### Nginx Passenger + +* Installs nginx via ppa and configs it +* Passenger related configuration + +* NO TLS/SSL config for nginx so far - we have another Router/Load Balancer in + front of our apps so we don't need that for this role. If you are interesting + in adding https than feel free to add a PR. +* Various default configs for /etc/nginx/conf.d/* + + +### USAGE + +This role is intended to run together with ansible-Rails' other provisioning roles. It does not need to run on deployment step, as it uses the default touch tmp/restart.txt method. + +``` +roles: + - ... + - role: dresden-weekly.Rails/nginx/passenger + app_name: 'myapp' + app_hosts: 'www.myapp.de myapp.de en.myapp.de' + passenger_enable_action_cable: true + passenger_enable_message_bus: true + passenger_max_pool_size: 10 + nginx_max_body_size: 100M + +``` + +Default config implements some common practices like: + +* Cache-Header for /assets, as well as /system /uploads/ /photos (var: nginx_public_folder_to_cache) +* https requirement for Omniauth /auth route paths. Most Social networks now only allow callback domains via ssl only +* optional: message-bus or ActionCable optimization. If you are using message_bus gem for "realtime" communication with frontend, you run into problems with passenger in default config. The messages sometimes take long time for delivery. The recommended fix is to run another passenger process in parallel that handles these. The same is true for ActionCable if you are running in the default Rails-moutend way. + YOU WILL ALSO NEED TO ADD A SNIPPET TO YOUR APPLICATION-CODE: https://github.com/SamSaffron/message_bus#passenger. Enable with passenger_enable_action_cable / passenger_enable_message_bus + + + + + + diff --git a/nginx/passenger/defaults/main.yml b/nginx/passenger/defaults/main.yml index 76568db..0e67a32 100644 --- a/nginx/passenger/defaults/main.yml +++ b/nginx/passenger/defaults/main.yml @@ -1,9 +1,18 @@ +passenger_max_pool_size: 30 +# variables for all apps in /etc/nginx/conf.d/passenger.conf passenger_main_variables: - passenger_max_pool_size: 30 + passenger_max_pool_size: "{{passenger_max_pool_size}}" passenger_pool_idle_time: 0 passenger_root: "/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini" passenger_ruby: "/usr/bin/passenger_free_ruby" +# variables for app /etc/nginx/sites_enabled/site +passenger_variables: + passenger_enabled: "on" + passenger_ruby: "/home/{{app_user}}/.rvm/wrappers/ruby-{{ruby_version}}/ruby" + passenger_min_instances: 1 + passenger_max_preloader_idle_time: 0 + # Remove identifing headers like Passenger + Nginx version passenger_cloak_headers: true @@ -11,10 +20,52 @@ passenger_cloak_headers: true # app_hosts: "www.example.com example.com en.example.com de.example.de" app_hosts: "{{app_domain}}" -passenger_variables: - passenger_enabled: "on" - passenger_ruby: "/home/{{app_user}}/.rvm/wrappers/ruby-{{ruby_version}}/ruby" - passenger_min_instances: 1 - passenger_max_preloader_idle_time: 0 - nginx_config_file: "{{app_name}}.conf" + +# Nginx Regex for paths that should be cached by clients for 7 days +nginx_public_folder_to_cache: '^/(system|uploads|video|packs)/' +nginx_max_body_size: 200M + +# see: https://github.com/SamSaffron/message_bus#passenger +passenger_enable_message_bus: false +# https://www.phusionpassenger.com/library/config/nginx/action_cable_integration/#running-the-action-cable-server-on-the-same-host-and-port-under-a-sub-uri +passenger_enable_action_cable: false + +nginx_gzip_types: 'text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/x-icon' + +nginx_install_from_passenger_repo: yes + +nginx_install_packages: +- passenger + +nginx_worker_processes: 8 +nginx_worker_connections: 512 +nginx_keepalive: 65 +nginx_main_log_format: | + log_format main '$remote_addr - $http_x_forwarded_for - $remote_user [$time_local] ' + '"$request_method $scheme://$host$request_uri $server_protocol" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" $request_time'; + +nginx_conf_d: + gzip: + - gzip on + - gzip_disable "msie6" + - gzip_vary on + - gzip_proxied any + - gzip_types {{nginx_gzip_types}} + privacy: + - "more_clear_headers 'X-Powered-By'" + - "more_clear_headers 'X-Request-Id'" + - "more_clear_headers 'X-Runtime'" + - "more_set_headers 'Server: nginx'" + - "server_tokens off" + proxy: + - proxy_set_header X-Real-IP $remote_addr + - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for + - proxy_set_header Host $http_host + - proxy_set_header X-Forwarded-Proto $scheme + log: + - "{{nginx_main_log_format}}" + +nginx_conf_extra: {} diff --git a/nginx/passenger/tasks/config.yml b/nginx/passenger/tasks/config.yml index 3efc6b1..52691fa 100644 --- a/nginx/passenger/tasks/config.yml +++ b/nginx/passenger/tasks/config.yml @@ -1,5 +1,13 @@ +- name: Create the configurations for config.d file + template: src=config.conf.j2 dest=/etc/nginx/conf.d/{{ item }}.conf + with_flattened: + - "{{ nginx_conf_d.keys() | list }}" + - "{{ nginx_conf_extra.keys() | list }}" + notify: nginx reload + - template: dest=/etc/nginx/conf.d/passenger.conf src=passenger.conf.j2 notify: nginx reload + name: "Create /etc/nginx/conf.d/passenger.conf main config for serverwide settings" - template: dest=/etc/nginx/sites-available/{{nginx_config_file}} src=site.conf.j2 notify: nginx reload @@ -7,3 +15,6 @@ - file: src=/etc/nginx/sites-available/{{nginx_config_file}} dest=/etc/nginx/sites-enabled/{{app_name}} state=link owner=root group=root notify: nginx reload +- name: Create nginx default config + template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf + notify: nginx reload diff --git a/nginx/passenger/templates/config.conf.j2 b/nginx/passenger/templates/config.conf.j2 new file mode 100644 index 0000000..5a0f3cc --- /dev/null +++ b/nginx/passenger/templates/config.conf.j2 @@ -0,0 +1,11 @@ +#{{ ansible_managed }} + +{% set config = nginx_conf_d[item] or nginx_conf_extra[item] %} +{% for v in config %} +{% if v.find('\n') != -1 %} +{{v}} +{% else %} +{% if v != "" %}{{ v.replace(";",";\n ").replace(" {"," {\n ").replace(" }"," \n}\n") }}{% if v.find('{') == -1%}; +{% endif %}{% endif %}{% endif %} +{% endfor %} + diff --git a/nginx/passenger/templates/nginx.conf.j2 b/nginx/passenger/templates/nginx.conf.j2 new file mode 100644 index 0000000..6c765b3 --- /dev/null +++ b/nginx/passenger/templates/nginx.conf.j2 @@ -0,0 +1,25 @@ +# {{ ansible_managed }} +user www-data www-data; +worker_processes {{nginx_worker_processes}}; +pid /var/run/nginx.pid; +worker_rlimit_nofile 1024; + +events { + worker_connections {{nginx_worker_connections}}; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile "on"; + tcp_nopush "on"; + tcp_nodelay "on"; + keepalive_timeout "{{nginx_keepalive}}"; + access_log "/var/log/nginx/access.log"; + error_log "/var/log/nginx/error.log"; + types_hash_max_size 2048; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} + diff --git a/nginx/passenger/templates/passenger.conf.j2 b/nginx/passenger/templates/passenger.conf.j2 index fec27d6..7a7cfc6 100644 --- a/nginx/passenger/templates/passenger.conf.j2 +++ b/nginx/passenger/templates/passenger.conf.j2 @@ -1,6 +1,6 @@ # {{ ansible_managed }} -{% for key,value in passenger_main_variables.iteritems() %} +{% for key,value in passenger_main_variables.items() | list %} {{key}} {{value}}; {% endfor %} @@ -10,3 +10,5 @@ more_clear_headers 'X-Request-Id'; more_clear_headers 'X-Runtime'; more_set_headers 'Server: nginx'; {% endif %} + +gzip_types {{nginx_gzip_types}}; diff --git a/nginx/passenger/templates/site.conf.j2 b/nginx/passenger/templates/site.conf.j2 index 4b26ff7..15ab238 100644 --- a/nginx/passenger/templates/site.conf.j2 +++ b/nginx/passenger/templates/site.conf.j2 @@ -12,10 +12,10 @@ server { # {% endif %} gzip on; - client_max_body_size 200M; + client_max_body_size {{nginx_max_body_size}}; root {{RAILS_APP_CURRENT_PATH}}/public; - {% for key,value in passenger_variables.iteritems() %} + {% for key,value in passenger_variables.items() | list %} {{key}} {{value}}; {% endfor %} @@ -24,9 +24,11 @@ server { add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; gzip on; + # enable delivery of prebuilt .gz files + gzip_static on; } - location ~ ^/(system|uploads)/ { + location ~ {{nginx_public_folder_to_cache}} { expires 7d; add_header Pragma public; add_header Cache-Control "public"; @@ -49,5 +51,23 @@ server { passenger_enabled on; } + {% if passenger_enable_message_bus is defined and passenger_enable_message_bus %} + # improve message_bus performance https://github.com/SamSaffron/message_bus#passenger + location /message-bus { + passenger_app_group_name {{app_name}}_websocket; + passenger_force_max_concurrent_requests_per_process 0; + } + {% endif %} + {% if passenger_enable_action_cable is defined and passenger_enable_action_cable %} + location /cable { + passenger_app_group_name {{app_name}}_cable; + passenger_force_max_concurrent_requests_per_process 0; + } + {% endif %} + + {% if nginx_site_config is defined %} + {{ nginx_site_config }} + {% endif %} } +# vim: ft=nginx