passenger 6.0.6 → 6.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +28 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/CONTRIBUTORS +2 -0
  5. data/bin/passenger-memory-stats +65 -12
  6. data/passenger.gemspec +1 -1
  7. data/resources/templates/error_renderer/with_details/dist/bundle.js +1 -1
  8. data/resources/templates/error_renderer/with_details/src/GetHelpView.jsx +1 -1
  9. data/resources/templates/standalone/rails_asset_pipeline.erb +1 -1
  10. data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +1 -0
  11. data/src/agent/Core/ApplicationPool/Implementation.cpp +0 -1
  12. data/src/agent/Core/ApplicationPool/Options.h +9 -0
  13. data/src/agent/Core/Config.h +2 -1
  14. data/src/agent/Core/Controller/Config.h +5 -1
  15. data/src/agent/Core/Controller/InitRequest.cpp +2 -0
  16. data/src/agent/Core/SpawningKit/Config.h +11 -0
  17. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h +13 -0
  18. data/src/agent/Core/SpawningKit/Spawner.h +1 -0
  19. data/src/agent/Watchdog/Config.h +2 -1
  20. data/src/apache2_module/Config.cpp +1 -1
  21. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +10 -0
  22. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +10 -0
  23. data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +25 -0
  24. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +10 -0
  25. data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +6 -0
  26. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +26 -0
  27. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +14 -0
  28. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +34 -0
  29. data/src/cxx_supportlib/Constants.h +3 -2
  30. data/src/cxx_supportlib/Hooks.h +1 -0
  31. data/src/cxx_supportlib/vendor-modified/modp_b64_data.h +0 -4
  32. data/src/cxx_supportlib/vendor-modified/modp_b64_strict_aliasing.cpp +5 -1
  33. data/src/helper-scripts/node-loader.js +1 -1
  34. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +8 -0
  35. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +7 -0
  36. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +12 -0
  37. data/src/nginx_module/Configuration.c +1 -1
  38. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +6 -0
  39. data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +15 -0
  40. data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +14 -0
  41. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +3 -0
  42. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +4 -0
  43. data/src/nginx_module/ngx_http_passenger_module.c +2 -2
  44. data/src/ruby_supportlib/phusion_passenger.rb +2 -2
  45. data/src/ruby_supportlib/phusion_passenger/admin_tools/memory_stats.rb +1 -1
  46. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +6 -0
  47. data/src/ruby_supportlib/phusion_passenger/constants.rb +2 -1
  48. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +5 -1
  49. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +6 -0
  50. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +1 -1
  51. data/src/ruby_supportlib/phusion_passenger/request_handler.rb +7 -6
  52. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +7 -0
  53. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +2 -2
  54. metadata +3 -3
@@ -280,6 +280,13 @@ set_manifest_autogenerated_app_conf_defaults(manifest_gen_ctx_t *ctx, PsgJsonVal
280
280
  "'smart' for Ruby apps, 'direct' for all other apps",
281
281
  sizeof("'smart' for Ruby apps, 'direct' for all other apps") - 1);
282
282
 
283
+ add_manifest_options_container_static_default_str(ctx,
284
+ options_container,
285
+ "passenger_direct_instance_request_address",
286
+ sizeof("passenger_direct_instance_request_address") - 1,
287
+ "127.0.0.1",
288
+ sizeof("127.0.0.1") - 1);
289
+
283
290
  add_manifest_options_container_static_default_bool(ctx,
284
291
  options_container,
285
292
  "passenger_load_shell_envvars",
@@ -685,6 +685,18 @@ passenger_conf_set_spawn_method(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
685
685
  return ngx_conf_set_str_slot(cf, cmd, conf);
686
686
  }
687
687
 
688
+ static char *
689
+ passenger_conf_set_direct_instance_request_address(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
690
+ passenger_loc_conf_t *passenger_conf = conf;
691
+
692
+ passenger_conf->autogenerated.direct_instance_request_address_explicitly_set = 1;
693
+ record_loc_conf_source_location(cf, passenger_conf,
694
+ &passenger_conf->autogenerated.direct_instance_request_address_source_file,
695
+ &passenger_conf->autogenerated.direct_instance_request_address_source_line);
696
+
697
+ return ngx_conf_set_str_slot(cf, cmd, conf);
698
+ }
699
+
688
700
  static char *
689
701
  passenger_conf_set_load_shell_envvars(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
690
702
  passenger_loc_conf_t *passenger_conf = conf;
@@ -1095,7 +1095,7 @@ static char *
1095
1095
  passenger_enterprise_only(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
1096
1096
  return ": this feature is only available in Phusion Passenger Enterprise. "
1097
1097
  "You are currently running the open source Phusion Passenger. "
1098
- "Please learn more about and/or buy Phusion Passenger Enterprise at https://www.phusionpassenger.com/enterprise ;";
1098
+ "Please learn more about and/or buy Phusion Passenger Enterprise at https://www.phusionpassenger.com/features#premium-features ;";
1099
1099
  }
1100
1100
  #endif
1101
1101
 
@@ -69,6 +69,8 @@ passenger_create_autogenerated_loc_conf(passenger_autogenerated_loc_conf_t *con
69
69
  conf->env_vars = NULL;
70
70
  conf->spawn_method.data = NULL;
71
71
  conf->spawn_method.len = 0;
72
+ conf->direct_instance_request_address.data = NULL;
73
+ conf->direct_instance_request_address.len = 0;
72
74
  conf->load_shell_envvars = NGX_CONF_UNSET;
73
75
  conf->max_request_queue_size = NGX_CONF_UNSET_UINT;
74
76
  conf->app_type.data = NULL;
@@ -172,6 +174,10 @@ passenger_create_autogenerated_loc_conf(passenger_autogenerated_loc_conf_t *con
172
174
  conf->spawn_method_source_file.len = 0;
173
175
  conf->spawn_method_source_line = 0;
174
176
  conf->spawn_method_explicitly_set = 0;
177
+ conf->direct_instance_request_address_source_file.data = NULL;
178
+ conf->direct_instance_request_address_source_file.len = 0;
179
+ conf->direct_instance_request_address_source_line = 0;
180
+ conf->direct_instance_request_address_explicitly_set = 0;
175
181
  conf->load_shell_envvars_source_file.data = NULL;
176
182
  conf->load_shell_envvars_source_file.len = 0;
177
183
  conf->load_shell_envvars_source_line = 0;
@@ -159,6 +159,12 @@ passenger_serialize_autogenerated_loc_conf_to_headers(ngx_conf_t *cf, passenger_
159
159
  len += sizeof("\r\n") - 1;
160
160
  }
161
161
 
162
+ if (conf->autogenerated.direct_instance_request_address.data != NULL) {
163
+ len += sizeof("!~PASSENGER_DIRECT_INSTANCE_REQUEST_ADDRESS: ") - 1;
164
+ len += conf->autogenerated.direct_instance_request_address.len;
165
+ len += sizeof("\r\n") - 1;
166
+ }
167
+
162
168
  if (conf->autogenerated.load_shell_envvars != NGX_CONF_UNSET) {
163
169
  len += sizeof("!~PASSENGER_LOAD_SHELL_ENVVARS: ") - 1;
164
170
  len += conf->autogenerated.load_shell_envvars
@@ -417,6 +423,15 @@ passenger_serialize_autogenerated_loc_conf_to_headers(ngx_conf_t *cf, passenger_
417
423
  conf->autogenerated.spawn_method.len);
418
424
  pos = ngx_copy(pos, (const u_char *) "\r\n", sizeof("\r\n") - 1);
419
425
  }
426
+ if (conf->autogenerated.direct_instance_request_address.data != NULL) {
427
+ pos = ngx_copy(pos,
428
+ "!~PASSENGER_DIRECT_INSTANCE_REQUEST_ADDRESS: ",
429
+ sizeof("!~PASSENGER_DIRECT_INSTANCE_REQUEST_ADDRESS: ") - 1);
430
+ pos = ngx_copy(pos,
431
+ conf->autogenerated.direct_instance_request_address.data,
432
+ conf->autogenerated.direct_instance_request_address.len);
433
+ pos = ngx_copy(pos, (const u_char *) "\r\n", sizeof("\r\n") - 1);
434
+ }
420
435
  if (conf->autogenerated.load_shell_envvars != NGX_CONF_UNSET) {
421
436
  pos = ngx_copy(pos,
422
437
  "!~PASSENGER_LOAD_SHELL_ENVVARS: ",
@@ -291,6 +291,20 @@ generate_config_manifest_for_autogenerated_loc_conf(manifest_gen_ctx_t *ctx, pas
291
291
  (const char *) plcf->autogenerated.spawn_method.data,
292
292
  plcf->autogenerated.spawn_method.len);
293
293
  }
294
+ if (plcf->autogenerated.direct_instance_request_address_explicitly_set) {
295
+ find_or_create_manifest_app_and_loc_options_containers(ctx,
296
+ plcf, cscf, clcf, &app_options_container, &loc_options_container);
297
+ option_container = find_or_create_manifest_option_container(ctx,
298
+ app_options_container,
299
+ "passenger_direct_instance_request_address",
300
+ sizeof("passenger_direct_instance_request_address") - 1);
301
+ hierarchy_member = add_manifest_option_container_hierarchy_member(option_container,
302
+ &plcf->autogenerated.direct_instance_request_address_source_file,
303
+ plcf->autogenerated.direct_instance_request_address_source_line);
304
+ psg_json_value_set_str(hierarchy_member, "value",
305
+ (const char *) plcf->autogenerated.direct_instance_request_address.data,
306
+ plcf->autogenerated.direct_instance_request_address.len);
307
+ }
294
308
  if (plcf->autogenerated.load_shell_envvars_explicitly_set) {
295
309
  find_or_create_manifest_app_and_loc_options_containers(ctx,
296
310
  plcf, cscf, clcf, &app_options_container, &loc_options_container);
@@ -101,6 +101,9 @@ passenger_merge_autogenerated_loc_conf(passenger_autogenerated_loc_conf_t *conf,
101
101
  ngx_conf_merge_str_value(conf->spawn_method,
102
102
  prev->spawn_method,
103
103
  NULL);
104
+ ngx_conf_merge_str_value(conf->direct_instance_request_address,
105
+ prev->direct_instance_request_address,
106
+ "127.0.0.1");
104
107
  ngx_conf_merge_value(conf->load_shell_envvars,
105
108
  prev->load_shell_envvars,
106
109
  1);
@@ -65,6 +65,7 @@ typedef struct {
65
65
  ngx_str_t app_root;
66
66
  ngx_str_t app_start_command;
67
67
  ngx_str_t app_type;
68
+ ngx_str_t direct_instance_request_address;
68
69
  ngx_str_t document_root;
69
70
  ngx_str_t environment;
70
71
  ngx_str_t group;
@@ -90,6 +91,7 @@ typedef struct {
90
91
  ngx_str_t base_uris_source_file;
91
92
  ngx_str_t buffer_upload_source_file;
92
93
  ngx_str_t debugger_source_file;
94
+ ngx_str_t direct_instance_request_address_source_file;
93
95
  ngx_str_t document_root_source_file;
94
96
  ngx_str_t enabled_source_file;
95
97
  ngx_str_t env_vars_source_file;
@@ -142,6 +144,7 @@ typedef struct {
142
144
  ngx_uint_t base_uris_source_line;
143
145
  ngx_uint_t buffer_upload_source_line;
144
146
  ngx_uint_t debugger_source_line;
147
+ ngx_uint_t direct_instance_request_address_source_line;
145
148
  ngx_uint_t document_root_source_line;
146
149
  ngx_uint_t enabled_source_line;
147
150
  ngx_uint_t env_vars_source_line;
@@ -194,6 +197,7 @@ typedef struct {
194
197
  ngx_int_t base_uris_explicitly_set;
195
198
  ngx_int_t buffer_upload_explicitly_set;
196
199
  ngx_int_t debugger_explicitly_set;
200
+ ngx_int_t direct_instance_request_address_explicitly_set;
197
201
  ngx_int_t document_root_explicitly_set;
198
202
  ngx_int_t enabled_explicitly_set;
199
203
  ngx_int_t env_vars_explicitly_set;
@@ -43,9 +43,9 @@
43
43
 
44
44
  #define MODP_B64_DONT_INCLUDE_BOOST_ENDIANNESS_HEADERS
45
45
  #if NGX_HAVE_LITTLE_ENDIAN
46
- #define BOOST_LITTLE_ENDIAN
46
+ #define BOOST_ENDIAN_LITTLE_BYTE
47
47
  #else
48
- #define BOOST_BIG_ENDIAN
48
+ #define BOOST_ENDIAN_BIG_BYTE
49
49
  #endif
50
50
 
51
51
  #include "ngx_http_passenger_module.h"
@@ -31,7 +31,7 @@ module PhusionPassenger
31
31
 
32
32
  PACKAGE_NAME = 'passenger'
33
33
  # Run 'rake src/cxx_supportlib/Constants.h configkit_schemas_inline_comments' after changing this number.
34
- VERSION_STRING = '6.0.6'
34
+ VERSION_STRING = '6.0.7'
35
35
 
36
36
  # Tip: find the SHA-256 with ./dev/nginx_version_sha2 <VERSION>
37
37
  PREFERRED_NGINX_VERSION = '1.18.0'
@@ -258,7 +258,7 @@ module PhusionPassenger
258
258
  end
259
259
 
260
260
 
261
- private
261
+ private
262
262
  def self.infer_install_spec
263
263
  filename = ENV['PASSENGER_LOCATION_CONFIGURATION_FILE']
264
264
  return filename if filename && !filename.empty?
@@ -294,7 +294,7 @@ module PhusionPassenger
294
294
  else
295
295
  return total
296
296
  end
297
- rescue Errno::EACCES, Errno::ENOENT
297
+ rescue Errno::EACCES, Errno::ENOENT, Errno::ESRCH
298
298
  return nil
299
299
  end
300
300
 
@@ -444,6 +444,12 @@ APACHE2_CONFIGURATION_OPTIONS = [
444
444
  :desc => 'The spawn method to use.',
445
445
  :function => 'cmd_passenger_spawn_method'
446
446
  },
447
+ {
448
+ :name => 'PassengerDirectInstanceRequestAddress',
449
+ :type => :string,
450
+ :default => DEFAULT_BIND_ADDRESS,
451
+ :desc => 'The address that Passenger binds to in order to allow sending HTTP requests to individual application processes.'
452
+ },
447
453
  {
448
454
  :name => 'PassengerFriendlyErrorPages',
449
455
  :type => :flag,
@@ -58,6 +58,7 @@ module PhusionPassenger
58
58
  DEFAULT_WEB_APP_USER = "nobody"
59
59
  DEFAULT_APP_ENV = "production"
60
60
  DEFAULT_SPAWN_METHOD = "smart"
61
+ DEFAULT_BIND_ADDRESS = "127.0.0.1"
61
62
  # Apache's unixd.h also defines DEFAULT_USER, so we avoid naming clash here.
62
63
  PASSENGER_DEFAULT_USER = "nobody"
63
64
  DEFAULT_CONCURRENCY_MODEL = "process"
@@ -116,7 +117,7 @@ module PhusionPassenger
116
117
  PROGRAM_WEBSITE = "https://www.phusionpassenger.com"
117
118
  PROGRAM_AUTHOR = "Phusion"
118
119
  SUPPORT_URL = "https://www.phusionpassenger.com/support"
119
- ENTERPRISE_URL = "https://www.phusionpassenger.com/enterprise"
120
+ ENTERPRISE_URL = "https://www.phusionpassenger.com/features#premium-features"
120
121
  GLOBAL_NAMESPACE_DIRNAME = PhusionPassenger::GLOBAL_NAMESPACE_DIRNAME_
121
122
  # Subdirectory under $HOME to use for storing stuff.
122
123
  USER_NAMESPACE_DIRNAME = PhusionPassenger::USER_NAMESPACE_DIRNAME_
@@ -317,7 +317,11 @@ module PhusionPassenger
317
317
  elsif ActiveRecord::Base.respond_to?(:clear_active_connections!)
318
318
  ActiveRecord::Base.clear_active_connections!
319
319
  end
320
- ActiveRecord::Base.establish_connection
320
+ begin
321
+ ActiveRecord::Base.establish_connection
322
+ rescue
323
+ DebugLogging.debug('ActiveRecord is not configured, start it yourself')
324
+ end
321
325
  end
322
326
 
323
327
  # Fire off events.
@@ -476,6 +476,12 @@ NGINX_CONFIGURATION_OPTIONS = [
476
476
  :dynamic_default => "'smart' for Ruby apps, 'direct' for all other apps",
477
477
  :type => :string
478
478
  },
479
+ {
480
+ :name => 'passenger_direct_instance_request_address',
481
+ :scope => :application,
482
+ :default => DEFAULT_BIND_ADDRESS,
483
+ :type => :string
484
+ },
479
485
  {
480
486
  :name => 'passenger_load_shell_envvars',
481
487
  :scope => :application,
@@ -890,7 +890,7 @@ module PhusionPassenger
890
890
  # On macOS >= 10.13 High Sierra /usr/include no longer
891
891
  # exists.
892
892
  xcode_prefix = `/usr/bin/xcode-select -p`.strip
893
- ["-I#{xcode_prefix}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/apr-1" \
893
+ ["-I#{xcode_prefix}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/apr-1 " \
894
894
  "-I#{xcode_prefix}/SDKs/MacOSX.sdk/usr/include/apr-1",
895
895
  '-laprutil-1']
896
896
  else
@@ -99,7 +99,7 @@ module PhusionPassenger
99
99
  if should_use_unix_sockets?
100
100
  @main_socket_address, @main_socket = create_unix_socket_on_filesystem(options)
101
101
  else
102
- @main_socket_address, @main_socket = create_tcp_socket
102
+ @main_socket_address, @main_socket = create_tcp_socket(options)
103
103
  end
104
104
  @server_sockets[:main] = {
105
105
  :address => @main_socket_address,
@@ -109,7 +109,7 @@ module PhusionPassenger
109
109
  :accept_http_requests => true
110
110
  }
111
111
 
112
- @http_socket_address, @http_socket = create_tcp_socket
112
+ @http_socket_address, @http_socket = create_tcp_socket(options)
113
113
  @server_sockets[:http] = {
114
114
  :address => @http_socket_address,
115
115
  :socket => @http_socket,
@@ -309,16 +309,17 @@ module PhusionPassenger
309
309
  end
310
310
  end
311
311
 
312
- def create_tcp_socket
313
- # We use "0.0.0.0" as address in order to force
312
+ def create_tcp_socket(options)
313
+ # We default to "127.0.0.1" as address in order to force
314
314
  # TCPv4 instead of TCPv6.
315
- socket = TCPServer.new('0.0.0.0', 0)
315
+ bind_address = options.fetch('bind_address', '127.0.0.1')
316
+ socket = TCPServer.new(bind_address, 0)
316
317
  socket.listen(BACKLOG_SIZE)
317
318
  socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
318
319
  socket.binmode
319
320
  socket.sync = true
320
321
  socket.close_on_exec!
321
- socket_address = "tcp://127.0.0.1:#{socket.addr[1]}"
322
+ socket_address = "tcp://#{bind_address}:#{socket.addr[1]}"
322
323
  return [socket_address, socket]
323
324
  end
324
325
 
@@ -258,6 +258,13 @@ module PhusionPassenger
258
258
  :default => PlatformInfo.ruby_supports_fork? ? DEFAULT_SPAWN_METHOD : 'direct',
259
259
  :desc => 'The spawn method to use. Default: see docs'
260
260
  },
261
+ {
262
+ :name => :direct_instance_request_address,
263
+ :type => :hostname,
264
+ :type_desc => 'HOST',
265
+ :default => '127.0.0.1',
266
+ :desc => "The address that Passenger binds to in order to allow sending HTTP requests to individual application processes.\nDefault: %DEFAULT%"
267
+ },
261
268
  {
262
269
  :name => :static_files_dir,
263
270
  :type => :path,
@@ -231,7 +231,7 @@ module PhusionPassenger
231
231
  abort "The '#{option_name}' feature is only available in #{PROGRAM_NAME} " +
232
232
  "Enterprise. You are currently running the open source #{PROGRAM_NAME}. " +
233
233
  "Please learn more about and/or buy #{PROGRAM_NAME} Enterprise at " +
234
- "https://www.phusionpassenger.com/enterprise"
234
+ "https://www.phusionpassenger.com/features#premium-features"
235
235
  end
236
236
  end
237
237
 
@@ -240,7 +240,7 @@ module PhusionPassenger
240
240
  abort "The '#{option_name}' feature is only available in #{PROGRAM_NAME} " +
241
241
  "Enterprise. You are currently running the open source #{PROGRAM_NAME}. " +
242
242
  "Please learn more about and/or buy #{PROGRAM_NAME} Enterprise at " +
243
- "https://www.phusionpassenger.com/enterprise"
243
+ "https://www.phusionpassenger.com/features#premium-features"
244
244
  end
245
245
  end
246
246
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passenger
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.6
4
+ version: 6.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phusion - http://www.phusion.nl/
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-14 00:00:00.000000000 Z
11
+ date: 2020-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -4445,7 +4445,7 @@ homepage: https://www.phusionpassenger.com/
4445
4445
  licenses: []
4446
4446
  metadata:
4447
4447
  bug_tracker_uri: https://github.com/phusion/passenger/issues
4448
- changelog_uri: https://github.com/phusion/passenger/blob/stable-6.0.6/CHANGELOG
4448
+ changelog_uri: https://github.com/phusion/passenger/blob/stable-6.0/CHANGELOG
4449
4449
  documentation_uri: https://www.phusionpassenger.com/docs/
4450
4450
  homepage_uri: https://www.phusionpassenger.com/
4451
4451
  source_code_uri: https://github.com/phusion/passenger