diff --git a/airflow/config_templates/config.yml b/airflow/config_templates/config.yml
index d0b97308a22e5..f929e738dbc5d 100644
--- a/airflow/config_templates/config.yml
+++ b/airflow/config_templates/config.yml
@@ -1303,6 +1303,13 @@
       type: integer
       example: ~
       default: "3"
+    - name: warn_deployment_exposure
+      description: |
+        Boolean for displaying warning for publicly viewable deployment
+      version_added: 2.3.0
+      type: boolean
+      example: ~
+      default: "True"
 
 - name: email
   description: |
diff --git a/airflow/config_templates/default_airflow.cfg b/airflow/config_templates/default_airflow.cfg
index 496616bbcfb66..f81312b8931e2 100644
--- a/airflow/config_templates/default_airflow.cfg
+++ b/airflow/config_templates/default_airflow.cfg
@@ -655,6 +655,9 @@ session_lifetime_minutes = 43200
 # when auto-refresh is turned on
 auto_refresh_interval = 3
 
+# Boolean for displaying warning for publicly viewable deployment
+warn_deployment_exposure = True
+
 [email]
 
 # Configuration email backend and whether to
diff --git a/airflow/www/views.py b/airflow/www/views.py
index 8144c9d0481e0..388e69cd0f70f 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -120,7 +120,7 @@
 from airflow.utils.session import create_session, provide_session
 from airflow.utils.state import State
 from airflow.utils.strings import to_boolean
-from airflow.utils.timezone import td_format
+from airflow.utils.timezone import td_format, utcnow
 from airflow.version import version
 from airflow.www import auth, utils as wwwutils
 from airflow.www.decorators import action_logging, gzipped
@@ -788,6 +788,29 @@ def _iter_parsed_moved_data_table_names():
                 # Second segment is a version marker that we don't need to show.
                 yield segments[2], table_name
 
+        if (
+            permissions.ACTION_CAN_ACCESS_MENU,
+            permissions.RESOURCE_ADMIN_MENU,
+        ) in user_permissions and conf.getboolean("webserver", "warn_deployment_exposure"):
+            robots_file_access_count = (
+                session.query(Log)
+                .filter(Log.event == "robots")
+                .filter(Log.dttm > (utcnow() - timedelta(days=7)))
+                .count()
+            )
+            if robots_file_access_count > 0:
+                flash(
+                    Markup(
+                        'Recent requests have been made to /robots.txt. '
+                        'This indicates that this deployment may be accessible to the public internet. '
+                        'This warning can be disabled by setting webserver.warn_deployment_exposure=False in '
+                        'airflow.cfg. Read more about web deployment security <a href='
+                        f'"{get_docs_url("security/webserver.html")}">'
+                        'here</a>'
+                    ),
+                    "warning",
+                )
+
         return self.render_template(
             'airflow/dags.html',
             dags=dags,
diff --git a/docs/apache-airflow/security/webserver.rst b/docs/apache-airflow/security/webserver.rst
index f168faaedc47e..91a06ad1235ea 100644
--- a/docs/apache-airflow/security/webserver.rst
+++ b/docs/apache-airflow/security/webserver.rst
@@ -31,6 +31,17 @@ set the below:
     [webserver]
     x_frame_enabled = False
 
+Disable Deployment Exposure Warning
+---------------------------------------
+
+Airflow warns when recent requests are made to ``/robot.txt``. To disable this warning set ``warn_deployment_exposure`` to
+``False`` as below:
+
+.. code-block:: ini
+
+    [webserver]
+    warn_deployment_exposure = False
+
 Sensitive Variable fields
 -------------------------
 
diff --git a/tests/www/views/test_views_base.py b/tests/www/views/test_views_base.py
index cc9968276e006..5759369265fbb 100644
--- a/tests/www/views/test_views_base.py
+++ b/tests/www/views/test_views_base.py
@@ -30,7 +30,7 @@
 
 
 def test_index(admin_client):
-    with assert_queries_count(49):
+    with assert_queries_count(50):
         resp = admin_client.get('/', follow_redirects=True)
     check_content_in_response('DAGs', resp)
 
diff --git a/tests/www/views/test_views_robots.py b/tests/www/views/test_views_robots.py
index e9fa98666d0e5..232bfe03dbfeb 100644
--- a/tests/www/views/test_views_robots.py
+++ b/tests/www/views/test_views_robots.py
@@ -14,8 +14,21 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from tests.test_utils.config import conf_vars
 
 
 def test_robots(viewer_client):
     resp = viewer_client.get('/robots.txt', follow_redirects=True)
     assert resp.data.decode('utf-8') == "User-agent: *\nDisallow: /\n"
+
+
+def test_deployment_warning_config(admin_client):
+    warn_text = "webserver.warn_deployment_exposure"
+    admin_client.get('/robots.txt', follow_redirects=True)
+    resp = admin_client.get('', follow_redirects=True)
+    assert warn_text in resp.data.decode('utf-8')
+
+    with conf_vars({('webserver', 'warn_deployment_exposure'): 'False'}):
+        admin_client.get('/robots.txt', follow_redirects=True)
+        resp = admin_client.get('/robots.txt', follow_redirects=True)
+        assert warn_text not in resp.data.decode('utf-8')
