diff --git a/app/assets/javascripts/drawio/constants.js b/app/assets/javascripts/drawio/constants.js
index 2e1e074db3bbd466f974b2b9f621461670690415..2f1870087f9b60b91c4389f9d42e240aa79c1149 100644
--- a/app/assets/javascripts/drawio/constants.js
+++ b/app/assets/javascripts/drawio/constants.js
@@ -1,9 +1,18 @@
 /*
  * TODO: Make this URL configurable
  */
-export const DRAWIO_EDITOR_URL =
-  'https://embed.diagrams.net/?ui=sketch&noSaveBtn=1&saveAndExit=1&keepmodified=1&spin=1&embed=1&libraries=1&configure=1&proto=json&toSvg=1'; // TODO Make it configurable
-
+export const DRAWIO_PARAMS = {
+  ui: 'sketch',
+  noSaveBtn: 1,
+  saveAndExit: 1,
+  keepmodified: 1,
+  spin: 1,
+  embed: 1,
+  libraries: 1,
+  configure: 1,
+  proto: 'json',
+  toSvg: 1,
+};
 export const DRAWIO_FRAME_ID = 'drawio-frame';
 
 export const DARK_BACKGROUND_COLOR = '#202020';
diff --git a/app/assets/javascripts/drawio/drawio_editor.js b/app/assets/javascripts/drawio/drawio_editor.js
index 38d1cadcc635a42b9224f916541a5397e1cac4c5..3c411d8093cd05f97045b94233303bad023a3673 100644
--- a/app/assets/javascripts/drawio/drawio_editor.js
+++ b/app/assets/javascripts/drawio/drawio_editor.js
@@ -4,8 +4,8 @@ import { darkModeEnabled } from '~/lib/utils/color_utils';
 import { __ } from '~/locale';
 import { setAttributes } from '~/lib/utils/dom_utils';
 import {
+  DRAWIO_PARAMS,
   DARK_BACKGROUND_COLOR,
-  DRAWIO_EDITOR_URL,
   DRAWIO_FRAME_ID,
   DIAGRAM_BACKGROUND_COLOR,
   DRAWIO_IFRAME_TIMEOUT,
@@ -17,7 +17,7 @@ function updateDrawioEditorState(drawIOEditorState, data) {
 }
 
 function postMessageToDrawioEditor(drawIOEditorState, message) {
-  const { origin } = new URL(DRAWIO_EDITOR_URL);
+  const { origin } = new URL(drawIOEditorState.drawioUrl);
 
   drawIOEditorState.iframe.contentWindow.postMessage(JSON.stringify(message), origin);
 }
@@ -222,7 +222,7 @@ function createEditorIFrame(drawIOEditorState) {
 
   setAttributes(iframe, {
     id: DRAWIO_FRAME_ID,
-    src: DRAWIO_EDITOR_URL,
+    src: drawIOEditorState.drawioUrl,
     class: 'drawio-editor',
   });
 
@@ -256,7 +256,7 @@ function attachDrawioIFrameMessageListener(drawIOEditorState, editorFacade) {
   });
 }
 
-const createDrawioEditorState = ({ filename = null }) => ({
+const createDrawioEditorState = ({ filename = null, drawioUrl }) => ({
   newDiagram: true,
   filename,
   diagramSvg: null,
@@ -266,10 +266,17 @@ const createDrawioEditorState = ({ filename = null }) => ({
   initialized: false,
   dark: darkModeEnabled(),
   disposeEventListener: null,
+  drawioUrl,
 });
 
-export function launchDrawioEditor({ editorFacade, filename }) {
-  const drawIOEditorState = createDrawioEditorState({ filename });
+export function launchDrawioEditor({ editorFacade, filename, drawioUrl = gon.diagramsnet_url }) {
+  const url = new URL(drawioUrl);
+
+  for (const [key, value] of Object.entries(DRAWIO_PARAMS)) {
+    url.searchParams.set(key, value);
+  }
+
+  const drawIOEditorState = createDrawioEditorState({ filename, drawioUrl: url.href });
 
   // The execution order of these two functions matter
   attachDrawioIFrameMessageListener(drawIOEditorState, editorFacade);
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
index 3b38d715ea582df8e23afcd09a163b74ba4a1993..4f68c7984e89c43ad643ade3912c389992d05951 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -107,7 +107,7 @@ export default {
     MarkdownEditor,
   },
   mixins: [trackingMixin],
-  inject: ['formatOptions', 'pageInfo'],
+  inject: ['formatOptions', 'pageInfo', 'drawioUrl'],
   data() {
     return {
       editingMode: 'source',
@@ -183,6 +183,9 @@ export default {
     disableSubmitButton() {
       return this.noContent || !this.title;
     },
+    drawioEnabled() {
+      return typeof this.drawioUrl === 'string' && this.drawioUrl.length > 0;
+    },
   },
   mounted() {
     if (!this.commitMessage) this.updateCommitMessage();
@@ -356,7 +359,7 @@ export default {
             :autofocus="pageInfo.persisted"
             :enable-autocomplete="true"
             :autocomplete-data-sources="autocompleteDataSources"
-            :drawio-enabled="true"
+            :drawio-enabled="drawioEnabled"
             @contentEditor="notifyContentEditorActive"
             @markdownField="notifyContentEditorInactive"
             @keydown.ctrl.enter="submitFormShortcut"
diff --git a/app/assets/javascripts/pages/shared/wikis/edit.js b/app/assets/javascripts/pages/shared/wikis/edit.js
index 02878633916ede1d6db7415ac5f0e6edaaaf69ae..0044575de62a380aca70afb031960dc0519d0cb8 100644
--- a/app/assets/javascripts/pages/shared/wikis/edit.js
+++ b/app/assets/javascripts/pages/shared/wikis/edit.js
@@ -70,6 +70,7 @@ const createWikiFormApp = () => {
       provide: {
         formatOptions: JSON.parse(formatOptions),
         pageInfo: convertObjectPropsToCamelCase(JSON.parse(pageInfo)),
+        drawioUrl: gon.diagramsnet_url,
       },
       render(createElement) {
         return createElement(wikiForm);
diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb
index 265cf2a769822ee02a43807530ee0f0cdb307462..c606ccf4a07e7bd3306df1801d1f6a9f333c370d 100644
--- a/app/controllers/concerns/wiki_actions.rb
+++ b/app/controllers/concerns/wiki_actions.rb
@@ -13,9 +13,10 @@ module WikiActions
   included do
     content_security_policy do |p|
       next if p.directives.blank?
+      next unless Gitlab::CurrentSettings.diagramsnet_enabled?
 
       default_frame_src = p.directives['frame-src'] || p.directives['default-src']
-      frame_src_values = Array.wrap(default_frame_src) | ['https://embed.diagrams.net'].compact
+      frame_src_values = Array.wrap(default_frame_src) | [Gitlab::CurrentSettings.diagramsnet_url].compact
 
       p.frame_src(*frame_src_values)
     end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index e163625f85fc9e1288851b41b255ba5e54443efa..1c988b9767fbec90c7d3f496cb1c1a76dd1bdd2b 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -337,6 +337,8 @@ def visible_attributes
       :kroki_formats,
       :plantuml_enabled,
       :plantuml_url,
+      :diagramsnet_enabled,
+      :diagramsnet_url,
       :polling_interval_multiplier,
       :project_export_enabled,
       :prometheus_metrics_enabled,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index aafce07dcdbef2827e5b7585543ba715e2fa9500..0e7fca6520889b00e72abbb1d4d199b4c12430a9 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -186,6 +186,11 @@ def self.kroki_formats_attributes
 
   validates :sourcegraph_url, presence: true, if: :sourcegraph_enabled
 
+  validates :diagramsnet_url,
+    presence: true,
+    addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ enforce_sanitization: true }),
+    if: :diagramsnet_enabled
+
   validates :gitpod_url,
     presence: true,
     addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ enforce_sanitization: true }),
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 81ce057fa222a60026f52ce388f02e3f4364819c..ea07fe99c996434313c820e3ebe64db3c9ce8311 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -132,6 +132,8 @@ def defaults # rubocop:disable Metrics/AbcSize
         personal_access_token_prefix: 'glpat-',
         plantuml_enabled: false,
         plantuml_url: nil,
+        diagramsnet_enabled: true,
+        diagramsnet_url: 'https://embed.diagrams.net',
         polling_interval_multiplier: 1,
         productivity_analytics_start_date: Time.current,
         project_download_export_limit: 1,
diff --git a/app/views/admin/application_settings/_diagramsnet.html.haml b/app/views/admin/application_settings/_diagramsnet.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e493110a9dc97dbc24836c45ed27d2e92df3bf1c
--- /dev/null
+++ b/app/views/admin/application_settings/_diagramsnet.html.haml
@@ -0,0 +1,25 @@
+- expanded = integration_expanded?('diagramsnet_')
+%section.settings.as-diagramsnet.no-animate#js-diagramsnet-settings{ class: ('expanded' if expanded) }
+  .settings-header
+    %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+      = _('Diagrams.net')
+    = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+      = expanded ? _('Collapse') : _('Expand')
+    %p
+      = _('Render diagrams in your documents using diagrams.net.')
+      = link_to _('Learn more.'), help_page_path('administration/integration/diagrams_net.md'), target: '_blank', rel: 'noopener noreferrer'
+  .settings-content
+    = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-diagramsnet-settings'), html: { class: 'fieldset-form', id: 'diagramsnet-settings' } do |f|
+      = form_errors(@application_setting) if expanded
+
+      %fieldset
+        .form-group
+          = f.gitlab_ui_checkbox_component :diagramsnet_enabled,
+            _('Enable diagrams.net')
+        .form-group
+          = f.label :diagramsnet_url, _('Diagrams.net URL'), class: 'label-bold'
+          = f.text_field :diagramsnet_url, class: 'form-control gl-form-input', placeholder: 'https://embed.diagrams.net'
+          .form-text.text-muted
+            = _('The hostname of your diagrams.net server.')
+
+      = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index e6c27c1bc84494e8a99af89204c60aa3c68d4313..3413774b3610d98a4a96f8f0b1a2e0d8688fdb3e 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -94,6 +94,7 @@
 = render 'admin/application_settings/kroki'
 = render 'admin/application_settings/mailgun'
 = render 'admin/application_settings/plantuml'
+= render 'admin/application_settings/diagramsnet'
 = render 'admin/application_settings/sourcegraph'
 = render_if_exists 'admin/application_settings/slack'
 -# this partial is from JiHu, see details in https://jihulab.com/gitlab-cn/gitlab/-/merge_requests/417
diff --git a/db/migrate/20230329235300_add_diagramsnet_to_application_settings.rb b/db/migrate/20230329235300_add_diagramsnet_to_application_settings.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9e351f190f4fbed136fa62d0429c061464b5b8b1
--- /dev/null
+++ b/db/migrate/20230329235300_add_diagramsnet_to_application_settings.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddDiagramsnetToApplicationSettings < Gitlab::Database::Migration[2.1]
+  enable_lock_retries!
+  # rubocop:disable Migration/AddLimitToTextColumns
+  # limit is added in 20230406115900_add_diagramsnet_text_limit.rb
+  def change
+    add_column :application_settings, :diagramsnet_enabled, :boolean, default: true, null: false
+    add_column :application_settings, :diagramsnet_url, :text, default: 'https://embed.diagrams.net'
+  end
+  # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20230406115900_add_diagramsnet_text_limit.rb b/db/migrate/20230406115900_add_diagramsnet_text_limit.rb
new file mode 100644
index 0000000000000000000000000000000000000000..27155c70c56b68bba72bef6b9bf60546284a1af8
--- /dev/null
+++ b/db/migrate/20230406115900_add_diagramsnet_text_limit.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddDiagramsnetTextLimit < Gitlab::Database::Migration[2.1]
+  disable_ddl_transaction!
+
+  def up
+    add_text_limit :application_settings, :diagramsnet_url, 2048
+  end
+
+  def down
+    remove_text_limit :application_settings, :diagramsnet_url
+  end
+end
diff --git a/db/schema_migrations/20230329235300 b/db/schema_migrations/20230329235300
new file mode 100644
index 0000000000000000000000000000000000000000..0f3d4099553cda48ec84b27389343bffd2458d66
--- /dev/null
+++ b/db/schema_migrations/20230329235300
@@ -0,0 +1 @@
+44df5e98715af0cf9f8920e8fc35754901d578ae5c1dcc5fa7a3fb9ee49f995b
\ No newline at end of file
diff --git a/db/schema_migrations/20230406115900 b/db/schema_migrations/20230406115900
new file mode 100644
index 0000000000000000000000000000000000000000..38fa9134dacea269dd8a69936756ba5b6028de8d
--- /dev/null
+++ b/db/schema_migrations/20230406115900
@@ -0,0 +1 @@
+85cf98db148785c25a6ed472a300f5967aea916ef9b937d78bff90e33905886f
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 45834eff57d5384c6abc3f9a6ccda45d7e5153b7..a23d01c628e0b7c40db4997db77368af42f1fdcd 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -11837,6 +11837,8 @@ CREATE TABLE application_settings (
     remember_me_enabled boolean DEFAULT true NOT NULL,
     encrypted_anthropic_api_key bytea,
     encrypted_anthropic_api_key_iv bytea,
+    diagramsnet_enabled boolean DEFAULT true NOT NULL,
+    diagramsnet_url text DEFAULT 'https://embed.diagrams.net'::text,
     allow_account_deletion boolean DEFAULT true NOT NULL,
     vertex_project text,
     wiki_asciidoc_allow_uri_includes boolean DEFAULT false NOT NULL,
@@ -11856,6 +11858,7 @@ CREATE TABLE application_settings (
     CONSTRAINT app_settings_registry_repair_worker_max_concurrency_positive CHECK ((container_registry_data_repair_detail_worker_max_concurrency >= 0)),
     CONSTRAINT app_settings_yaml_max_depth_positive CHECK ((max_yaml_depth > 0)),
     CONSTRAINT app_settings_yaml_max_size_positive CHECK ((max_yaml_size_bytes > 0)),
+    CONSTRAINT check_0542340619 CHECK ((char_length(diagramsnet_url) <= 2048)),
     CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
     CONSTRAINT check_2b820eaac3 CHECK ((char_length(database_grafana_tag) <= 255)),
     CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
diff --git a/doc/administration/integration/diagrams_net.md b/doc/administration/integration/diagrams_net.md
new file mode 100644
index 0000000000000000000000000000000000000000..fe5e730a0643b762f5cd1eef1569361b1ff46b45
--- /dev/null
+++ b/doc/administration/integration/diagrams_net.md
@@ -0,0 +1,53 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+type: reference, howto
+---
+
+# Diagrams.net **(FREE)**
+
+With the [diagrams.net](https://www.diagrams.net/) integration, you can create and embed SVG diagrams in wikis.
+The diagram editor is available in both the Markdown editor and the content editor.
+
+On GitLab.com, this integration is enabled for all SaaS users and does not require any additional configuration.
+
+On self-managed GitLab, you can choose to integrate with the free [diagrams.net](https://www.diagrams.net/)
+website, or use a self-managed diagrams.net site in offline environments.
+
+To set up the integration on a self-managed instance, you must:
+
+1. Choose to integrate with the free diagrams.net website or
+   [configure your diagrams.net server](#configure-your-diagramsnet-server).
+1. [Enable the integration](#enable-diagramsnet-integration).
+
+After completing the integration, the diagrams.net editor opens with the URL you provided.
+
+## Configure your diagrams.net server
+
+You can set up your own diagrams.net server to generate the diagrams.
+
+This is a required step for users on offline (or "air-gapped") self-managed GitLab installations.
+
+For example, to run a diagrams.net container in Docker, run the following command:
+
+```shell
+docker run -it --rm --name="draw" -p 8080:8080 -p 8443:8443 jgraph/drawio
+```
+
+Make note of the hostname of the server running the container, to be used as the diagrams.net URL
+when you enable the integration.
+
+For more information, see [Run your own diagrams.net server with Docker](https://www.diagrams.net/blog/diagrams-docker-app).
+
+## Enable Diagrams.net integration
+
+1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Diagrams.net**.
+1. Select the **Enable Diagrams.net** checkbox.
+1. Enter the Diagrams.net URL. To connect to:
+   - The free public instance: enter `https://embed.diagrams.net`.
+   - A self-managed diagrams.net instance: enter the URL you [configured earlier](#configure-your-diagramsnet-server).
+1. Select **Save changes**.
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 559332858b3d2835f5a4287928a82b2d19b91853..231cff418e562b93f04c9da2096094f5d4e88e20 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -67,6 +67,8 @@ Example response:
   "repository_storages_weighted": {"default": 100},
   "plantuml_enabled": false,
   "plantuml_url": null,
+  "diagramsnet_enabled": true,
+  "diagramsnet_url": "https://embed.diagrams.net",
   "kroki_enabled": false,
   "kroki_url": null,
   "terminal_max_session_time": 0,
@@ -193,6 +195,8 @@ Example response:
   "repository_storages": ["default"],
   "plantuml_enabled": false,
   "plantuml_url": null,
+  "diagramsnet_enabled": true,
+  "diagramsnet_url": "https://embed.diagrams.net",
   "terminal_max_session_time": 0,
   "polling_interval_multiplier": 1.0,
   "rsa_key_restriction": 0,
@@ -325,6 +329,8 @@ listed in the descriptions of the relevant settings.
 | `delayed_group_deletion` **(PREMIUM SELF)**   | boolean     | no                                   | Enable delayed group deletion. Default is `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352959) in GitLab 15.0. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), disables and locks the group-level setting for delayed protect deletion when set to `false`. From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled, this attribute has been removed. This attribute will be completely removed in GitLab 16.0. |
 | `default_project_deletion_protection` **(PREMIUM SELF)** | boolean | no                            | Enable default project deletion protection so only administrators can delete projects. Default is `false`. |
 | `deletion_adjourned_period` **(PREMIUM SELF)** | integer    | no                                   | The number of days to wait before deleting a project or group that is marked for deletion. Value must be between `1` and `90`. Defaults to `7`. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), a hook on `deletion_adjourned_period` sets the period to `1` on every update, and sets both `delayed_project_deletion` and `delayed_group_deletion` to `false` if the period is `0`. |
+| `diagramsnet_enabled`                       | boolean          | no                                   | (If enabled, requires `diagramsnet_url`) Enable [Diagrams.net integration](../administration/integration/diagrams_net.md). Default is `true`. |
+| `diagramsnet_url`                           | string           | required by: `diagramsnet_enabled`      | The Diagrams.net instance URL for integration. |
 | `diff_max_patch_bytes`                   | integer          | no                                   | Maximum [diff patch size](../user/admin_area/diff_limits.md), in bytes. |
 | `diff_max_files`                         | integer          | no                                   | Maximum [files in a diff](../user/admin_area/diff_limits.md). |
 | `diff_max_lines`                         | integer          | no                                   | Maximum [lines in a diff](../user/admin_area/diff_limits.md). |
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index b8ed1c0632425674e6556c2451c105130d5478a8..2026a03315044c4232b23527c366eb83212306c7 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -567,13 +567,12 @@ This example links to `<wiki_root>/miscellaneous.md`:
 
 > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322174) in GitLab 15.10.
 
-NOTE:
-Use of the diagrams.net editor is not available on offline environments.
-
 In wikis, you can use the [diagrams.net](https://www.diagrams.net/) editor to create diagrams. You
 can also edit diagrams created with the diagrams.net editor. The diagram editor is available in both
 the Markdown editor and the content editor.
 
+For more information, see [Diagrams.net](../administration/integration/diagrams_net.md).
+
 ##### Markdown editor
 
 To create a diagram in the Markdown editor:
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 78be9ee75e943d97cabc97fdaf9a57f26830532f..3b553c4a66eac9130e945b2926cd17cac38e57c1 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -125,6 +125,10 @@ def filter_attributes_using_license(attrs)
       given plantuml_enabled: ->(val) { val } do
         requires :plantuml_url, type: String, desc: 'The PlantUML server URL'
       end
+      optional :diagramsnet_enabled, type: Boolean, desc: 'Enable Diagrams.net'
+      given diagramsnet_enabled: ->(val) { val } do
+        requires :diagramsnet_url, type: String, desc: 'The Diagrams.net server URL'
+      end
       optional :polling_interval_multiplier, type: BigDecimal, desc: 'Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling.'
       optional :project_export_enabled, type: Boolean, desc: 'Enable project export'
       optional :prometheus_metrics_enabled, type: Boolean, desc: 'Enable Prometheus metrics'
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 904a2ccc79bf70ac17c1a447106978fa4d165010..eef176687e7622fabb8872d65938126aea4abdb8 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -51,6 +51,8 @@ def add_gon_variables
       gon.dot_com                = Gitlab.com?
       gon.uf_error_prefix        = ::Gitlab::Utils::ErrorMessage::UF_ERROR_PREFIX
 
+      gon.diagramsnet_url = Gitlab::CurrentSettings.diagramsnet_url if Gitlab::CurrentSettings.diagramsnet_enabled
+
       if current_user
         gon.current_user_id = current_user.id
         gon.current_username = current_user.username
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 46b5d39d1e5304005be4ce0e62d088e108f58a58..245f089b561f9b7d1d277fc952c3b46c6271a165 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15829,6 +15829,12 @@ msgstr ""
 msgid "Diagram saved successfully."
 msgstr ""
 
+msgid "Diagrams.net"
+msgstr ""
+
+msgid "Diagrams.net URL"
+msgstr ""
+
 msgid "Did not delete the source branch."
 msgstr ""
 
@@ -16797,6 +16803,9 @@ msgstr ""
 msgid "Enable dashboard limits on namespaces"
 msgstr ""
 
+msgid "Enable diagrams.net"
+msgstr ""
+
 msgid "Enable email notification"
 msgstr ""
 
@@ -38022,6 +38031,9 @@ msgstr ""
 msgid "Render diagrams in your documents using PlantUML."
 msgstr ""
 
+msgid "Render diagrams in your documents using diagrams.net."
+msgstr ""
+
 msgid "Renew subscription"
 msgstr ""
 
@@ -45458,6 +45470,9 @@ msgstr ""
 msgid "The hostname of your Snowplow collector."
 msgstr ""
 
+msgid "The hostname of your diagrams.net server."
+msgstr ""
+
 msgid "The import cannot be canceled because it is %{project_status}"
 msgstr ""
 
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index e113e305af55ed126d9cdcd2a32684f988159b33..3aa2ce2a154f73dc15cd303b7410701d323be806 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -6,12 +6,15 @@
   include RepoHelpers
 
   let(:project) { create(:project, :repository) }
+  let(:diagramsnet_url) { 'https://embed.diagrams.net' }
   let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
   let(:user) { create(:user) }
 
   before do
     project.add_maintainer(user)
     sign_in(user)
+    allow(Gitlab::CurrentSettings).to receive(:diagramsnet_enabled).and_return(true)
+    allow(Gitlab::CurrentSettings).to receive(:diagramsnet_url).and_return(diagramsnet_url)
 
     visit(merge_request_path(merge_request))
   end
diff --git a/spec/frontend/__helpers__/test_constants.js b/spec/frontend/__helpers__/test_constants.js
index 628b9b054d3349c756e996d2a270e44e274f348f..b5a585811d1940e1b44e1a177c48db1db84c13c6 100644
--- a/spec/frontend/__helpers__/test_constants.js
+++ b/spec/frontend/__helpers__/test_constants.js
@@ -1,5 +1,6 @@
 const FIXTURES_PATH = `/fixtures`;
 const TEST_HOST = 'http://test.host';
+const DRAWIO_ORIGIN = 'https://embed.diagrams.net';
 
 const DUMMY_IMAGE_URL = `${FIXTURES_PATH}/static/images/one_white_pixel.png`;
 
@@ -15,6 +16,7 @@ const DUMMY_IMAGE_BLOB_PATH = 'SpongeBlob.png';
 module.exports = {
   FIXTURES_PATH,
   TEST_HOST,
+  DRAWIO_ORIGIN,
   DUMMY_IMAGE_URL,
   GREEN_BOX_IMAGE_URL,
   RED_BOX_IMAGE_URL,
diff --git a/spec/frontend/drawio/drawio_editor_spec.js b/spec/frontend/drawio/drawio_editor_spec.js
index d7d75922e1ee6393442b647f5f6ba4e1a4db87b9..4d93908b75725de52c0c4da7af18c45694aaa35c 100644
--- a/spec/frontend/drawio/drawio_editor_spec.js
+++ b/spec/frontend/drawio/drawio_editor_spec.js
@@ -1,6 +1,5 @@
 import { launchDrawioEditor } from '~/drawio/drawio_editor';
 import {
-  DRAWIO_EDITOR_URL,
   DRAWIO_FRAME_ID,
   DIAGRAM_BACKGROUND_COLOR,
   DRAWIO_IFRAME_TIMEOUT,
@@ -8,6 +7,10 @@ import {
 } from '~/drawio/constants';
 import { createAlert, VARIANT_SUCCESS } from '~/alert';
 
+const DRAWIO_EDITOR_URL =
+  'https://embed.diagrams.net/?ui=sketch&noSaveBtn=1&saveAndExit=1&keepmodified=1&spin=1&embed=1&libraries=1&configure=1&proto=json&toSvg=1';
+const DRAWIO_EDITOR_ORIGIN = new URL(DRAWIO_EDITOR_URL).origin;
+
 jest.mock('~/alert');
 
 jest.useFakeTimers();
@@ -59,6 +62,7 @@ describe('drawio/drawio_editor', () => {
       updateDiagram: jest.fn(),
     };
     drawioIFrameReceivedMessages = [];
+    gon.diagramsnet_url = DRAWIO_EDITOR_ORIGIN;
   });
 
   afterEach(() => {
@@ -356,7 +360,11 @@ describe('drawio/drawio_editor', () => {
       const TEST_FILENAME = 'diagram.drawio.svg';
 
       beforeEach(() => {
-        launchDrawioEditor({ editorFacade, filename: TEST_FILENAME });
+        launchDrawioEditor({
+          editorFacade,
+          filename: TEST_FILENAME,
+          drawioUrl: DRAWIO_EDITOR_ORIGIN,
+        });
       });
 
       it('displays loading spinner in the draw.io editor', async () => {
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index ddaa3df71e8c41abc8b374024713bcec06a36c0d..1a3eb86a00ea20c8724bfc40b2aabfe393036fb7 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -14,6 +14,7 @@ import {
   WIKI_FORMAT_LABEL,
   WIKI_FORMAT_UPDATED_ACTION,
 } from '~/pages/shared/wikis/constants';
+import { DRAWIO_ORIGIN } from 'spec/test_constants';
 
 jest.mock('~/emoji');
 
@@ -69,12 +70,12 @@ describe('WikiForm', () => {
     AsciiDoc: 'asciidoc',
     Org: 'org',
   };
-
   function createWrapper({
     mountFn = shallowMount,
     persisted = false,
     pageInfo,
     glFeatures = { wikiSwitchBetweenContentEditorRawMarkdown: false },
+    provide = { drawioUrl: null },
   } = {}) {
     wrapper = extendedWrapper(
       mountFn(WikiForm, {
@@ -85,6 +86,7 @@ describe('WikiForm', () => {
             ...(persisted ? pageInfoPersisted : pageInfoNew),
             ...pageInfo,
           },
+          ...provide,
         },
         stubs: {
           GlAlert,
@@ -334,4 +336,20 @@ describe('WikiForm', () => {
       });
     });
   });
+
+  describe('when drawioURL is provided', () => {
+    it('enables drawio editor in the Markdown Editor', () => {
+      createWrapper({ provide: { drawioUrl: DRAWIO_ORIGIN } });
+
+      expect(findMarkdownEditor().props().drawioEnabled).toBe(true);
+    });
+  });
+
+  describe('when drawioURL is empty', () => {
+    it('disables drawio editor in the Markdown Editor', () => {
+      createWrapper();
+
+      expect(findMarkdownEditor().props().drawioEnabled).toBe(false);
+    });
+  });
 });
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 37f4bbf0f631e31c54f5a49531424e4555f7d6f6..9ecb0c6f75bceab7007f13237ad98aec129b4902 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -1127,6 +1127,26 @@ def expect_invalid
       end
     end
 
+    describe 'diagrams.net settings' do
+      context 'when diagrams.net is enabled' do
+        before do
+          setting.diagramsnet_enabled = true
+        end
+
+        it { is_expected.not_to allow_value(nil).for(:diagramsnet_url) }
+        it { is_expected.to allow_value("https://embed.diagrams.net").for(:diagramsnet_url) }
+        it { is_expected.not_to allow_value('not a URL').for(:diagramsnet_url) }
+      end
+
+      context 'when diagrams.net is not enabled' do
+        before do
+          setting.diagramsnet_enabled = false
+        end
+
+        it { is_expected.to allow_value(nil).for(:diagramsnet_url) }
+      end
+    end
+
     context 'throttle_* settings' do
       where(:throttle_setting) do
         %i[
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 26c9399a8e5bb4b797dae3b681bbf7275f68629d..79e96d7ea3ebc80018b21c9d6a52b5de51e8112f 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -19,6 +19,8 @@
       expect(json_response['password_authentication_enabled']).to be_truthy
       expect(json_response['plantuml_enabled']).to be_falsey
       expect(json_response['plantuml_url']).to be_nil
+      expect(json_response['diagramsnet_enabled']).to be_truthy
+      expect(json_response['diagramsnet_url']).to eq('https://embed.diagrams.net')
       expect(json_response['default_ci_config_path']).to be_nil
       expect(json_response['sourcegraph_enabled']).to be_falsey
       expect(json_response['sourcegraph_url']).to be_nil
@@ -125,6 +127,8 @@
             repository_storages_weighted: { 'custom' => 100 },
             plantuml_enabled: true,
             plantuml_url: 'http://plantuml.example.com',
+            diagramsnet_enabled: false,
+            diagramsnet_url: nil,
             sourcegraph_enabled: true,
             sourcegraph_url: 'https://sourcegraph.com',
             sourcegraph_public_only: false,
@@ -203,6 +207,8 @@
         expect(json_response['repository_storages_weighted']).to eq({ 'custom' => 100 })
         expect(json_response['plantuml_enabled']).to be_truthy
         expect(json_response['plantuml_url']).to eq('http://plantuml.example.com')
+        expect(json_response['diagramsnet_enabled']).to be_falsey
+        expect(json_response['diagramsnet_url']).to be_nil
         expect(json_response['sourcegraph_enabled']).to be_truthy
         expect(json_response['sourcegraph_url']).to eq('https://sourcegraph.com')
         expect(json_response['sourcegraph_public_only']).to eq(false)
@@ -553,6 +559,15 @@
       end
     end
 
+    context "missing diagramsnet_url value when diagramsnet_enabled is true" do
+      it "returns a blank parameter error message" do
+        put api("/application/settings", admin), params: { diagramsnet_enabled: true }
+
+        expect(response).to have_gitlab_http_status(:bad_request)
+        expect(json_response['error']).to eq('diagramsnet_url is missing')
+      end
+    end
+
     context 'asset_proxy settings' do
       it 'updates application settings' do
         put api('/application/settings', admin),
diff --git a/spec/requests/projects/wikis_controller_spec.rb b/spec/requests/projects/wikis_controller_spec.rb
index 3c434b36b2124f4b4d4bc62a6e0590a55d6a987f..9f69faf499e1aac5bfe824dffea6754e6a4b89b2 100644
--- a/spec/requests/projects/wikis_controller_spec.rb
+++ b/spec/requests/projects/wikis_controller_spec.rb
@@ -6,6 +6,8 @@
   using RSpec::Parameterized::TableSyntax
 
   let_it_be(:user) { create(:user) }
+  let_it_be(:diagramsnet_is_enabled) { false }
+  let_it_be(:diagramsnet_url) { 'https://url.diagrams.net' }
   let_it_be(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
   let_it_be(:project_wiki) { create(:project_wiki, project: project, user: user) }
   let_it_be(:wiki_page) do
@@ -18,6 +20,12 @@
 
   before do
     sign_in(user)
+    allow(Gitlab::CurrentSettings)
+      .to receive(:diagramsnet_enabled?)
+      .and_return(diagramsnet_is_enabled)
+    allow(Gitlab::CurrentSettings)
+      .to receive(:diagramsnet_url)
+      .and_return(diagramsnet_url)
 
     allow_next_instance_of(described_class) do |instance|
       allow(instance).to receive(:content_security_policy_nonce).and_return(csp_nonce)
@@ -25,12 +33,26 @@
   end
 
   shared_examples 'embed.diagrams.net frame-src directive' do
-    it 'adds drawio frame-src directive to the Content Security Policy header' do
-      frame_src = response.headers['Content-Security-Policy'].split(';')
-        .map(&:strip)
-        .find { |entry| entry.starts_with?('frame-src') }
+    context 'when diagrams.net disabled' do
+      it 'drawio frame-src directive to the Content Security Policy header' do
+        frame_src = response.headers['Content-Security-Policy'].split(';')
+          .map(&:strip)
+          .find { |entry| entry.starts_with?('frame-src') }
 
-      expect(frame_src).to include('https://embed.diagrams.net')
+        expect(frame_src).not_to include(diagramsnet_url)
+      end
+    end
+
+    context 'when diagrams.net enabled' do
+      let(:diagramsnet_is_enabled) { true }
+
+      it 'drawio frame-src directive to the Content Security Policy header' do
+        frame_src = response.headers['Content-Security-Policy'].split(';')
+          .map(&:strip)
+          .find { |entry| entry.starts_with?('frame-src') }
+
+        expect(frame_src).to include(diagramsnet_url)
+      end
     end
   end
 
diff --git a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
index 1877aa6490d57562e7ea63a4bab9b3c9d1d8cd89..7725366d56591b54cf4b720c3e74f5b743461114 100644
--- a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
@@ -6,9 +6,12 @@
 
 RSpec.shared_examples 'User updates wiki page' do
   include WikiHelpers
+  let(:diagramsnet_url) { 'https://embed.diagrams.net' }
 
   before do
     sign_in(user)
+    allow(Gitlab::CurrentSettings).to receive(:diagramsnet_enabled).and_return(true)
+    allow(Gitlab::CurrentSettings).to receive(:diagramsnet_url).and_return(diagramsnet_url)
   end
 
   context 'when wiki is empty', :js do