diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs
index 676fea487b35b97f1c36d3b3701c0bebe60d296a..afbda8599b2aa03c4ed4a7c33a93fdd429646516 100644
--- a/bridges/relays/client-substrate/src/client.rs
+++ b/bridges/relays/client-substrate/src/client.rs
@@ -264,12 +264,22 @@ impl<C: Chain> Client<C> {
 		params: &ConnectionParams,
 	) -> Result<(Arc<tokio::runtime::Runtime>, Arc<RpcClient>)> {
 		let tokio = tokio::runtime::Runtime::new()?;
-		let uri = format!(
-			"{}://{}:{}",
-			if params.secure { "wss" } else { "ws" },
-			params.host,
-			params.port,
-		);
+
+		let uri = match params.uri {
+			Some(ref uri) => uri.clone(),
+			None => {
+				format!(
+					"{}://{}:{}{}",
+					if params.secure { "wss" } else { "ws" },
+					params.host,
+					params.port,
+					match params.path {
+						Some(ref path) => format!("/{}", path),
+						None => String::new(),
+					},
+				)
+			},
+		};
 		log::info!(target: "bridge", "Connecting to {} node at {}", C::NAME, uri);
 
 		let client = tokio
diff --git a/bridges/relays/client-substrate/src/lib.rs b/bridges/relays/client-substrate/src/lib.rs
index 6c62b8e1cd5482b4760af32eeacdc29c0038252c..d5b8d4dcced2d8b2e1883b6779905c536eec49f1 100644
--- a/bridges/relays/client-substrate/src/lib.rs
+++ b/bridges/relays/client-substrate/src/lib.rs
@@ -57,10 +57,15 @@ pub use bp_runtime::{
 /// Substrate-over-websocket connection params.
 #[derive(Debug, Clone)]
 pub struct ConnectionParams {
+	/// Websocket endpoint URL. Overrides all other URL components (`host`, `port`, `path` and
+	/// `secure`).
+	pub uri: Option<String>,
 	/// Websocket server host name.
 	pub host: String,
 	/// Websocket server TCP port.
 	pub port: u16,
+	/// Websocket endpoint path at server.
+	pub path: Option<String>,
 	/// Use secure websocket connection.
 	pub secure: bool,
 	/// Defined chain runtime version
@@ -70,8 +75,10 @@ pub struct ConnectionParams {
 impl Default for ConnectionParams {
 	fn default() -> Self {
 		ConnectionParams {
+			uri: None,
 			host: "localhost".into(),
 			port: 9944,
+			path: None,
 			secure: false,
 			chain_runtime_version: ChainRuntimeVersion::Auto,
 		}
diff --git a/bridges/relays/lib-substrate-relay/src/cli/chain_schema.rs b/bridges/relays/lib-substrate-relay/src/cli/chain_schema.rs
index c5b802173ad94c1e427e6741f38e89cec4a65f03..6246bdbf015152fe0e82ac0a8287692df6a1ace9 100644
--- a/bridges/relays/lib-substrate-relay/src/cli/chain_schema.rs
+++ b/bridges/relays/lib-substrate-relay/src/cli/chain_schema.rs
@@ -92,15 +92,24 @@ macro_rules! declare_chain_runtime_version_params_cli_schema {
 macro_rules! declare_chain_connection_params_cli_schema {
 	($chain:ident, $chain_prefix:ident) => {
 		bp_runtime::paste::item! {
+			// TODO: https://github.com/paritytech/parity-bridges-common/issues/2909
+			// remove all obsolete arguments (separate URI components)
+
 			#[doc = $chain " connection params."]
 			#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
 			pub struct [<$chain ConnectionParams>] {
-				#[doc = "Connect to " $chain " node at given host."]
+				#[doc = "WS endpoint of " $chain ": full URI. Overrides all other connection string components (host, port, path, secure)."]
+				#[structopt(long)]
+				pub [<$chain_prefix _uri>]: Option<String>,
+				#[doc = "WS endpoint of " $chain ": host component."]
 				#[structopt(long, default_value = "127.0.0.1")]
 				pub [<$chain_prefix _host>]: String,
-				#[doc = "Connect to " $chain " node websocket server at given port."]
+				#[doc = "WS endpoint of " $chain ": port component."]
 				#[structopt(long, default_value = "9944")]
 				pub [<$chain_prefix _port>]: u16,
+				#[doc = "WS endpoint of " $chain ": path component."]
+				#[structopt(long)]
+				pub [<$chain_prefix _path>]: Option<String>,
 				#[doc = "Use secure websocket connection."]
 				#[structopt(long)]
 				pub [<$chain_prefix _secure>]: bool,
@@ -119,8 +128,10 @@ macro_rules! declare_chain_connection_params_cli_schema {
 						.[<$chain_prefix _runtime_version>]
 						.into_runtime_version(Chain::RUNTIME_VERSION)?;
 					Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams {
+						uri: self.[<$chain_prefix _uri>],
 						host: self.[<$chain_prefix _host>],
 						port: self.[<$chain_prefix _port>],
+						path: self.[<$chain_prefix _path>],
 						secure: self.[<$chain_prefix _secure>],
 						chain_runtime_version,
 					})
diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs
index d404f714b5878af1a79727ad778ff36fdd8b0267..27e9f1c21ba0dae1480ef8128afdfd635a1d22c2 100644
--- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs
+++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs
@@ -425,8 +425,10 @@ mod tests {
 					},
 				},
 				left: BridgeHubKusamaConnectionParams {
+					bridge_hub_kusama_uri: None,
 					bridge_hub_kusama_host: "bridge-hub-kusama-node-collator1".into(),
 					bridge_hub_kusama_port: 9944,
+					bridge_hub_kusama_path: None,
 					bridge_hub_kusama_secure: false,
 					bridge_hub_kusama_runtime_version: BridgeHubKusamaRuntimeVersionParams {
 						bridge_hub_kusama_version_mode: RuntimeVersionType::Bundle,
@@ -442,8 +444,10 @@ mod tests {
 					bridge_hub_kusama_transactions_mortality: Some(64),
 				},
 				left_relay: KusamaConnectionParams {
+					kusama_uri: None,
 					kusama_host: "kusama-alice".into(),
 					kusama_port: 9944,
+					kusama_path: None,
 					kusama_secure: false,
 					kusama_runtime_version: KusamaRuntimeVersionParams {
 						kusama_version_mode: RuntimeVersionType::Bundle,
@@ -452,8 +456,10 @@ mod tests {
 					},
 				},
 				right: BridgeHubPolkadotConnectionParams {
+					bridge_hub_polkadot_uri: None,
 					bridge_hub_polkadot_host: "bridge-hub-polkadot-collator1".into(),
 					bridge_hub_polkadot_port: 9944,
+					bridge_hub_polkadot_path: None,
 					bridge_hub_polkadot_secure: false,
 					bridge_hub_polkadot_runtime_version: BridgeHubPolkadotRuntimeVersionParams {
 						bridge_hub_polkadot_version_mode: RuntimeVersionType::Bundle,
@@ -469,8 +475,10 @@ mod tests {
 					bridge_hub_polkadot_transactions_mortality: Some(64),
 				},
 				right_relay: PolkadotConnectionParams {
+					polkadot_uri: None,
 					polkadot_host: "polkadot-alice".into(),
 					polkadot_port: 9944,
+					polkadot_path: None,
 					polkadot_secure: false,
 					polkadot_runtime_version: PolkadotRuntimeVersionParams {
 						polkadot_version_mode: RuntimeVersionType::Bundle,
diff --git a/bridges/relays/lib-substrate-relay/src/parachains/source.rs b/bridges/relays/lib-substrate-relay/src/parachains/source.rs
index 32d70cf425f0ba6fe88b3685d2d730a6eacd28da..4cc512b9d9b45c7334ffb121c1a8613b7f118550 100644
--- a/bridges/relays/lib-substrate-relay/src/parachains/source.rs
+++ b/bridges/relays/lib-substrate-relay/src/parachains/source.rs
@@ -106,6 +106,13 @@ where
 		// parachain head - we simply return `Unavailable`
 		let best_block_number = self.client.best_finalized_header_number().await?;
 		if is_ancient_block(at_block.number(), best_block_number) {
+			log::trace!(
+				target: "bridge",
+				"{} block {:?} is ancient. Cannot prove the {} header there",
+				P::SourceRelayChain::NAME,
+				at_block,
+				P::SourceParachain::NAME,
+			);
 			return Ok(AvailableHeader::Unavailable)
 		}