diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js
index 3508bf5..05cd185 100644
--- src/wp-admin/js/customize-controls.js
+++ src/wp-admin/js/customize-controls.js
@@ -4055,7 +4055,7 @@
 			// ssl certs.
 
 			previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) {
-				var result, urlParser, newPreviewUrl, schemeMatchingPreviewUrl, queryParams;
+				var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = [];
 				urlParser = document.createElement( 'a' );
 				urlParser.href = to;
 
@@ -4077,31 +4077,30 @@
 					}
 				}
 
-				newPreviewUrl = urlParser.href;
-				urlParser.protocol = previewer.scheme.get() + ':';
-				schemeMatchingPreviewUrl = urlParser.href;
+				parsedCandidateUrls.push( urlParser );
+
+				// Prepend list with URL that matches the scheme/protocol of the iframe.
+				if ( previewer.scheme.get() + ':' !== urlParser.protocol ) {
+					urlParser = document.createElement( 'a' );
+					urlParser.href = parsedCandidateUrls[0].href;
+					urlParser.protocol = previewer.scheme.get() + ':';
+					parsedCandidateUrls.unshift( urlParser );
+				}
 
 				// Attempt to match the URL to the control frame's scheme
 				// and check if it's allowed. If not, try the original URL.
-				$.each( [ schemeMatchingPreviewUrl, newPreviewUrl ], function( i, url ) {
-					$.each( previewer.allowedUrls, function( i, allowed ) {
-						var path;
-
-						allowed = allowed.replace( /\/+$/, '' );
-						path = url.replace( allowed, '' );
-
-						if ( 0 === url.indexOf( allowed ) && /^([/#?]|$)/.test( path ) ) {
-							result = url;
-							return false;
+				parsedAllowedUrl = document.createElement( 'a' );
+				_.find( parsedCandidateUrls, function( parsedCandidateUrl ) {
+					return ! _.isUndefined( _.find( previewer.allowedUrls, function( allowedUrl ) {
+						parsedAllowedUrl.href = allowedUrl;
+						if ( urlParser.protocol === parsedAllowedUrl.protocol && urlParser.host === parsedAllowedUrl.host && 0 === parsedAllowedUrl.pathname.indexOf( urlParser.pathname ) ) {
+							result = parsedCandidateUrl.href;
+							return true;
 						}
-					});
-					if ( result ) {
-						return false;
-					}
-				});
+					} ) );
+				} );
 
-				// If we found a matching result, return it. If not, bail.
-				return result ? result : null;
+				return result;
 			});
 
 			previewer.bind( 'ready', previewer.ready );
diff --git src/wp-includes/js/customize-base.js src/wp-includes/js/customize-base.js
index 11b868c..a8fa41d 100644
--- src/wp-includes/js/customize-base.js
+++ src/wp-includes/js/customize-base.js
@@ -654,7 +654,8 @@ window.wp = window.wp || {};
 			this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
 				var urlParser = document.createElement( 'a' );
 				urlParser.href = to;
-				return urlParser.protocol + '//' + urlParser.hostname;
+				// Port stripping needed by IE since it adds to host but not to event.origin.
+				return urlParser.protocol + '//' + urlParser.host.replace( /:80$/, '' );
 			});
 
 			// first add with no value
diff --git src/wp-includes/js/customize-preview.js src/wp-includes/js/customize-preview.js
index 52de00d..f1bd852 100644
--- src/wp-includes/js/customize-preview.js
+++ src/wp-includes/js/customize-preview.js
@@ -275,13 +275,13 @@
 	 * @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
 	 * @param {string} element.search Query string.
 	 * @param {string} element.pathname Path.
-	 * @param {string} element.hostname Hostname.
+	 * @param {string} element.host Host.
 	 * @param {object} [options]
 	 * @param {object} [options.allowAdminAjax=false] Allow admin-ajax.php requests.
 	 * @returns {boolean} Is appropriate for changeset link.
 	 */
 	api.isLinkPreviewable = function isLinkPreviewable( element, options ) {
-		var hasMatchingHost, urlParser, args;
+		var matchesAllowedUrl, parsedAllowedUrl, args;
 
 		args = _.extend( {}, { allowAdminAjax: false }, options || {} );
 
@@ -294,15 +294,12 @@
 			return false;
 		}
 
-		urlParser = document.createElement( 'a' );
-		hasMatchingHost = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) {
-			urlParser.href = allowedUrl;
-			if ( urlParser.hostname === element.hostname && urlParser.protocol === element.protocol ) {
-				return true;
-			}
-			return false;
+		parsedAllowedUrl = document.createElement( 'a' );
+		matchesAllowedUrl = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) {
+			parsedAllowedUrl.href = allowedUrl;
+			return parsedAllowedUrl.protocol === element.protocol && parsedAllowedUrl.host === element.host && 0 === element.pathname.indexOf( parsedAllowedUrl.pathname );
 		} ) );
-		if ( ! hasMatchingHost ) {
+		if ( ! matchesAllowedUrl ) {
 			return false;
 		}
 
@@ -331,7 +328,9 @@
 	 * @access protected
 	 *
 	 * @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
-	 * @param {object} element.search Query string.
+	 * @param {string} element.search Query string.
+	 * @param {string} element.host Host.
+	 * @param {string} element.protocol Protocol.
 	 * @returns {void}
 	 */
 	api.prepareLinkPreview = function prepareLinkPreview( element ) {
@@ -348,7 +347,7 @@
 		}
 
 		// Make sure links in preview use HTTPS if parent frame uses HTTPS.
-		if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.hostname ) ) {
+		if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.host ) ) {
 			element.protocol = 'https:';
 		}
 
@@ -496,7 +495,7 @@
 		urlParser.href = form.action;
 
 		// Make sure forms in preview use HTTPS if parent frame uses HTTPS.
-		if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.hostname ) ) {
+		if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.host ) ) {
 			urlParser.protocol = 'https:';
 			form.action = urlParser.href;
 		}
