diff --git a/src/simutrans/gui/server_frame.cc b/src/simutrans/gui/server_frame.cc
index 9b0b81625..b8e360a72 100644
--- a/src/simutrans/gui/server_frame.cc
+++ b/src/simutrans/gui/server_frame.cc
@@ -13,6 +13,7 @@
 
 #include "../dataobj/environment.h"
 #include "../dataobj/translator.h"
+#include "../sys/simsys.h"
 #include "../display/simgraph.h"
 #include "../network/network.h"
 #include "../network/network_cmd_ingame.h"
@@ -60,6 +61,45 @@ public:
 };
 
 
+void server_frame_t::load_pakset_servers()
+{
+	pakset_servers.clear();
+	std::string filepath = env_t::pak_dir + "config/servers.tab";
+	FILE *f = dr_fopen(filepath.c_str(), "r");
+	if(  !f  ) {
+		return;
+	}
+	char line[512];
+	while(  fgets(line, sizeof(line), f)  ) {
+		// skip leading whitespace
+		char *p = line;
+		while(  *p == ' '  ||  *p == '\t'  ) { p++; }
+		// skip comments and empty lines
+		if(  *p == '#'  ||  *p == '\0'  ||  *p == '\n'  ||  *p == '\r'  ) {
+			continue;
+		}
+		// find '='
+		char *eq = strchr(p, '=');
+		if(  !eq  ) { continue; }
+		// trim name (right-trim up to '=')
+		char *name_end = eq - 1;
+		while(  name_end > p  &&  (*name_end == ' '  ||  *name_end == '\t')  ) { name_end--; }
+		std::string name(p, name_end - p + 1);
+		// trim address (left-trim after '=')
+		char *addr = eq + 1;
+		while(  *addr == ' '  ||  *addr == '\t'  ) { addr++; }
+		// right-trim address
+		char *addr_end = addr + strlen(addr) - 1;
+		while(  addr_end > addr  &&  (*addr_end == ' '  ||  *addr_end == '\t'  ||  *addr_end == '\n'  ||  *addr_end == '\r')  ) { addr_end--; }
+		std::string dns(addr, addr_end - addr + 1);
+		if(  !name.empty()  &&  !dns.empty()  ) {
+			pakset_servers.push_back({ name, dns });
+		}
+	}
+	fclose(f);
+}
+
+
 server_frame_t::server_frame_t() :
 	gui_frame_t( translator::translate("Game info") ),
 	gi(welt),
@@ -169,6 +209,7 @@ server_frame_t::server_frame_t() :
 	if (  !env_t::networkmode  ) {
 		// only update serverlist, when not already in network mode
 		// otherwise desync to current game may happen
+		load_pakset_servers();
 		update_serverlist();
 	}
 
@@ -307,6 +348,14 @@ bool server_frame_t::update_serverlist ()
 #endif
 	}
 
+	// Add servers defined in pak_dir/config/servers.tab first
+	for(  const pakset_server_t &s : pakset_servers  ) {
+		cbuffer_t name, dns, altdns;
+		name.append( s.name.c_str() );
+		dns.append(  s.dns.c_str()  );
+		serverlist.new_component<server_scrollitem_t>( name, dns, altdns, true, color_idx_to_rgb(COL_BLUE) );
+	}
+
 	// Parse listing into CSV_t object
 	CSV_t csvdata( buf.get_str() );
 	int ret;
diff --git a/src/simutrans/gui/server_frame.h b/src/simutrans/gui/server_frame.h
index f4db7311d..9f4c50e8c 100644
--- a/src/simutrans/gui/server_frame.h
+++ b/src/simutrans/gui/server_frame.h
@@ -16,6 +16,8 @@
 #include "components/gui_textinput.h"
 #include "../dataobj/gameinfo.h"
 #include "../utils/cbuffer.h"
+#include <string>
+#include <vector>
 
 class gui_minimap_t;
 /**
@@ -94,6 +96,13 @@ private:
 	 */
 	bool update_serverlist ();
 
+	/// Servers defined in pak_dir/config/servers.tab (name, address pairs)
+	struct pakset_server_t { std::string name; std::string dns; };
+	std::vector<pakset_server_t> pakset_servers;
+
+	/// Load servers from pak_dir/config/servers.tab
+	void load_pakset_servers();
+
 public:
 	server_frame_t();
 
