diff --git a/src/page_config.rs b/src/page_config.rs
index 0bc36cb5cc..07c408c02a 100644
--- a/src/page_config.rs
+++ b/src/page_config.rs
@@ -1,8 +1,9 @@
 use super::*;
 
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub(crate) struct PageConfig {
   pub(crate) chain: Chain,
+  pub(crate) csp_origin: Option<String>,
   pub(crate) domain: Option<String>,
   pub(crate) index_sats: bool,
 }
diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs
index 1f9c941fc3..d458b0f8f7 100644
--- a/src/subcommand/server.rs
+++ b/src/subcommand/server.rs
@@ -132,6 +132,11 @@ pub(crate) struct Server {
     help = "Request ACME TLS certificate for <ACME_DOMAIN>. This ord instance must be reachable at <ACME_DOMAIN>:443 to respond to Let's Encrypt ACME challenges."
   )]
   acme_domain: Vec<String>,
+  #[arg(
+    long,
+    help = "Use <CSP_ORIGIN> in Content-Security-Policy header. Set this to the public-facing URL of your ord instance."
+  )]
+  csp_origin: Option<String>,
   #[arg(
     long,
     help = "Listen on <HTTP_PORT> for incoming HTTP requests. [default: 80]."
@@ -182,6 +187,7 @@ impl Server {
 
       let page_config = Arc::new(PageConfig {
         chain: options.chain(),
+        csp_origin: self.csp_origin.clone(),
         domain: acme_domains.first().cloned(),
         index_sats: index.has_sat_index(),
       });
@@ -985,6 +991,7 @@ impl Server {
   async fn content(
     Extension(index): Extension<Arc<Index>>,
     Extension(config): Extension<Arc<Config>>,
+    Extension(page_config): Extension<Arc<PageConfig>>,
     Path(inscription_id): Path<InscriptionId>,
     accept_encoding: AcceptEncoding,
   ) -> ServerResult<Response> {
@@ -997,7 +1004,7 @@ impl Server {
       .ok_or_not_found(|| format!("inscription {inscription_id}"))?;
 
     Ok(
-      Self::content_response(inscription, accept_encoding)?
+      Self::content_response(inscription, accept_encoding, &page_config)?
         .ok_or_not_found(|| format!("inscription {inscription_id} content"))?
         .into_response(),
     )
@@ -1006,6 +1013,7 @@ impl Server {
   fn content_response(
     inscription: Inscription,
     accept_encoding: AcceptEncoding,
+    page_config: &PageConfig,
   ) -> ServerResult<Option<(HeaderMap, Vec<u8>)>> {
     let mut headers = HeaderMap::new();
 
@@ -1027,15 +1035,25 @@ impl Server {
       }
     }
 
-    headers.insert(
-      header::CONTENT_SECURITY_POLICY,
-      HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:"),
-    );
-
-    headers.append(
-      header::CONTENT_SECURITY_POLICY,
-      HeaderValue::from_static("default-src *:*/content/ *:*/blockheight *:*/blockhash *:*/blockhash/ *:*/blocktime *:*/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"),
-    );
+    match &page_config.csp_origin {
+      None => {
+        headers.insert(
+          header::CONTENT_SECURITY_POLICY,
+          HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:"),
+        );
+        headers.append(
+          header::CONTENT_SECURITY_POLICY,
+          HeaderValue::from_static("default-src *:*/content/ *:*/blockheight *:*/blockhash *:*/blockhash/ *:*/blocktime *:*/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"),
+        );
+      }
+      Some(origin) => {
+        let csp = format!("default-src {origin}/content/ {origin}/blockheight {origin}/blockhash {origin}/blockhash/ {origin}/blocktime {origin}/r/ 'unsafe-eval' 'unsafe-inline' data: blob:");
+        headers.insert(
+          header::CONTENT_SECURITY_POLICY,
+          HeaderValue::from_str(&csp).map_err(|err| ServerError::Internal(Error::from(err)))?,
+        );
+      }
+    }
 
     headers.insert(
       header::CACHE_CONTROL,
@@ -1052,6 +1070,7 @@ impl Server {
   async fn preview(
     Extension(index): Extension<Arc<Index>>,
     Extension(config): Extension<Arc<Config>>,
+    Extension(page_config): Extension<Arc<PageConfig>>,
     Path(inscription_id): Path<InscriptionId>,
     accept_encoding: AcceptEncoding,
   ) -> ServerResult<Response> {
@@ -1089,7 +1108,7 @@ impl Server {
           .into_response(),
       ),
       Media::Iframe => Ok(
-        Self::content_response(inscription, accept_encoding)?
+        Self::content_response(inscription, accept_encoding, &page_config)?
           .ok_or_not_found(|| format!("inscription {inscription_id} content"))?
           .into_response(),
       ),
@@ -3131,7 +3150,8 @@ mod tests {
     assert_eq!(
       Server::content_response(
         Inscription::new(Some("text/plain".as_bytes().to_vec()), None),
-        AcceptEncoding::default()
+        AcceptEncoding::default(),
+        &PageConfig::default(),
       )
       .unwrap(),
       None
@@ -3143,6 +3163,7 @@ mod tests {
     let (headers, body) = Server::content_response(
       Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
       AcceptEncoding::default(),
+      &PageConfig::default(),
     )
     .unwrap()
     .unwrap();
@@ -3151,6 +3172,38 @@ mod tests {
     assert_eq!(body, vec![1, 2, 3]);
   }
 
+  #[test]
+  fn content_security_policy_no_origin() {
+    let (headers, _) = Server::content_response(
+      Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
+      AcceptEncoding::default(),
+      &PageConfig::default(),
+    )
+    .unwrap()
+    .unwrap();
+
+    assert_eq!(
+      headers["content-security-policy"],
+      HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:")
+    );
+  }
+
+  #[test]
+  fn content_security_policy_with_origin() {
+    let (headers, _) = Server::content_response(
+      Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
+      AcceptEncoding::default(),
+      &PageConfig {
+        csp_origin: Some("https://ordinals.com".into()),
+        ..Default::default()
+      },
+    )
+    .unwrap()
+    .unwrap();
+
+    assert_eq!(headers["content-security-policy"], HeaderValue::from_static("default-src https://ordinals.com/content/ https://ordinals.com/blockheight https://ordinals.com/blockhash https://ordinals.com/blockhash/ https://ordinals.com/blocktime https://ordinals.com/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"));
+  }
+
   #[test]
   fn code_preview() {
     let server = TestServer::new_with_regtest();
@@ -3181,6 +3234,7 @@ mod tests {
     let (headers, body) = Server::content_response(
       Inscription::new(None, Some(Vec::new())),
       AcceptEncoding::default(),
+      &PageConfig::default(),
     )
     .unwrap()
     .unwrap();
@@ -3194,6 +3248,7 @@ mod tests {
     let (headers, body) = Server::content_response(
       Inscription::new(Some("\n".as_bytes().to_vec()), Some(Vec::new())),
       AcceptEncoding::default(),
+      &PageConfig::default(),
     )
     .unwrap()
     .unwrap();
diff --git a/src/templates.rs b/src/templates.rs
index 32f6653776..7ad6b30c8a 100644
--- a/src/templates.rs
+++ b/src/templates.rs
@@ -117,6 +117,7 @@ mod tests {
     assert_regex_match!(
       Foo.page(Arc::new(PageConfig {
         chain: Chain::Mainnet,
+        csp_origin: Some("https://signet.ordinals.com".into()),
         domain: Some("signet.ordinals.com".into()),
         index_sats: true,
       }),),
@@ -162,9 +163,10 @@ mod tests {
     assert_regex_match!(
       Foo.page(Arc::new(PageConfig {
         chain: Chain::Mainnet,
+        csp_origin: None,
         domain: None,
         index_sats: true,
-      }),),
+      })),
       r".*<nav class=links>\s*<a href=/>Ordinals<sup>alpha</sup></a>.*"
     );
   }
@@ -174,9 +176,10 @@ mod tests {
     assert_regex_match!(
       Foo.page(Arc::new(PageConfig {
         chain: Chain::Mainnet,
+        csp_origin: None,
         domain: None,
         index_sats: false,
-      }),),
+      })),
       r".*<nav class=links>\s*<a href=/>Ordinals<sup>alpha</sup></a>.*<a href=/clock>Clock</a>\s*<form action=/search.*",
     );
   }
@@ -186,9 +189,10 @@ mod tests {
     assert_regex_match!(
       Foo.page(Arc::new(PageConfig {
         chain: Chain::Signet,
+        csp_origin: None,
         domain: None,
         index_sats: true,
-      }),),
+      })),
       r".*<nav class=links>\s*<a href=/>Ordinals<sup>signet</sup></a>.*"
     );
   }