diff --git a/components/net/cpp/include/ftl/net/universe.hpp b/components/net/cpp/include/ftl/net/universe.hpp
index 54748fdc6bdc14fe059276a34776bd716642d988..260e9dea3a753380b90844eb4686c5de89d718b2 100644
--- a/components/net/cpp/include/ftl/net/universe.hpp
+++ b/components/net/cpp/include/ftl/net/universe.hpp
@@ -236,6 +236,7 @@ class Universe : public ftl::Configurable {
 	
 	std::vector<ftl::net::Listener*> listeners_;
 	std::vector<ftl::net::Peer*> peers_;
+	std::unordered_map<std::string, ftl::net::Peer*> peer_by_uri_;
 	//std::map<std::string, std::vector<ftl::UUID>> subscribers_;
 	//std::unordered_set<std::string> owned_;
 	std::map<ftl::UUID, ftl::net::Peer*> peer_ids_;
diff --git a/components/net/cpp/src/universe.cpp b/components/net/cpp/src/universe.cpp
index 783d44707936051cbc4d9c34c1956c351f04fd45..8eaff08b4caa5dde5e8ed11cad77e4f48ca19477 100644
--- a/components/net/cpp/src/universe.cpp
+++ b/components/net/cpp/src/universe.cpp
@@ -149,12 +149,21 @@ bool Universe::listen(const string &addr) {
 }
 
 Peer *Universe::connect(const string &addr) {
+	// Check if already connected
+	{
+		UNIQUE_LOCK(net_mutex_,lk);
+		if (peer_by_uri_.find(addr) != peer_by_uri_.end()) {
+			return peer_by_uri_[addr];
+		}
+	}
+
 	auto p = new Peer(addr.c_str(), this, &disp_);
 	if (!p) return nullptr;
 	
 	if (p->status() != Peer::kInvalid) {
 		UNIQUE_LOCK(net_mutex_,lk);
 		peers_.push_back(p);
+		peer_by_uri_[addr] = p;
 	}
 	
 	_installBindings(p);
diff --git a/components/streams/include/ftl/streams/feed.hpp b/components/streams/include/ftl/streams/feed.hpp
index 7f83447ac626db2cffbc5324e2c7be5bc742a2c7..a06cc3405ab27fc52cc0a60a0b911b99da2064f8 100644
--- a/components/streams/include/ftl/streams/feed.hpp
+++ b/components/streams/include/ftl/streams/feed.hpp
@@ -141,6 +141,8 @@ public:
 	Filter* filter(const std::unordered_set<ftl::codecs::Channel> &channels);
 
 	void removeFilter(Filter* filter);
+
+	void autoConnect();
 };
 
 }
diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp
index cdc5e12f9674fc6e550411378691174165d1ff74..b11a56a67d7ae6c3854c3b960bcd139a861ae8eb 100644
--- a/components/streams/src/feed.cpp
+++ b/components/streams/src/feed.cpp
@@ -63,7 +63,8 @@ Feed::Feed(nlohmann::json &config, ftl::net::Universe*net) :
 
 	//feed_config = ftl::loadJSON(FTL_LOCAL_CONFIG_ROOT "/feed.json");
 	restore(ftl::Configurable::getID(), {
-		"recent_files"
+		"recent_files",
+		"known_hosts"
 	});
 
 	pool_ = std::make_unique<ftl::data::Pool>(3,5);
@@ -158,6 +159,8 @@ Feed::Feed(nlohmann::json &config, ftl::net::Universe*net) :
 	});
 
 	stream_->begin();
+
+	autoConnect();
 }
 
 Feed::~Feed() {
@@ -350,6 +353,16 @@ std::vector<std::string> Feed::availableDeviceSources() {
 	return {};
 }
 
+void Feed::autoConnect() {
+	ftl::pool.push([this](int id) {
+		auto &known_hosts = getConfig()["known_hosts"];
+
+		for (auto &h : known_hosts.items()) {
+			net_->connect(h.key());
+		}
+	});
+}
+
 bool Feed::sourceAvailable(const std::string &uri) {
 	return false;
 }
@@ -483,6 +496,10 @@ uint32_t Feed::add(const std::string &path) {
 		// TODO: do not connect same uri twice
 		// TODO: write unit test
 
+		auto &known_hosts = getConfig()["known_hosts"];
+		auto &host_details = known_hosts[uri.getBaseURI()];
+		host_details["last_open"] = ftl::timer::get_time();
+
 		net_->connect(path)->waitConnection();
 
 	}