diff --git a/src/sbbs3/echocfg.c b/src/sbbs3/echocfg.c
index c01557a61afc9574c63208e6c6fa76c7bac41e76..9f45d1c8832d0043246a807fdbbc9b3c34132398 100644
--- a/src/sbbs3/echocfg.c
+++ b/src/sbbs3/echocfg.c
@@ -87,6 +87,8 @@ void global_settings(void)
 			,cfg.auto_utf8 ? "Yes":"No");
 		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Use Outboxes for Mail Files "
 			,cfg.use_outboxes ? "Yes":"No");
+		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Sort Linked Node List  "
+			,cfg.sort_nodelist ? "Yes":"No");
 
 		sprintf(opt[i++], "%-30s %s", "BSY Mutex File Timeout", duration_to_vstr(cfg.bsy_timeout, duration, sizeof(duration)));
 		if(cfg.flo_mailer) {
@@ -156,6 +158,9 @@ void global_settings(void)
 			"    send files from configured outboxes in addition to the normal\n"
 			"    outbound directories, even when this option is set to `No`.\n"
 			"\n"
+			"`Sort Linked Node List` instructs SBBSecho to sort the list of linked\n"
+			"    nodes (in sbbsecho.ini) both when readnig and writing the file.\n"
+			"\n"
 			"`BSY Mutex File Timeout` determines the maximum age of an existing\n"
 			"    mutex file (`*.bsy`) before SBBSecho will act as though the mutex\n"
 			"    file was not present.  This setting applies to the global\n"
@@ -289,34 +294,44 @@ void global_settings(void)
 				break;
 			}
 			case 11:
+			{
+				int k = !cfg.sort_nodelist;
+				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
+					,"Sort List of Linked Nodes",uifcYesNoOpts)) {
+					case 0:	cfg.sort_nodelist = true;	break;
+					case 1:	cfg.sort_nodelist = false;	break;
+				}
+				break;
+			}
+			case 12:
 				duration_to_vstr(cfg.bsy_timeout, duration, sizeof(duration));
 				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "BSY Mutex File Timeout", duration, 10, K_EDIT) > 0)
 					cfg.bsy_timeout = (ulong)parse_duration(duration);
 				break;
 
-			case 12:
+			case 13:
 				duration_to_vstr(cfg.bso_lock_delay, duration, sizeof(duration));
 				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Delay Between BSO Lock Attempts", duration, 10, K_EDIT) > 0)
 					cfg.bso_lock_delay = (ulong)parse_duration(duration);
 				break;
 
-			case 13:
+			case 14:
 				sprintf(str, "%lu", cfg.bso_lock_attempts);
 				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum BSO Lock Attempts", str, 5, K_EDIT|K_NUMBER) > 0)
 					cfg.bso_lock_attempts = atoi(str);
 				break;
 
-			case 14:
+			case 15:
 				uifc.input(WIN_MID|WIN_SAV,0,0
 					,"BinkP Capabilities (BinkIT)", cfg.binkp_caps, sizeof(cfg.binkp_caps)-1, K_EDIT);
 				break;
 
-			case 15:
+			case 16:
 				uifc.input(WIN_MID|WIN_SAV,0,0
 					,"BinkP Sysop Name (BinkIT)", cfg.binkp_sysop, sizeof(cfg.binkp_sysop)-1, K_EDIT);
 				break;
 
-			case 16:
+			case 17:
 			{
 				int k = !cfg.binkp_plainAuthOnly;
 				strcpy(opt[0], "Plain-Password Only");
@@ -334,7 +349,7 @@ void global_settings(void)
 				break;
 			}
 
-			case 17:
+			case 18:
 			{
 				if(cfg.binkp_plainAuthOnly) {
 					uifc.msg("CRAM-MD5 authentication/encryption has been disabled globally");
diff --git a/src/sbbs3/rechocfg.c b/src/sbbs3/rechocfg.c
index 3b383df1cc44d0168aeca8aeabab8af60e352f99..11fe1d854d651c9118617131b280442f66f38e5d 100644
--- a/src/sbbs3/rechocfg.c
+++ b/src/sbbs3/rechocfg.c
@@ -275,6 +275,7 @@ bool sbbsecho_read_ini(sbbsecho_cfg_t* cfg)
 	cfg->strip_soft_cr			= iniGetBool(ini, ROOT_SECTION, "StripSoftCRs", cfg->strip_soft_cr);
 	cfg->use_outboxes			= iniGetBool(ini, ROOT_SECTION, "UseOutboxes", cfg->use_outboxes);
 	cfg->auto_utf8				= iniGetBool(ini, ROOT_SECTION, "AutoUTF8", cfg->auto_utf8);
+	cfg->sort_nodelist			= iniGetBool(ini, ROOT_SECTION, "SortNodeList", cfg->sort_nodelist);
 
 	/* EchoMail options: */
 	cfg->maxbdlsize				= (ulong)iniGetBytes(ini, ROOT_SECTION, "BundleSize", 1, cfg->maxbdlsize);
@@ -339,6 +340,8 @@ bool sbbsecho_read_ini(sbbsecho_cfg_t* cfg)
 	/* Links/Nodes: */
 	/****************/
 	str_list_t nodelist = iniGetSectionList(ini, "node:");
+	if(cfg->sort_nodelist)
+		strListSortAlphaCase(nodelist);
 	cfg->nodecfgs = strListCount(nodelist);
 	if((cfg->nodecfg = realloc(cfg->nodecfg, sizeof(nodecfg_t)*cfg->nodecfgs)) == NULL) {
 		strListFree(&nodelist);
@@ -545,6 +548,7 @@ bool sbbsecho_write_ini(sbbsecho_cfg_t* cfg)
 	iniSetBool(&ini,		ROOT_SECTION, "StripSoftCRs"			,cfg->strip_soft_cr				,style);
 	iniSetBool(&ini,		ROOT_SECTION, "UseOutboxes"				,cfg->use_outboxes				,style);
 	iniSetBool(&ini,		ROOT_SECTION, "AutoUTF8"				,cfg->auto_utf8					,style);
+	iniSetBool(&ini,		ROOT_SECTION, "SortNodeList"			,cfg->sort_nodelist				,style);
 	iniSetBool(&ini,		ROOT_SECTION, "ConvertTearLines"		,cfg->convert_tear				,style);
 	iniSetBool(&ini,		ROOT_SECTION, "FuzzyNetmailZones"		,cfg->fuzzy_zone				,style);
 	iniSetBool(&ini,		ROOT_SECTION, "BinkleyStyleOutbound"	,cfg->flo_mailer				,style);
@@ -637,6 +641,8 @@ bool sbbsecho_write_ini(sbbsecho_cfg_t* cfg)
 		iniSetBool(&ini		,section,	"BinkpTLS",node->binkp_tls, style);
 		iniSetString(&ini	,section,	"BinkpSourceAddress",node->binkp_src, style);
 	}
+	if(cfg->sort_nodelist)
+		iniSortSections(&ini, "node:", /* sort keys: */false);
 
 	/**************/
 	/* EchoLists: */
diff --git a/src/sbbs3/sbbsecho.h b/src/sbbs3/sbbsecho.h
index 707c47cbfdf2b7bc3db289b35fb6e3b91421d61d..d7a930b8aef08be40e8fad07345ac9b639e672d5 100644
--- a/src/sbbs3/sbbsecho.h
+++ b/src/sbbs3/sbbsecho.h
@@ -29,7 +29,7 @@
 #include "ini_file.h"
 
 #define SBBSECHO_VERSION_MAJOR		3
-#define SBBSECHO_VERSION_MINOR		14
+#define SBBSECHO_VERSION_MINOR		15
 
 #define SBBSECHO_PRODUCT_CODE		0x12FF	/* from http://ftsc.org/docs/ftscprod.013 */
 
@@ -228,6 +228,7 @@ typedef struct {
 	bool		binkp_plainAuthOnly;
 	bool		binkp_plainTextOnly;
 	bool		used_include;
+	bool		sort_nodelist;
 } sbbsecho_cfg_t;
 
 extern ini_style_t sbbsecho_ini_style;