errorstudio_capistrano_recipes 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +29 -0
  9. data/Rakefile +1 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +7 -0
  12. data/errorstudio_capistrano_recipes.gemspec +34 -0
  13. data/lib/capistrano/errorstudio.rb +5 -0
  14. data/lib/capistrano/errorstudio/composer.rb +3 -0
  15. data/lib/capistrano/errorstudio/cron.rb +2 -0
  16. data/lib/capistrano/errorstudio/nginx.rb +2 -0
  17. data/lib/capistrano/errorstudio/ownership.rb +1 -0
  18. data/lib/capistrano/errorstudio/passenger.rb +2 -0
  19. data/lib/capistrano/errorstudio/prompts.rb +1 -0
  20. data/lib/capistrano/errorstudio/rails.rb +13 -0
  21. data/lib/capistrano/errorstudio/rvm.rb +4 -0
  22. data/lib/capistrano/errorstudio/static.rb +4 -0
  23. data/lib/capistrano/errorstudio/tasks/composer.rake +12 -0
  24. data/lib/capistrano/errorstudio/tasks/cron.rake +15 -0
  25. data/lib/capistrano/errorstudio/tasks/nginx.rake +198 -0
  26. data/lib/capistrano/errorstudio/tasks/ownership.rake +11 -0
  27. data/lib/capistrano/errorstudio/tasks/passenger.rake +76 -0
  28. data/lib/capistrano/errorstudio/tasks/prompts.rake +18 -0
  29. data/lib/capistrano/errorstudio/tasks/rails.rake +80 -0
  30. data/lib/capistrano/errorstudio/tasks/rvm.rake +49 -0
  31. data/lib/capistrano/errorstudio/tasks/static.rake +0 -0
  32. data/lib/capistrano/errorstudio/tasks/templates/nginx/basic_auth.erb +8 -0
  33. data/lib/capistrano/errorstudio/tasks/templates/nginx/cloudflare_real_ips.erb +4 -0
  34. data/lib/capistrano/errorstudio/tasks/templates/nginx/cors.erb +34 -0
  35. data/lib/capistrano/errorstudio/tasks/templates/nginx/custom_aliases.erb +5 -0
  36. data/lib/capistrano/errorstudio/tasks/templates/nginx/custom_rules.erb +3 -0
  37. data/lib/capistrano/errorstudio/tasks/templates/nginx/location_proxy_cache.erb +6 -0
  38. data/lib/capistrano/errorstudio/tasks/templates/nginx/nginx_vhost.conf.erb +84 -0
  39. data/lib/capistrano/errorstudio/tasks/templates/nginx/path_redirects.erb +5 -0
  40. data/lib/capistrano/errorstudio/tasks/templates/nginx/php.erb +27 -0
  41. data/lib/capistrano/errorstudio/tasks/templates/nginx/proxy_cache_path.erb +1 -0
  42. data/lib/capistrano/errorstudio/tasks/templates/nginx/redirects.erb +10 -0
  43. data/lib/capistrano/errorstudio/tasks/templates/nginx/rewrites.erb +7 -0
  44. data/lib/capistrano/errorstudio/tasks/templates/nginx/ssl_settings.erb +24 -0
  45. data/lib/capistrano/errorstudio/tasks/templates/nginx/upstream_proxy.erb +11 -0
  46. data/lib/capistrano/errorstudio/tasks/templates/passenger/passenger_init.erb +27 -0
  47. data/lib/capistrano/errorstudio/tasks/templates/rails/database.yml.erb +8 -0
  48. data/lib/capistrano/errorstudio/tasks/templates/rails/secrets.yml.erb +5 -0
  49. data/lib/capistrano/errorstudio/tasks/templates/wordpress/env.erb +23 -0
  50. data/lib/capistrano/errorstudio/tasks/wordpress.rake +158 -0
  51. data/lib/capistrano/errorstudio/wordpress.rb +12 -0
  52. data/lib/version.rb +3 -0
  53. metadata +209 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: de0bf29b0aca35349c3f21c4c3c4346803091736
4
+ data.tar.gz: 61af7fe8e700af6b21a4d1aa508191f3a9e186d1
5
+ SHA512:
6
+ metadata.gz: 91dd4b9af5f213cd8837db5c02d175928ee2156dcabe907dad6982e3a59616d1d7c06570cd42a67863fab539803772f517dd076575849a4ef17a385b6ac0e1a6
7
+ data.tar.gz: 082ffe378aa0e9c197152749fa3bf8327e225a43422d264256a9d19c1b1f8df9b6fa0a6e33d816174331d65b093d0d33e8834d7fdf21c8a533450fcda2d9ed85
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
@@ -0,0 +1 @@
1
+ errorstudio-capistrano-recipes
@@ -0,0 +1 @@
1
+ 2.4.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in errorstudio_capistrano_recipes.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Error Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Error Studio Capistrano Recipes
2
+
3
+ At [Error](https://error.agency) we like to deploy things with Capistrano. This is a selection of our scripts for deploying:
4
+
5
+ * Rails
6
+ * Wordpress (using the [Bedrock](https://roots.io/bedrock/) approach and composer)
7
+ * Static sites
8
+
9
+ There are some optional parts too:
10
+
11
+ * Nginx config with SSL
12
+ * RVM setup
13
+ * Phusion Passenger configuration
14
+ * Cron jobs
15
+
16
+
17
+ # Warning / Disclaimer
18
+ This is mostly an internal tool - you'll have to spelunk through the code to get a handle on all the options. In due course we'll document everything.
19
+
20
+ # Prerequisites
21
+ On the machine you're deploying from, you'll need:
22
+
23
+ * Ruby
24
+ * GPG 2 (for decrypting secret SSL keys locally)
25
+
26
+ # License
27
+ MIT - see LICENSE.txt
28
+
29
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "capistrano/errorstudio"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "errorstudio_capistrano_recipes"
8
+ spec.version = ErrorstudioCapistranoRecipes::VERSION
9
+ spec.authors = ["Ed Jones", "Paul Hendrick"]
10
+ spec.email = ["ed@error.agency", "paul@error.agency"]
11
+
12
+ spec.summary = %q{Error's cap recipes}
13
+ spec.description = %q{Cap recipes we use to deploy our websites.}
14
+ spec.homepage = "https://github.com/errorstudio/errorstudio_capistrano_recipes"
15
+ spec.license = "MIT"
16
+
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.10"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+
26
+ #production deps
27
+ spec.add_dependency 'capistrano', '~>3.11.0'
28
+ spec.add_dependency 'capistrano-composer', '>=0.0.6'
29
+ spec.add_dependency 'capistrano-bundler'
30
+ spec.add_dependency 'capistrano-rails'
31
+ # spec.add_dependency 'capistrano-rvm'
32
+ spec.add_dependency 'rvm1-capistrano3'
33
+ spec.add_dependency 'capistrano-passenger'
34
+ end
@@ -0,0 +1,5 @@
1
+ require 'capistrano/setup'
2
+ require 'capistrano/deploy'
3
+ require 'capistrano/errorstudio/ownership'
4
+ require 'capistrano/errorstudio/prompts'
5
+ set :deploy_to, ->{"/var/www/#{fetch(:deploy_domain)}"}
@@ -0,0 +1,3 @@
1
+ require 'capistrano/composer'
2
+ Rake::Task['deploy:updated'].prerequisites.delete('composer:install')
3
+ load File.expand_path("../tasks/composer.rake", __FILE__)
@@ -0,0 +1,2 @@
1
+ require 'capistrano/errorstudio'
2
+ load File.expand_path("../tasks/cron.rake", __FILE__)
@@ -0,0 +1,2 @@
1
+ require 'open-uri'
2
+ load File.expand_path("../tasks/nginx.rake", __FILE__)
@@ -0,0 +1 @@
1
+ load File.expand_path("../tasks/ownership.rake", __FILE__)
@@ -0,0 +1,2 @@
1
+ require 'capistrano/errorstudio/rvm'
2
+ load File.expand_path("../tasks/passenger.rake", __FILE__)
@@ -0,0 +1 @@
1
+ load File.expand_path("../tasks/prompts.rake", __FILE__)
@@ -0,0 +1,13 @@
1
+ require 'capistrano/errorstudio'
2
+ set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')
3
+ set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
4
+ set :upstream_proxy_required, true
5
+ set :upstream_proxy_port, -> {fetch(:passenger_port)}
6
+ set :upstream_proxy_cache, fetch(:upstream_proxy_cache, true)
7
+ require 'capistrano/rails'
8
+ require 'capistrano/rails/assets'
9
+ # require 'capistrano/rails/migrations'
10
+ require 'capistrano/errorstudio/nginx'
11
+ require 'capistrano/errorstudio/passenger'
12
+ require 'capistrano/errorstudio/rvm'
13
+ load File.expand_path("../tasks/rails.rake", __FILE__)
@@ -0,0 +1,4 @@
1
+ require 'rvm1/capistrano3'
2
+ require 'capistrano/bundler'
3
+
4
+ load File.expand_path("../tasks/rvm.rake", __FILE__)
@@ -0,0 +1,4 @@
1
+ require 'capistrano/errorstudio'
2
+ require 'capistrano/errorstudio/nginx'
3
+ load File.expand_path("../tasks/static.rake", __FILE__)
4
+
@@ -0,0 +1,12 @@
1
+ namespace :composer do
2
+ desc "Set paths for composer and invoke the installation of the composer executable"
3
+ task :set_paths_and_install do
4
+ set :composer_working_dir, ->{ File.join(release_path,"public")}
5
+ set :composer_install_flags, '--no-interaction --optimize-autoloader'
6
+ SSHKit.config.command_map[:composer] = "php #{shared_path.join("composer.phar")}"
7
+ invoke "composer:install_executable"
8
+ end
9
+ end
10
+
11
+ after "deploy:starting", 'composer:set_paths_and_install'
12
+ after "deploy:updated", "composer:install"
@@ -0,0 +1,15 @@
1
+ namespace :cron do
2
+ desc "Generate cron scripts"
3
+ task :generate_cron_scripts do
4
+ on roles(:web) do
5
+ fetch(:cron_scripts).each do |cron_time, files|
6
+ files.each do |cron_template|
7
+ buffer = ERB.new(File.read(cron_template)).result(binding)+"\n"
8
+ cron_filename = File.basename(cron_template).gsub(/\.sh\.erb$/, '')
9
+ upload! StringIO.new(buffer), "#{shared_path}/#{cron_time}.#{File.basename(cron_template)}"
10
+ execute "sudo mv -f #{shared_path}/#{cron_time}.#{File.basename(cron_template)} /etc/cron.#{cron_time}/#{cron_filename} && sudo chown root:root /etc/cron.#{cron_time}/#{cron_filename} && sudo chmod +x /etc/cron.#{cron_time}/#{cron_filename}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,198 @@
1
+ set :nginx_configuration, fetch(:nginx_configuration, {})
2
+ set :base_domain, ->{fetch(:base_domain,ask(:base_domain,nil))}
3
+ set :prelaunch_domain, ->{fetch(:prelaunch_domain,ask(:prelaunch_domain,nil))}
4
+ set :site_domains, ->{fetch(:site_domains,ask(:site_domains,nil))}
5
+ set :basic_auth_required, fetch(:basic_auth_required, false)
6
+ set :ssl_required, fetch(:ssl_required, false)
7
+ set :deploy_domain, ->{fetch(:deploy_domain,ask(:deploy_domain,nil))}
8
+
9
+ namespace :nginx do
10
+ desc "Check the config exists, and generate if it doesn't"
11
+ task :check_config do
12
+ set :nginx_sites_available, "/etc/nginx/sites-available/#{fetch(:deploy_domain)}"
13
+ set :nginx_sites_enabled, "/etc/nginx/sites-enabled/#{fetch(:deploy_domain)}"
14
+ on roles(:web) do
15
+ unless test("[ -f #{"/etc/nginx/sites-enabled/#{fetch(:deploy_domain)}"} ]")
16
+ invoke "nginx:generate_config"
17
+ end
18
+ end
19
+ end
20
+
21
+ desc "Generate an Nginx config from a template, with a few prerequisite tasks"
22
+ task :generate_config => [
23
+ :generate_ssl,
24
+ :generate_cloudflare_real_ips,
25
+ :generate_php,
26
+ :generate_upstream_proxy,
27
+ :generate_redirects,
28
+ :add_basic_auth,
29
+ :generate_rewrites,
30
+ :generate_custom_rules,
31
+ :generate_custom_aliases,
32
+ :generate_cors,
33
+ :generate_path_redirects,
34
+ :generate_proxy_cache
35
+ ] do
36
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "nginx_vhost.conf.erb")
37
+
38
+ buffer = ERB.new(File.read(file)).result(binding)
39
+ on roles(:web) do
40
+ upload! StringIO.new(buffer), "#{shared_path}/#{fetch(:deploy_domain)}"
41
+ execute "mv #{shared_path}/#{fetch(:deploy_domain)} #{"/etc/nginx/sites-available/#{fetch(:deploy_domain)}"}"
42
+ execute "ln -nfs #{"/etc/nginx/sites-available/#{fetch(:deploy_domain)}"} #{"/etc/nginx/sites-enabled/#{fetch(:deploy_domain)}"}"
43
+ invoke 'nginx:reload'
44
+ end
45
+ end
46
+
47
+ desc "Add basic auth to the nginx config"
48
+ task :add_basic_auth do
49
+ #set up the basic auth if the vars are defined
50
+ if fetch(:basic_auth_required, false)
51
+ set :basic_auth_realm, "Your username and password are required"
52
+ # set :basic_auth_username, ->{fetch(:basic_auth_username,ask(:basic_auth_username,nil))}
53
+ # set :basic_auth_password, ->{fetch(:basic_auth_password,ask(:basic_auth_password,nil))}
54
+ on roles :web do
55
+ encrypted_password = `openssl passwd -apr1 #{fetch(:basic_auth_password)}`
56
+ execute :echo, "'#{fetch(:basic_auth_username)}:#{encrypted_password.chomp}'", "> #{shared_path}/.htpasswd"
57
+ end
58
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "basic_auth.erb")
59
+ basic_auth = {basic_auth: ERB.new(File.read(file)).result(binding)}
60
+ set :nginx_configuration, fetch(:nginx_configuration).merge(basic_auth)
61
+ invoke "deploy:set_ownership"
62
+ end
63
+ end
64
+
65
+ desc "Reload Nginx"
66
+ task :reload do
67
+ on roles(:web) do
68
+ sudo "/usr/sbin/invoke-rc.d nginx reload"
69
+ end
70
+ end
71
+
72
+ desc "Generate CORS headers for nginx"
73
+ task :generate_cors do
74
+ if fetch(:include_nginx_cors, false)
75
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "cors.erb")
76
+ # generate a hash which is the content of the nginx redirects, with a key
77
+ cors = {cors: ERB.new(File.read(file)).result(binding)}
78
+ set :nginx_configuration, fetch(:nginx_configuration).merge(cors)
79
+ end
80
+ end
81
+
82
+ desc "Generate custom rules from a hash of rules. NB this is inside the main server block"
83
+ task :generate_custom_rules do
84
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "custom_rules.erb")
85
+ # generate a hash which is the content of the nginx redirects, with a key
86
+ rules = {custom_rules: ERB.new(File.read(file)).result(binding)}
87
+ set :nginx_configuration, fetch(:nginx_configuration).merge(rules)
88
+ end
89
+
90
+ desc "Generate custom aliases from a hash. NB this is inside the main server block"
91
+ task :generate_custom_aliases do
92
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "custom_aliases.erb")
93
+ # generate a hash which is the content of the nginx redirects, with a key
94
+ aliases = {custom_aliases: ERB.new(File.read(file)).result(binding)}
95
+ set :nginx_configuration, fetch(:nginx_configuration).merge(aliases)
96
+ end
97
+
98
+ desc "Generate 301 path redirects from a hash. NB this is inside the main server block"
99
+ task :generate_path_redirects do
100
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "path_redirects.erb")
101
+ # generate a hash which is the content of the nginx redirects, with a key
102
+ aliases = {path_redirects: ERB.new(File.read(file)).result(binding)}
103
+ set :nginx_configuration, fetch(:nginx_configuration).merge(aliases)
104
+ end
105
+
106
+ desc "Generate PHP-FPM proxy and headers"
107
+ task :generate_php => :generate_ssl do
108
+ if fetch(:php_required, false)
109
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "php.erb")
110
+ php = {php: ERB.new(File.read(file)).result(binding)}
111
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(php)
112
+ end
113
+ end
114
+
115
+ desc "Generate upstream proxy and headers"
116
+ task :generate_upstream_proxy => :generate_ssl do
117
+ if fetch(:upstream_proxy_required, false)
118
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "upstream_proxy.erb")
119
+ upstream = {upstream: ERB.new(File.read(file)).result(binding)}
120
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(upstream)
121
+ end
122
+ end
123
+
124
+ desc "Generate proxy cache settings"
125
+ task :generate_proxy_cache => :generate_upstream_proxy do
126
+ if fetch(:upstream_proxy_cache, false)
127
+ set :cache_zone, "#{fetch(:application)}_#{fetch(:stage)}"
128
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "proxy_cache_path.erb")
129
+ cache_path = {proxy_cache_path: ERB.new(File.read(file)).result(binding)}
130
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(cache_path)
131
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "location_proxy_cache.erb")
132
+ location_proxy_cache = {location_proxy_cache: ERB.new(File.read(file)).result(binding)}
133
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(location_proxy_cache)
134
+ end
135
+ end
136
+
137
+ desc "Generate redirects in separate server blocks"
138
+ task :generate_redirects => :generate_ssl do
139
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "redirects.erb")
140
+ # generate a hash which is the content of the nginx redirects, with a key
141
+ redirects = {domain_redirects: ERB.new(File.read(file)).result(binding)}
142
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(redirects)
143
+ end
144
+
145
+ desc "Generate rewrites"
146
+ task :generate_rewrites do
147
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "rewrites.erb")
148
+ rewrites = {url_rewrites: ERB.new(File.read(file)).result(binding)}
149
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(rewrites)
150
+ end
151
+
152
+ desc "Generate SSL settings from files in a specified location"
153
+ task :generate_ssl do
154
+ if fetch(:ssl_required, false)
155
+ set :ip_address, ->{fetch(:ip_address, ask(:ip_address,nil))}
156
+ set :ssl_cert_path, File.join(fetch(:ssl_dir), fetch(:ssl_cert))
157
+ set :ssl_key_path, File.join(fetch(:ssl_dir), fetch(:ssl_key))
158
+ set :ssl_dh_path, File.join(fetch(:ssl_dir), fetch(:ssl_dh))
159
+
160
+ unless File.exists?(fetch(:ssl_cert_path)) && File.exists?(fetch(:ssl_key_path)) & File.exists?(fetch(:ssl_dh_path))
161
+ puts "You need to put your SSL GPG-encrypted key, DH params and cert in the locations you've specified"
162
+ exit
163
+ end
164
+
165
+ set :gpg_phrase, ask("GPG passphrase for SSL key and DH:",nil)
166
+ set :ssl_path, "/etc/nginx/ssl"
167
+ key = `echo #{fetch(:gpg_phrase)} | gpg -d -q --batch --passphrase-fd 0 --no-mdc-warning #{fetch(:ssl_key_path)}`
168
+ dh = `echo #{fetch(:gpg_phrase)} | gpg -d -q --batch --passphrase-fd 0 --no-mdc-warning #{fetch(:ssl_dh_path)}`
169
+ set :certificate_sha256, `openssl x509 -in #{fetch(:ssl_cert_path)} -pubkey -noout | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -binary | openssl enc -base64`
170
+ if $?.success?
171
+ on roles(:web) do
172
+ upload! fetch(:ssl_cert_path), "#{fetch(:ssl_path)}/#{fetch(:deploy_domain)}.crt"
173
+ upload! StringIO.new(key), "#{fetch(:ssl_path)}/#{fetch(:deploy_domain)}.key"
174
+ upload! StringIO.new(dh), "#{fetch(:ssl_path)}/#{fetch(:deploy_domain)}.pem"
175
+ end
176
+ else
177
+ puts "Incorrect GPG passphrase"
178
+ exit
179
+ end
180
+
181
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "ssl_settings.erb")
182
+ ssl_settings = {ssl_settings: ERB.new(File.read(file)).result(binding)}
183
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(ssl_settings)
184
+ end
185
+ end
186
+
187
+ desc "Get a list of Cloudflare IPs, and set real ip from the header"
188
+ task :generate_cloudflare_real_ips do
189
+ ips = open("https://www.cloudflare.com/ips-v4/").read
190
+ set :cloudflare_real_ips, ips.gsub(/\<.*>/,"").split("\n")
191
+ file = File.join(File.dirname(__FILE__), "templates","nginx", "cloudflare_real_ips.erb")
192
+ cloudflare_ips = {cloudflare_real_ips: ERB.new(File.read(file)).result(binding)}
193
+ set :nginx_configuration, fetch(:nginx_configuration,{}).merge(cloudflare_ips)
194
+ end
195
+ end
196
+
197
+ after "deploy:check", "nginx:check_config"
198
+ after "nginx:generate_config", "nginx:reload"