diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt
index 383759435419f726ff5778d6c9d7f30abebb3cf8..369f926cd02ee4b8f49ac56261dd23e163afbcb8 100644
--- a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt
@@ -10,6 +10,7 @@ import dagger.hilt.components.SingletonComponent
 import org.briarproject.mailbox.core.event.EventBus
 import org.briarproject.mailbox.core.lifecycle.IoExecutor
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager
+import org.briarproject.mailbox.core.settings.SettingsManager
 import org.briarproject.mailbox.core.system.AndroidWakeLockManager
 import org.briarproject.mailbox.core.system.Clock
 import org.briarproject.mailbox.core.system.LocationUtils
@@ -43,6 +44,7 @@ internal class AndroidTorModule {
     fun provideAndroidTorPlugin(
         @ApplicationContext app: Context,
         @IoExecutor ioExecutor: Executor,
+        settingsManager: SettingsManager,
         networkManager: NetworkManager,
         locationUtils: LocationUtils,
         clock: Clock,
@@ -55,6 +57,7 @@ internal class AndroidTorModule {
     ) = AndroidTorPlugin(
         ioExecutor,
         app,
+        settingsManager,
         networkManager,
         locationUtils,
         clock,
diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java
index 0992a4674e118abd9157f8abc4b1b52e4631a76b..a29caa9372e1af4fb007e33fc55fde66a5bf67f6 100644
--- a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java
@@ -1,16 +1,12 @@
 package org.briarproject.mailbox.core.tor;
 
-import static android.os.Build.VERSION.SDK_INT;
-import static org.briarproject.mailbox.core.util.LogUtils.info;
-import static org.slf4j.LoggerFactory.getLogger;
-import static java.util.Arrays.asList;
-
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
 
+import org.briarproject.mailbox.core.settings.SettingsManager;
 import org.briarproject.mailbox.core.system.AndroidWakeLock;
 import org.briarproject.mailbox.core.system.AndroidWakeLockManager;
 import org.briarproject.mailbox.core.system.Clock;
@@ -31,6 +27,11 @@ import java.util.zip.ZipInputStream;
 
 import javax.annotation.Nullable;
 
+import static android.os.Build.VERSION.SDK_INT;
+import static java.util.Arrays.asList;
+import static org.briarproject.mailbox.core.util.LogUtils.info;
+import static org.slf4j.LoggerFactory.getLogger;
+
 public class AndroidTorPlugin extends TorPlugin {
 
     private static final List<String> LIBRARY_ARCHITECTURES =
@@ -47,6 +48,7 @@ public class AndroidTorPlugin extends TorPlugin {
 
     AndroidTorPlugin(Executor ioExecutor,
                      Context ctx,
+                     SettingsManager settingsManager,
                      NetworkManager networkManager,
                      LocationUtils locationUtils,
                      Clock clock,
@@ -56,7 +58,7 @@ public class AndroidTorPlugin extends TorPlugin {
                      Backoff backoff,
                      @Nullable String architecture,
                      File torDirectory) {
-        super(ioExecutor, networkManager, locationUtils, clock, resourceProvider, circumventionProvider, backoff, architecture, torDirectory);
+        super(ioExecutor, settingsManager, networkManager, locationUtils, clock, resourceProvider, circumventionProvider, backoff, architecture, torDirectory);
         this.ctx = ctx;
         wakeLock = wakeLockManager.createWakeLock("TorPlugin");
         String nativeLibDir = ctx.getApplicationInfo().nativeLibraryDir;
diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt b/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt
index 4454de7df29d6b2a23ddd196d631faeb490bb982..051edfe6a889f91e80d11fef66db36ae1ff9f97e 100644
--- a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt
+++ b/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt
@@ -7,6 +7,7 @@ import dagger.hilt.components.SingletonComponent
 import org.briarproject.mailbox.core.event.EventBus
 import org.briarproject.mailbox.core.lifecycle.IoExecutor
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager
+import org.briarproject.mailbox.core.settings.SettingsManager
 import org.briarproject.mailbox.core.system.Clock
 import org.briarproject.mailbox.core.system.LocationUtils
 import org.briarproject.mailbox.core.system.ResourceProvider
@@ -37,6 +38,7 @@ internal class JavaTorModule {
     @Singleton
     fun provideJavaTorPlugin(
         @IoExecutor ioExecutor: Executor,
+        settingsManager: SettingsManager,
         networkManager: NetworkManager,
         locationUtils: LocationUtils,
         clock: Clock,
@@ -51,6 +53,7 @@ internal class JavaTorModule {
         val torDir = File(mailboxDir, "tor")
         return JavaTorPlugin(
             ioExecutor,
+            settingsManager,
             networkManager,
             locationUtils,
             clock,
diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java b/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java
index c9ce0a9e2cc00dfbceeef2ac0bb8b9bf69849d02..e097d26e7060728b0d692c4d6ea3de8001d4b7e0 100644
--- a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java
+++ b/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java
@@ -3,6 +3,7 @@ package org.briarproject.mailbox.core.tor;
 import com.sun.jna.Library;
 import com.sun.jna.Native;
 
+import org.briarproject.mailbox.core.settings.SettingsManager;
 import org.briarproject.mailbox.core.system.Clock;
 import org.briarproject.mailbox.core.system.LocationUtils;
 import org.briarproject.mailbox.core.system.ResourceProvider;
@@ -18,6 +19,7 @@ import javax.annotation.Nullable;
 public class JavaTorPlugin extends TorPlugin {
 
     JavaTorPlugin(Executor ioExecutor,
+                  SettingsManager settingsManager,
                   NetworkManager networkManager,
                   LocationUtils locationUtils,
                   Clock clock,
@@ -26,7 +28,7 @@ public class JavaTorPlugin extends TorPlugin {
                   Backoff backoff,
                   @Nullable String architecture,
                   File torDirectory) {
-        super(ioExecutor, networkManager, locationUtils, clock, resourceProvider,
+        super(ioExecutor, settingsManager, networkManager, locationUtils, clock, resourceProvider,
                 circumventionProvider, backoff, architecture, torDirectory);
     }
 
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
index 229da7f21a7e0cf4d8916406a3e7556b2faf13e8..740fbdc0fdadbdae5fa5f936a7db26d808b86519 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
@@ -8,6 +8,7 @@ import org.briarproject.mailbox.core.db.DatabaseModule
 import org.briarproject.mailbox.core.event.EventModule
 import org.briarproject.mailbox.core.lifecycle.LifecycleModule
 import org.briarproject.mailbox.core.server.WebServerModule
+import org.briarproject.mailbox.core.settings.SettingsModule
 import org.briarproject.mailbox.core.system.Clock
 import org.briarproject.mailbox.core.tor.TorModule
 import javax.inject.Singleton
@@ -18,6 +19,7 @@ import javax.inject.Singleton
         LifecycleModule::class,
         DatabaseModule::class,
         WebServerModule::class,
+        SettingsModule::class,
         TorModule::class,
     ]
 )
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorConstants.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorConstants.java
index f0a2b52b7d1a2ba9a6bebed445bc434ef19256fa..37bbcff87ab1b9fe572772c4c1c56b93fec262e7 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorConstants.java
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorConstants.java
@@ -2,28 +2,12 @@ package org.briarproject.mailbox.core.tor;
 
 public interface TorConstants {
 
-	// Transport properties
-	String PROP_ONION_V3 = "onion3";
+	// Settings
+	String SETTINGS_NAMESPACE = "Tor";
+	String HS_PRIVATE_KEY_V3 = "onionPrivKey3";
+	String HS_ADDRESS_V3 = "onionAddress3";
 
 	int SOCKS_PORT = 59050;
 	int CONTROL_PORT = 59051;
 
-	int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
-	int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
-
-	// Local settings (not shared with contacts)
-	String HS_PRIVATE_KEY_V3 = "onionPrivKey3";
-	String HS_V3_CREATED = "onionPrivKey3Created";
-
-	// Values for PREF_TOR_NETWORK
-	int PREF_TOR_NETWORK_AUTOMATIC = 0;
-	int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
-	int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
-
-	// Default values for local settings
-	boolean DEFAULT_PREF_PLUGIN_ENABLE = true;
-	int DEFAULT_PREF_TOR_NETWORK = PREF_TOR_NETWORK_AUTOMATIC;
-	boolean DEFAULT_PREF_TOR_MOBILE = true;
-	boolean DEFAULT_PREF_TOR_ONLY_WHEN_CHARGING = false;
-
 }
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorPlugin.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorPlugin.java
index 1ec14a2e1e37ef77ae933afd69a912a9eddec728..05929a6ef0dd4fdd7bcbf6fb2eaab759ddc7c1bc 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorPlugin.java
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/TorPlugin.java
@@ -4,12 +4,15 @@ import net.freehaven.tor.control.EventHandler;
 import net.freehaven.tor.control.TorControlConnection;
 
 import org.briarproject.mailbox.core.PoliteExecutor;
+import org.briarproject.mailbox.core.db.DbException;
 import org.briarproject.mailbox.core.event.Event;
 import org.briarproject.mailbox.core.event.EventListener;
 import org.briarproject.mailbox.core.lifecycle.IoExecutor;
 import org.briarproject.mailbox.core.lifecycle.Service;
 import org.briarproject.mailbox.core.lifecycle.ServiceException;
 import org.briarproject.mailbox.core.server.WebServerManager;
+import org.briarproject.mailbox.core.settings.Settings;
+import org.briarproject.mailbox.core.settings.SettingsManager;
 import org.briarproject.mailbox.core.system.Clock;
 import org.briarproject.mailbox.core.system.LocationUtils;
 import org.briarproject.mailbox.core.system.ResourceProvider;
@@ -44,6 +47,9 @@ import static java.util.Objects.requireNonNull;
 import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
 import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
 import static org.briarproject.mailbox.core.tor.TorConstants.CONTROL_PORT;
+import static org.briarproject.mailbox.core.tor.TorConstants.HS_ADDRESS_V3;
+import static org.briarproject.mailbox.core.tor.TorConstants.HS_PRIVATE_KEY_V3;
+import static org.briarproject.mailbox.core.tor.TorConstants.SETTINGS_NAMESPACE;
 import static org.briarproject.mailbox.core.tor.TorPlugin.State.ACTIVE;
 import static org.briarproject.mailbox.core.tor.TorPlugin.State.DISABLED;
 import static org.briarproject.mailbox.core.tor.TorPlugin.State.ENABLING;
@@ -70,6 +76,7 @@ abstract class TorPlugin implements Service, EventHandler, EventListener {
 
     private final Executor ioExecutor;
     private final Executor connectionStatusExecutor;
+    private final SettingsManager settingsManager;
     private final NetworkManager networkManager;
     private final LocationUtils locationUtils;
     private final Clock clock;
@@ -92,6 +99,7 @@ abstract class TorPlugin implements Service, EventHandler, EventListener {
     protected abstract long getLastUpdateTime();
 
     TorPlugin(Executor ioExecutor,
+              SettingsManager settingsManager,
               NetworkManager networkManager,
               LocationUtils locationUtils,
               Clock clock,
@@ -101,6 +109,7 @@ abstract class TorPlugin implements Service, EventHandler, EventListener {
               @Nullable String architecture,
               File torDirectory) {
         this.ioExecutor = ioExecutor;
+        this.settingsManager = settingsManager;
         this.networkManager = networkManager;
         this.locationUtils = locationUtils;
         this.clock = clock;
@@ -320,9 +329,16 @@ abstract class TorPlugin implements Service, EventHandler, EventListener {
     @IoExecutor
     private void publishHiddenService(String port) {
         if (!state.isTorRunning()) return;
-        // TODO get stored key
-        String privKey3 = null;
-        publishV3HiddenService(port, privKey3);
+
+        Settings s;
+        try {
+            s = settingsManager.getSettings(SETTINGS_NAMESPACE);
+        } catch (DbException e) {
+            logException(LOG, e);
+            s = new Settings();
+        }
+        String privateKey3 = s.get(HS_PRIVATE_KEY_V3);
+        publishV3HiddenService(port, privateKey3);
     }
 
     @IoExecutor
@@ -350,16 +366,21 @@ abstract class TorPlugin implements Service, EventHandler, EventListener {
             LOG.warn("Tor did not return a private key");
             return;
         }
+        Settings s = new Settings();
         String onion3 = response.get(HS_ADDRESS);
+        s.put(HS_ADDRESS_V3, onion3);
         info(LOG, () -> "V3 hidden service " + scrubOnion(onion3));
-        // TODO remove
+
+        // TODO remove before release
         LOG.warn("V3 hidden service: http://" + onion3 + ".onion");
+
         if (privKey == null) {
-            // TODO Save the hidden service's onion hostname
-//			p.put(PROP_ONION_V3, onion3);
-            // TODO Save the hidden service's private key for next time
-//			s.put(HS_PRIVATE_KEY_V3, response.get(HS_PRIVKEY));
-//			s.put(HS_V3_CREATED, String.valueOf(clock.currentTimeMillis()));
+            s.put(HS_PRIVATE_KEY_V3, response.get(HS_PRIVKEY));
+        }
+        try {
+            settingsManager.mergeSettings(s, SETTINGS_NAMESPACE);
+        } catch (DbException e) {
+            logException(LOG, e);
         }
     }