--- a/etc/inc/interfaces.inc
+++ b/etc/inc/interfaces.inc
@@ -1,12 +1,71 @@
-		// Create IPsec interface
-		if (does_interface_exist($ipsecif)) {
-			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
+		/*
+		 * Preserve an existing IPv4 VTI when its runtime configuration already
+		 * matches the configured reqid, outer tunnel, and inner addresses.
+		 */
+		$vti_reconfigure = true;
+		$vti_exists = does_interface_exist($ipsecif);
+		if ($vti_exists) {
+			$ifconfig_output = array();
+			$ifconfig_status = 0;
+			exec("/sbin/ifconfig -f inet:cidr " . escapeshellarg($ipsecif),
+				$ifconfig_output, $ifconfig_status);
+			$ifconfig_output = implode("\n", $ifconfig_output);
+			$expected_reqid = $ipsec_reqid_base + $reqids[$ipsecif];
+			$outer_inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
+
+			$vti_matches =
+				($ifconfig_status === 0) &&
+				preg_match('/^' . preg_quote($ipsecif, '/') .
+					':.*<[^>]*\bUP\b[^>]*>/m', $ifconfig_output) &&
+				preg_match('/^\s*reqid:\s*' . preg_quote((string)$expected_reqid, '/') .
+					'\s*$/m', $ifconfig_output) &&
+				preg_match('/^\s*tunnel\s+' . preg_quote($outer_inet, '/') . '\s+' .
+					preg_quote($left_spec, '/') . '\s+-->\s+' .
+					preg_quote($right_spec, '/') . '\s*$/m', $ifconfig_output);
+
+			$expected_v4_count = 0;
+			foreach ($addrs as $addr) {
+				if (is_v6($addr['left'])) {
+					$vti_matches = false;
+					break;
+				}
+				$left_addr = explode('/', $addr['left'], 2);
+				$right_addr = explode('/', $addr['right'], 2);
+				if (empty($left_addr[0]) || empty($left_addr[1]) ||
+				    empty($right_addr[0])) {
+					$vti_matches = false;
+					break;
+				}
+				$expected_v4_count++;
+				if (!preg_match('/^\s*inet\s+' .
+					preg_quote($left_addr[0], '/') . '\s+-->\s+' .
+					preg_quote($right_addr[0], '/') . '\/' .
+					preg_quote($left_addr[1], '/') . '\s*$/m',
+					$ifconfig_output)) {
+					$vti_matches = false;
+					break;
+				}
+			}
+			preg_match_all('/^\s*inet\s+/m', $ifconfig_output, $current_v4);
+			if (count($current_v4[0]) !== $expected_v4_count) {
+				$vti_matches = false;
+			}
+			if ($vti_matches) {
+				$vti_reconfigure = false;
+				log_error(sprintf("IPsec VTI %s unchanged, preserving interface", $ipsecif));
+			}
 		}
-		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
 
-		/* Apply the outer tunnel addresses to the interface */
-		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
-		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
+		if ($vti_reconfigure) {
+			if ($vti_exists) {
+				mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
+			}
+			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
+
+			/* Apply the outer tunnel addresses to the interface */
+			$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
+			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
+		}
 
 		/* Loop through all of the addresses for this interface and apply them as needed */
 		foreach ($addrs as $addr) {
@@ -21,7 +80,9 @@
 				$right = escapeshellarg((explode('/', $addr['right'], 2))[0]);
 			}
 
-			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
+			if ($vti_reconfigure) {
+				mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
+			}
 			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
 			if (empty($addr['alias'])) {
 				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", (explode('/', $addr['right'], 2))[0]);