rails-nginx 1.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 15c1730eca41e2227f246633756a27130a5e4c5bf87796a9a88893357be441a4
4
+ data.tar.gz: a372053d911522bf503522ebed38b8a2605bd91032541210a5ffd8092d02d88d
5
+ SHA512:
6
+ metadata.gz: 83d060932d2b1c76be3081b280525e893f918e0d10350827e67add23352d0c0da1eb25a8d2ccfb7c3e47626154b4199000ef0913a0744952f5696b78b09f86f4
7
+ data.tar.gz: a4314d08cbb951387f5a20420187f91916f841aa355752e55180c11e2a66fd3e5042a6124630ab44302d0e8cfafeb02c3bbc0af6795af53fd384a625b3704f4b
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ ## [Unreleased]
2
+
3
+ ## [1.0.0-alpha] - 2024-11-21
4
+
5
+ - Initial release
6
+ - Added configuration delegation to ruby-nginx.
7
+ - Added Puma plugin.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Bert McCutchen
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.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Rails NGINX
2
+
3
+ Automatically configure NGINX with SSL upon boot for Rails applications.
4
+
5
+ 1. ERB for NGINX configuration templating.
6
+ 2. Mkcert for SSL certificate generation.
7
+ 3. Tried and true NGINX for reverse proxying.
8
+
9
+ This gem is intended to be an aid to your development environment. **Don't use this in production.**
10
+
11
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/M4M76DVZR)
12
+
13
+ ## Installation
14
+
15
+ Install via Bundler:
16
+ ```bash
17
+ bundle add rails-nginx
18
+ ```
19
+
20
+ Or install it manually:
21
+ ```bash
22
+ gem install rails-nginx
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### config/puma.rb
28
+ ```ruby
29
+ port ENV.fetch('PORT') { 3000 } unless Rails.env.development?
30
+
31
+ plugin :rails_nginx if Rails.env.development?
32
+
33
+ # All configuration is entirely optional, the following blocks are not required.
34
+ rails_nginx_config(:primary) do |config|
35
+ config[:domain] = 'route1.spline-reticulator.test' # default eg. rails-app-name.test
36
+ config[:host] = '0.0.0.0' # default '127.0.0.1'
37
+ config[:root_path] = './public' # default `Rails.public_path`
38
+ config[:ssl] = false # default true
39
+ config[:log] = false # default true
40
+
41
+ # default location Rails.root + tmp/nginx/
42
+ config[:ssl_certificate_path] = './tmp/certs/_spline-reticulator.test.pem'
43
+ config[:ssl_certificate_key_path] = './tmp/certs/_spline-reticulator-key.test.pem'
44
+
45
+ # default location Rails.root + log/nginx/
46
+ config[:access_log_path] = './log/route1.nginx.access.log'
47
+ config[:error_log_path] = './log/route1.nginx.error.log'
48
+ end
49
+
50
+ # You can define multiple configurations and all will be created on puma boot.
51
+ rails_nginx_config(:secondary) do |config|
52
+ config.merge!(rails_nginx_config(:primary))
53
+
54
+ config[:domain] = 'route2.spline-reticulator.test'
55
+ config[:access_log_path] = './log/route2.nginx.access.log'
56
+ config[:error_log_path] = './log/route2.nginx.error.log'
57
+ end
58
+ ```
59
+
60
+ ## Development
61
+
62
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
63
+
64
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
65
+
66
+ ## Contributing
67
+
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bert-mccutchen/rails-nginx.
69
+
70
+ ## License
71
+
72
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "puma/plugin"
4
+ require_relative "../../rails/nginx"
5
+
6
+ # The Puma team recommends this approach to extend the Puma DSL.
7
+ # @see https://github.com/puma/puma/discussions/3173
8
+ module Puma
9
+ class DSL
10
+ def rails_nginx_configs
11
+ @rails_nginx_configs ||= {}
12
+ end
13
+
14
+ def rails_nginx_config(name = :primary)
15
+ rails_nginx_configs[name] ||= {}
16
+ yield rails_nginx_configs[name] if block_given?
17
+ rails_nginx_configs[name]
18
+ end
19
+ end
20
+ end
21
+
22
+ # The Rails server command's port will override ENV['PORT'] out of the box.
23
+ # However, Rails itself does not reasign back to ENV['PORT'].
24
+ def rails_port!
25
+ rails_port = Rails::Command::ServerCommand.new([], ARGV).options[:port]
26
+ ENV["PORT"] = rails_port.to_s if rails_port
27
+ end
28
+
29
+ Puma::Plugin.create do
30
+ def config(puma_config) # rubocop:disable Metrics/MethodLength
31
+ rails_port!
32
+
33
+ puma_config.port Rails::Nginx.port
34
+
35
+ puma_config.on_booted do
36
+ if puma_config.rails_nginx_configs.empty?
37
+ Rails::Nginx.start!
38
+ else
39
+ puma_config.rails_nginx_configs.each_value do |options|
40
+ Rails::Nginx.start!(options)
41
+ end
42
+ end
43
+ end
44
+
45
+ puma_config.on_restart do
46
+ if puma_config.rails_nginx_configs.empty?
47
+ Rails::Nginx.stop!
48
+ Rails::Nginx.start!
49
+ else
50
+ puma_config.rails_nginx_configs.each_value do |options|
51
+ Rails::Nginx.stop!(options)
52
+ Rails::Nginx.start!(options)
53
+ end
54
+ end
55
+ end
56
+
57
+ if defined?(puma_config.on_stopped) # rubocop:disable Style/GuardClause
58
+ puma_config.on_stopped do
59
+ if puma_config.rails_nginx_configs.empty?
60
+ Rails::Nginx.stop!
61
+ else
62
+ puma_config.rails_nginx_configs.each_value do |options|
63
+ Rails::Nginx.stop!(options)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,104 @@
1
+ # Generic and NGINX configuration file for a Rails application.
2
+ # https://www.digitalocean.com/community/tools/nginx
3
+
4
+ map $http_upgrade $connection_upgrade {
5
+ default upgrade;
6
+ '' close;
7
+ }
8
+
9
+ map $remote_addr $proxy_forwarded_elem {
10
+ # IPv4 addresses can be sent as-is
11
+ ~^[0-9.]+$ "for=$remote_addr";
12
+
13
+ # IPv6 addresses need to be bracketed and quoted
14
+ ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\"";
15
+
16
+ # Unix domain socket names cannot be represented in RFC 7239 syntax
17
+ default "for=unknown";
18
+ }
19
+
20
+ map $http_forwarded $proxy_add_forwarded {
21
+ # If the incoming Forwarded header is syntactically valid, append to it
22
+ "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem";
23
+
24
+ # Otherwise, replace it
25
+ default "$proxy_forwarded_elem";
26
+ }
27
+
28
+ upstream <%= name %> {
29
+ server 127.0.0.1:<%= options[:port] %> fail_timeout=0;
30
+ }
31
+
32
+ server {
33
+ listen 80;
34
+ server_name <%= options[:domain] %>;
35
+ root <%= options[:root_path] %>;
36
+ try_files $uri/index.html $uri @<%= name %>;
37
+
38
+ <% if options[:ssl] %>
39
+ # ssl
40
+ listen 443 ssl;
41
+ http2 on;
42
+ ssl_certificate <%= options[:ssl_certificate_path] %>;
43
+ ssl_certificate_key <%= options[:ssl_certificate_key_path] %>;
44
+ <% end %>
45
+
46
+ <% if options[:log] %>
47
+ # logging
48
+ access_log <%= options[:access_log_path] %> combined buffer=512k flush=1m;
49
+ error_log <%= options[:error_log_path] %> warn;
50
+ <% end %>
51
+
52
+ # ect.
53
+ large_client_header_buffers 4 16k;
54
+ client_max_body_size 4G;
55
+ keepalive_timeout 75s;
56
+
57
+ # reverse proxy
58
+ location @<%= name %> {
59
+ proxy_pass http://<%= name %>;
60
+ proxy_http_version 1.1;
61
+ proxy_cache_bypass $http_upgrade;
62
+
63
+ <% if options[:ssl] %>
64
+ # proxy SSL
65
+ proxy_ssl_server_name on;
66
+ <% end %>
67
+
68
+ # proxy headers
69
+ proxy_set_header Host $host;
70
+ proxy_set_header Upgrade $http_upgrade;
71
+ proxy_set_header Connection $connection_upgrade;
72
+ proxy_set_header X-Real-IP $remote_addr;
73
+ proxy_set_header Forwarded $proxy_add_forwarded;
74
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
75
+ proxy_set_header X-Forwarded-Proto $scheme;
76
+ proxy_set_header X-Forwarded-Host $host;
77
+ proxy_set_header X-Forwarded-Port $server_port;
78
+ }
79
+
80
+ location ^~ /assets/ {
81
+ proxy_pass http://<%= name %>;
82
+ proxy_http_version 1.1;
83
+ proxy_cache_bypass $http_upgrade;
84
+
85
+ <% if options[:ssl] %>
86
+ # proxy SSL
87
+ proxy_ssl_server_name on;
88
+ <% end %>
89
+
90
+ # proxy headers
91
+ proxy_set_header Host $host;
92
+ proxy_set_header Upgrade $http_upgrade;
93
+ proxy_set_header Connection $connection_upgrade;
94
+ proxy_set_header X-Real-IP $remote_addr;
95
+ proxy_set_header Forwarded $proxy_add_forwarded;
96
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
97
+ proxy_set_header X-Forwarded-Proto $scheme;
98
+ proxy_set_header X-Forwarded-Host $host;
99
+ proxy_set_header X-Forwarded-Port $server_port;
100
+
101
+ add_header Cache-Control public;
102
+ add_header Access-Control-Allow-Origin *;
103
+ }
104
+ }
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Nginx
5
+ VERSION = "1.0.0-alpha"
6
+ end
7
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "ruby/nginx"
5
+
6
+ module Rails
7
+ module Nginx
8
+ class Error < StandardError; end
9
+
10
+ def self.port
11
+ ENV["PORT"] ||= Addrinfo.tcp("127.0.0.1", 0).bind { |s| s.local_address.ip_port }.to_s
12
+ end
13
+
14
+ def self.start!(options = {}, &block)
15
+ return unless rails_server?
16
+
17
+ config = Ruby::Nginx.add!(options.reverse_merge(defaults(options)), &block)
18
+
19
+ puts start_message(config.options) # rubocop:disable Rails/Output
20
+ end
21
+
22
+ def self.stop!(options = {}, &block)
23
+ return unless rails_server?
24
+
25
+ Ruby::Nginx.remove!(options.reverse_merge(defaults(options)), &block)
26
+ end
27
+
28
+ private
29
+
30
+ def self.rails_server?
31
+ defined?(Rails::Server)
32
+ end
33
+ private_class_method :rails_server?
34
+
35
+ def self.defaults(options)
36
+ domain = options[:domain] || "#{Rails.application.class.module_parent.name.underscore.dasherize}.test"
37
+
38
+ {
39
+ domain: domain,
40
+ port: port,
41
+ root_path: Rails.public_path,
42
+ ssl: true,
43
+ log: true,
44
+ ssl_certificate_path: Rails.root.join("tmp/nginx/_#{domain}.pem"),
45
+ ssl_certificate_key_path: Rails.root.join("tmp/nginx/_#{domain}-key.pem"),
46
+ access_log_path: Rails.root.join("log/nginx/#{domain}.access.log"),
47
+ error_log_path: Rails.root.join("log/nginx/#{domain}.error.log")
48
+ }
49
+ end
50
+ private_class_method :defaults
51
+
52
+ def self.start_message(config)
53
+ message = ["* Rails NGINX version: #{Rails::Nginx::VERSION}"]
54
+ message << "* HTTP Endpoint: http://#{config[:domain]}"
55
+ message << "* HTTPS Endpoint: https://#{config[:domain]}" if config[:ssl]
56
+ message << "* Access Log: #{config[:access_log_path]}" if config[:log]
57
+ message << "* Error Log: #{config[:error_log_path]}" if config[:log]
58
+ message << "* Upstreaming to http://#{config[:host]}:#{config[:port]}"
59
+ message.join("\n")
60
+ end
61
+ private_class_method :start_message
62
+ end
63
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-nginx
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Bert McCutchen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: puma
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-nginx
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Automatically configure NGINX with SSL upon boot for Rails applications.
56
+ email:
57
+ - mail@bertm.dev
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - LICENSE.txt
64
+ - README.md
65
+ - lib/puma/plugin/rails_nginx.rb
66
+ - lib/rails/nginx.rb
67
+ - lib/rails/nginx/nginx.conf.erb
68
+ - lib/rails/nginx/version.rb
69
+ homepage: https://github.com/bert-mccutchen/rails-nginx
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ homepage_uri: https://github.com/bert-mccutchen/rails-nginx
74
+ source_code_uri: https://github.com/bert-mccutchen/rails-nginx
75
+ changelog_uri: https://github.com/bert-mccutchen/rails-nginx/blob/main/CHANGELOG.md
76
+ rubygems_mfa_required: 'true'
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 3.0.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.5.22
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Automatic NGINX+SSL configuration for Rails.
96
+ test_files: []