diff --git a/config/application.rb b/config/application.rb
index 524827226e745a5445546132c725ce3ffe7143fa..47f8ca48d9185d61c1ebc120786a1be9c78a088e 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -17,6 +17,7 @@ module Gitlab
   class Application < Rails::Application
     require_dependency Rails.root.join('lib/gitlab')
     require_dependency Rails.root.join('lib/gitlab/utils')
+    require_dependency Rails.root.join('lib/gitlab/action_cable/config')
     require_dependency Rails.root.join('lib/gitlab/redis/wrapper')
     require_dependency Rails.root.join('lib/gitlab/redis/cache')
     require_dependency Rails.root.join('lib/gitlab/redis/queues')
diff --git a/config/environments/test.rb b/config/environments/test.rb
index c130eb84baaba3c75a087226aa6d32764440707c..e08e2a34ff4ec7391d798511c385b2eb87562bc4 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -54,4 +54,8 @@
     config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
     config.log_level = :fatal
   end
+
+  # Mount the ActionCable Engine in-app so that we don't have to spawn another Puma
+  # process for feature specs
+  ENV['ACTION_CABLE_IN_APP'] = 'true'
 end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 766d8b0251a3aba2aadad4dc82ed345bca34ac8f..5ebf30126c74f303bae2c56b0576edcd239625a1 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -515,7 +515,7 @@ production: &base
     # NOTE: This will only take effect if elasticsearch is enabled.
     elastic_index_bulk_cron_worker:
       cron: "*/1 * * * *"
-      
+
     # Elasticsearch bulk updater for initial updates.
     # NOTE: This will only take effect if elasticsearch is enabled.
     elastic_index_initial_bulk_cron_worker:
@@ -1111,14 +1111,6 @@ production: &base
     #   host: localhost
     #   port: 3808
 
-  ## ActionCable settings
-  action_cable:
-    # Enables handling of ActionCable requests on the Puma web workers
-    # When this is disabled, a standalone ActionCable server must be started
-    in_app: true
-    # Number of threads used to process ActionCable connection callbacks and channel actions
-    # worker_pool_size: 4
-
   ## Monitoring
   # Built in monitoring settings
   monitoring:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index dd9d8b8d4d8d3560d9e79835e47ea76f4bba0ffe..ba99206d52fb3aa0169734f091e8258093bba2c2 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -740,13 +740,6 @@
 Settings.webpack.dev_server['host']    ||= 'localhost'
 Settings.webpack.dev_server['port']    ||= 3808
 
-#
-# ActionCable settings
-#
-Settings['action_cable'] ||= Settingslogic.new({})
-Settings.action_cable['in_app'] ||= false
-Settings.action_cable['worker_pool_size'] ||= 4
-
 #
 # Monitoring settings
 #
diff --git a/config/initializers/action_cable.rb b/config/initializers/action_cable.rb
index 074d393473f06cca77c137af84766ce1d76a3880..5530e7d64a25590bb7050b3739ba5353e86036dd 100644
--- a/config/initializers/action_cable.rb
+++ b/config/initializers/action_cable.rb
@@ -4,10 +4,10 @@
 
 Rails.application.configure do
   # Mount the ActionCable engine when in-app mode is enabled
-  config.action_cable.mount_path = Gitlab.config.action_cable.in_app ? '/-/cable' : nil
+  config.action_cable.mount_path = Gitlab::ActionCable::Config.in_app? ? '/-/cable' : nil
 
   config.action_cable.url = Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/-/cable')
-  config.action_cable.worker_pool_size = Gitlab.config.action_cable.worker_pool_size
+  config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
 end
 
 # https://github.com/rails/rails/blob/bb5ac1623e8de08c1b7b62b1368758f0d3bb6379/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
diff --git a/lib/gitlab/action_cable/config.rb b/lib/gitlab/action_cable/config.rb
new file mode 100644
index 0000000000000000000000000000000000000000..38e870353ebf6baa14bbba82e37b902ac6ecbae1
--- /dev/null
+++ b/lib/gitlab/action_cable/config.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+  module ActionCable
+    class Config
+      class << self
+        def in_app?
+          Gitlab::Utils.to_boolean(ENV.fetch('ACTION_CABLE_IN_APP', false))
+        end
+
+        def worker_pool_size
+          ENV.fetch('ACTION_CABLE_WORKER_POOL_SIZE', 4).to_i
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/runtime.rb b/lib/gitlab/runtime.rb
index 147924048f1d65220b9d29374805650470c5ddbf..8b40aaa101a5aef2459fbf75c8e7b792d4419f2d 100644
--- a/lib/gitlab/runtime.rb
+++ b/lib/gitlab/runtime.rb
@@ -74,7 +74,7 @@ def web_server?
       end
 
       def action_cable?
-        web_server? && (!!defined?(ACTION_CABLE_SERVER) || Gitlab.config.action_cable.in_app)
+        web_server? && (!!defined?(ACTION_CABLE_SERVER) || Gitlab::ActionCable::Config.in_app?)
       end
 
       def multi_threaded?
@@ -93,7 +93,7 @@ def max_threads
         end
 
         if action_cable?
-          threads += Gitlab.config.action_cable.worker_pool_size
+          threads += Gitlab::ActionCable::Config.worker_pool_size
         end
 
         threads
diff --git a/spec/lib/gitlab/runtime_spec.rb b/spec/lib/gitlab/runtime_spec.rb
index 4d21f7eb3574500d2335e5bce9d0c1cf2c52a4f2..8ed7cc141cdb98b1d208c7c984cf8063e0fb06d3 100644
--- a/spec/lib/gitlab/runtime_spec.rb
+++ b/spec/lib/gitlab/runtime_spec.rb
@@ -48,14 +48,15 @@
     before do
       stub_const('::Puma', puma_type)
       allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2)
-      stub_config(action_cable: { in_app: false })
+      stub_env('ACTION_CABLE_IN_APP', 'false')
     end
 
     it_behaves_like "valid runtime", :puma, 3
 
     context "when ActionCable in-app mode is enabled" do
       before do
-        stub_config(action_cable: { in_app: true, worker_pool_size: 3 })
+        stub_env('ACTION_CABLE_IN_APP', 'true')
+        stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
       end
 
       it_behaves_like "valid runtime", :puma, 6
@@ -64,7 +65,7 @@
     context "when ActionCable standalone is run" do
       before do
         stub_const('ACTION_CABLE_SERVER', true)
-        stub_config(action_cable: { worker_pool_size: 8 })
+        stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '8')
       end
 
       it_behaves_like "valid runtime", :puma, 11
@@ -75,14 +76,15 @@
     before do
       stub_const('::Unicorn', Module.new)
       stub_const('::Unicorn::HttpServer', Class.new)
-      stub_config(action_cable: { in_app: false })
+      stub_env('ACTION_CABLE_IN_APP', 'false')
     end
 
     it_behaves_like "valid runtime", :unicorn, 1
 
     context "when ActionCable in-app mode is enabled" do
       before do
-        stub_config(action_cable: { in_app: true, worker_pool_size: 3 })
+        stub_env('ACTION_CABLE_IN_APP', 'true')
+        stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
       end
 
       it_behaves_like "valid runtime", :unicorn, 4