diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 5b4b0ba029227e9528726389c0d0dfcaffe859b0..452860a15756ff9a9a6a0199e3b55d7b4d7e8666 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -84,9 +84,20 @@ public class TunnelController implements Logging {
     public static final String TYPE_SOCKS_IRC = "socksirctunnel";
     public static final String TYPE_STD_CLIENT = "client";
     public static final String TYPE_STD_SERVER = "server";
+    /** Client in the UI and I2P side but a server on the localhost side */
     public static final String TYPE_STREAMR_CLIENT = "streamrclient";
+    /** Server in the UI and I2P side but a client on the localhost side */
     public static final String TYPE_STREAMR_SERVER = "streamrserver";
 
+    /**
+     *  This is guaranteed to be available.
+     *  @since 0.9.17
+     */
+    public static final SigType PREFERRED_SIGTYPE = SigType.ECDSA_SHA256_P256.isAvailable() ?
+                                                    SigType.ECDSA_SHA256_P256 :
+                                                    SigType.DSA_SHA1;
+
+
     /**
      * Create a new controller for a tunnel out of the specific config options.
      * The config may contain a large number of options - only ones that begin in
@@ -125,15 +136,12 @@ public class TunnelController implements Logging {
      */
     private boolean createPrivateKey() {
         I2PClient client = I2PClientFactory.createClient();
-        String filename = getPrivKeyFile();
-        if ( (filename == null) || (filename.trim().length() <= 0) ) {
+        File keyFile = getPrivateKeyFile();
+        if (keyFile == null) {
             log("No filename specified for the private key");
             return false;
         }
         
-        File keyFile = new File(getPrivKeyFile());
-        if (!keyFile.isAbsolute())
-            keyFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), getPrivKeyFile());
         if (keyFile.exists()) {
             //log("Not overwriting existing private keys in " + keyFile.getAbsolutePath());
             return true;
@@ -145,11 +153,11 @@ public class TunnelController implements Logging {
         FileOutputStream fos = null;
         try {
             fos = new SecureFileOutputStream(keyFile);
-            SigType stype = I2PClient.DEFAULT_SIGTYPE;
+            SigType stype = PREFERRED_SIGTYPE;
             String st = _config.getProperty(OPT_SIG_TYPE);
             if (st != null) {
                 SigType type = SigType.parseSigType(st);
-                if (type != null)
+                if (type != null && type.isAvailable())
                     stype = type;
                 else
                     log("Unsupported sig type " + st + ", reverting to " + stype);
@@ -586,11 +594,12 @@ public class TunnelController implements Logging {
                     _config.setProperty(OPT_LOW_TAGS, "14");
             }
             // same default logic as in EditBean.getSigType()
-            if ((type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) || type.equals(TYPE_SOCKS_IRC))
-                && !Boolean.valueOf(getSharedClient())) {
-                if (!_config.containsKey(OPT_SIG_TYPE) &&
-                    SigType.ECDSA_SHA256_P256.isAvailable())
-                    _config.setProperty(OPT_SIG_TYPE, "ECDSA_SHA256_P256");
+            if (!isClient(type) ||
+                ((type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) ||
+                  type.equals(TYPE_SOCKS_IRC) || type.equals(TYPE_STREAMR_CLIENT))
+                 && !Boolean.valueOf(getSharedClient()))) {
+                if (!_config.containsKey(OPT_SIG_TYPE))
+                    _config.setProperty(OPT_SIG_TYPE, PREFERRED_SIGTYPE.name());
             }
         }
 
@@ -640,6 +649,34 @@ public class TunnelController implements Logging {
     public String getI2CPHost() { return _config.getProperty(PROP_I2CP_HOST); }
     public String getI2CPPort() { return _config.getProperty(PROP_I2CP_PORT); }
 
+    /**
+     *  Is it a client or server in the UI and I2P side?
+     *  Note that a streamr client is a UI and I2P client but a server on the localhost side.
+     *  Note that a streamr server is a UI and I2P server but a client on the localhost side.
+     *
+     *  @since 0.9.17
+     */
+    public boolean isClient() {
+        return isClient(getType());
+    }
+
+    /**
+     *  Is it a client or server in the UI and I2P side?
+     *  Note that a streamr client is a UI and I2P client but a server on the localhost side.
+     *  Note that a streamr server is a UI and I2P server but a client on the localhost side.
+     *
+     *  @since 0.9.17 moved from IndexBean
+     */
+    public static boolean isClient(String type) {
+        return TYPE_STD_CLIENT.equals(type) || 
+               TYPE_HTTP_CLIENT.equals(type) ||
+               TYPE_SOCKS.equals(type) ||
+               TYPE_SOCKS_IRC.equals(type) ||
+               TYPE_CONNECT.equals(type) ||
+               TYPE_STREAMR_CLIENT.equals(type) ||
+               TYPE_IRC_CLIENT.equals(type);
+    }
+
     /**
      *  These are the ones with a prefix of "option."
      *
@@ -664,7 +701,12 @@ public class TunnelController implements Logging {
     public String getTargetHost() { return _config.getProperty(PROP_TARGET_HOST); }
     public String getTargetPort() { return _config.getProperty(PROP_TARGET_PORT); }
     public String getSpoofedHost() { return _config.getProperty(PROP_SPOOFED_HOST); }
+
+    /**
+     *  Probably not absolute. May be null. getPrivateKeyFile() recommended.
+     */
     public String getPrivKeyFile() { return _config.getProperty(PROP_FILE); }
+
     public String getListenPort() { return _config.getProperty(PROP_LISTEN_PORT); }
     public String getTargetDestination() { return _config.getProperty(PROP_DEST); }
     public String getProxyList() { return _config.getProperty(PROP_PROXIES); }
@@ -674,30 +716,59 @@ public class TunnelController implements Logging {
     public boolean getStartOnLoad() { return Boolean.parseBoolean(_config.getProperty(PROP_START, "true")); }
     public boolean getPersistentClientKey() { return Boolean.parseBoolean(_config.getProperty(OPT_PERSISTENT)); }
 
+    /**
+     *  Does not necessarily exist.
+     *  @return absolute path or null if unset
+     *  @since 0.9.17
+     */
+    public File getPrivateKeyFile() {
+        String f = getPrivKeyFile();
+        if (f == null)
+            return null;
+        f = f.trim();
+        if (f.length() == 0)
+            return null;
+        File rv = new File(f);
+        if (!rv.isAbsolute())
+            rv = new File(I2PAppContext.getGlobalContext().getConfigDir(), f);
+        return rv;
+    }
+
+    /**
+     *  Returns null if not running.
+     *  @return Base64 or null
+     */
     public String getMyDestination() {
-        if (_tunnel != null) {
-            List<I2PSession> sessions = _tunnel.getSessions();
-            for (int i = 0; i < sessions.size(); i++) {
-                I2PSession session = sessions.get(i);
-                Destination dest = session.getMyDestination();
-                if (dest != null)
-                    return dest.toBase64();
-            }
-        }
+        Destination dest = getDestination();
+        if (dest != null)
+            return dest.toBase64();
         return null;
     }
     
     /**
+     *  Returns null if not running.
      *  @return "{52 chars}.b32.i2p" or null
      */
     public String getMyDestHashBase32() {
+        Destination dest = getDestination();
+        if (dest != null)
+            return dest.toBase32();
+        return null;
+    }
+    
+    /**
+     *  Returns null if not running.
+     *  @return Destination or null
+     *  @since 0.9.17
+     */
+    public Destination getDestination() {
         if (_tunnel != null) {
             List<I2PSession> sessions = _tunnel.getSessions();
             for (int i = 0; i < sessions.size(); i++) {
                 I2PSession session = sessions.get(i);
                 Destination dest = session.getMyDestination();
                 if (dest != null)
-                    return dest.toBase32();
+                    return dest;
             }
         }
         return null;
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
index 5217befbea7ee487b915252f9702fc5ec6a99f27..bc0748e8375d42f7a29a4a807bf173dd47d2da77 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
@@ -41,6 +41,11 @@ import net.i2p.util.Addresses;
 public class EditBean extends IndexBean {
     public EditBean() { super(); }
     
+    /**
+     *  Is it a client or server in the UI and I2P side?
+     *  Note that a streamr client is a UI and I2P client but a server on the localhost side.
+     *  Note that a streamr server is a UI and I2P server but a client on the localhost side.
+     */
     public static boolean staticIsClient(int tunnel) {
         TunnelControllerGroup group = TunnelControllerGroup.getInstance();
         if (group == null)
@@ -190,6 +195,12 @@ public class EditBean extends IndexBean {
         String ttype;
         boolean isShared;
         if (tunnel >= 0) {
+            Destination d = getDestination(tunnel);
+            if (d != null) {
+                type = d.getSigType();
+                if (type != null)
+                    return type.getCode();
+            }
             String stype = getProperty(tunnel, I2PClient.PROP_SIGTYPE, null);
             type = stype != null ? SigType.parseSigType(stype) : null;
             ttype = getTunnelType(tunnel);
@@ -201,12 +212,13 @@ public class EditBean extends IndexBean {
         }
         if (type == null) {
             // same default logic as in TunnelController.setConfig()
-            if ((TunnelController.TYPE_IRC_CLIENT.equals(ttype) ||
-                 TunnelController.TYPE_SOCKS_IRC.equals(ttype) ||
-                 TunnelController.TYPE_STD_CLIENT.equals(ttype)) &&
-                !isShared &&
-                SigType.ECDSA_SHA256_P256.isAvailable())
-                type = SigType.ECDSA_SHA256_P256;
+            if ((!TunnelController.isClient(ttype) ||
+                ((TunnelController.TYPE_IRC_CLIENT.equals(ttype) ||
+                  TunnelController.TYPE_SOCKS_IRC.equals(ttype) ||
+                  TunnelController.TYPE_STREAMR_CLIENT.equals(ttype) ||
+                  TunnelController.TYPE_STD_CLIENT.equals(ttype)) &&
+                 !isShared)))
+                type = TunnelController.PREFERRED_SIGTYPE;
             else
                 type = SigType.DSA_SHA1;
         }
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 30aee1eb48fac67efe0fcf1049fb5952b6c9a641..53f3681b60470decc912454da57661817643bf1b 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -467,20 +467,24 @@ public class IndexBean {
         return _group.getControllers().size();
     }
     
+    /**
+     *  Is it a client or server in the UI and I2P side?
+     *  Note that a streamr client is a UI and I2P client but a server on the localhost side.
+     *  Note that a streamr server is a UI and I2P server but a client on the localhost side.
+     */
     public boolean isClient(int tunnelNum) {
         TunnelController cur = getController(tunnelNum);
         if (cur == null) return false;
-        return isClient(cur.getType());
+        return cur.isClient();
     }
 
+    /**
+     *  Is it a client or server in the UI and I2P side?
+     *  Note that a streamr client is a UI and I2P client but a server on the localhost side.
+     *  Note that a streamr server is a UI and I2P server but a client on the localhost side.
+     */
     public static boolean isClient(String type) {
-        return ( (TunnelController.TYPE_STD_CLIENT.equals(type)) || 
-        		(TunnelController.TYPE_HTTP_CLIENT.equals(type)) ||
-        		(TunnelController.TYPE_SOCKS.equals(type)) ||
-        		(TunnelController.TYPE_SOCKS_IRC.equals(type)) ||
-        		(TunnelController.TYPE_CONNECT.equals(type)) ||
-        		(TunnelController.TYPE_STREAMR_CLIENT.equals(type)) ||
-        		(TunnelController.TYPE_IRC_CLIENT.equals(type)));
+        return TunnelController.isClient(type);
     }
     
     public String getTunnelName(int tunnel) {
@@ -657,36 +661,50 @@ public class IndexBean {
             return "";
     }
     
-    public String getDestinationBase64(int tunnel) {
+    /**
+     *  Works even if tunnel is not running.
+     *  @return Destination or null
+     *  @since 0.9.17
+     */
+    protected Destination getDestination(int tunnel) {
         TunnelController tun = getController(tunnel);
         if (tun != null) {
-            String rv = tun.getMyDestination();
+            Destination rv = tun.getDestination();
             if (rv != null)
                 return rv;
             // if not running, do this the hard way
-            String keyFile = tun.getPrivKeyFile();
-            if (keyFile != null && keyFile.trim().length() > 0) {
+            File keyFile = tun.getPrivateKeyFile();
+            if (keyFile != null) {
                 PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
                 try {
-                    Destination d = pkf.getDestination();
-                    if (d != null)
-                        return d.toBase64();
+                    rv = pkf.getDestination();
+                    if (rv != null)
+                        return rv;
                 } catch (Exception e) {}
             }
         }
+        return null;
+    }
+    
+    /**
+     *  Works even if tunnel is not running.
+     *  @return Base64 or ""
+     */
+    public String getDestinationBase64(int tunnel) {
+        Destination d = getDestination(tunnel);
+        if (d != null)
+            return d.toBase64();
         return "";
     }
     
     /**
+     *  Works even if tunnel is not running.
      *  @return "{52 chars}.b32.i2p" or ""
      */
     public String getDestHashBase32(int tunnel) {
-        TunnelController tun = getController(tunnel);
-        if (tun != null) {
-            String rv = tun.getMyDestHashBase32();
-            if (rv != null)
-                return rv;
-        }
+        Destination d = getDestination(tunnel);
+        if (d != null)
+            return d.toBase32();
         return "";
     }
     
diff --git a/core/java/src/net/i2p/data/KeysAndCert.java b/core/java/src/net/i2p/data/KeysAndCert.java
index 309799a01fa7099bbe85a589d5e333bd297a192c..431cb8fe4856ee91d76713847f77bfe68b71fb0c 100644
--- a/core/java/src/net/i2p/data/KeysAndCert.java
+++ b/core/java/src/net/i2p/data/KeysAndCert.java
@@ -16,6 +16,7 @@ import java.io.OutputStream;
 import java.util.Arrays;
 
 import net.i2p.crypto.SHA256Generator;
+import net.i2p.crypto.SigType;
 
 /**
  * KeysAndCert has a public key, a signing key, and a certificate.
@@ -51,6 +52,22 @@ public class KeysAndCert extends DataStructureImpl {
         _certificate = cert;
     }
 
+    /**
+     *  @return null if not set or unknown
+     *  @since 0.9.17
+     */
+    public SigType getSigType() {
+        if (_certificate == null)
+            return null;
+        if (_certificate.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
+            try {
+                KeyCertificate kcert = _certificate.toKeyCertificate();
+                return kcert.getSigType();
+            } catch (DataFormatException dfe) {}
+        }
+        return SigType.DSA_SHA1;
+    }
+
     public PublicKey getPublicKey() {
         return _publicKey;
     }
diff --git a/installer/resources/i2ptunnel.config b/installer/resources/i2ptunnel.config
index 45d26d5431485a1056e8f9c25b5925c77ac971cc..7406d7118b145ed69b8990bde98ec83024abe4f2 100644
--- a/installer/resources/i2ptunnel.config
+++ b/installer/resources/i2ptunnel.config
@@ -91,6 +91,7 @@ tunnel.3.i2cpHost=127.0.0.1
 tunnel.3.i2cpPort=7654
 tunnel.3.option.inbound.nickname=eepsite
 tunnel.3.option.outbound.nickname=eepsite
+tunnel.3.option.i2cp.destination.sigType=ECDSA_SHA256_P256
 tunnel.3.option.inbound.length=3
 tunnel.3.option.inbound.lengthVariance=0
 tunnel.3.option.outbound.length=3