diff --git a/Makefile b/Makefile
index 7256d23e6a242631e282851a2f44f6aba58b1815..8a3a345faf6fd2a294f8dced896ca2be9199afec 100644
--- a/Makefile
+++ b/Makefile
@@ -22,8 +22,7 @@ all:
 
 CFLAGS=		-W -Wall -std=c99 -pedantic -Os -fomit-frame-pointer $(COPT)
 MAC_SHARED=	-flat_namespace -bundle -undefined suppress
-SSLFLAGS=	-lssl -lcrypto
-LINFLAGS=	-ldl -pthread $(SSLFLAGS) $(CFLAGS)
+LINFLAGS=	-ldl -pthread $(CFLAGS)
 LIB=		_$(PROG).so
 
 linux:
@@ -32,17 +31,16 @@ linux:
 
 bsd:
 	$(CC) $(CFLAGS) mongoose.c -shared -pthread -fpic -fPIC -o $(LIB)
-	$(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG)
+	$(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG)
 
 mac:
-	$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread $(SSLFLAGS) -o $(LIB)
-	$(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG)
+	$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread -o $(LIB)
+	$(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG)
 
 solaris:
 	gcc $(CFLAGS) mongoose.c -pthread -lnsl \
-		-lsocket $(SSLFLAGS) -fpic -fPIC -shared -o $(LIB)
-	gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket $(SSLFLAGS) \
-		-o $(PROG)
+		-lsocket -fpic -fPIC -shared -o $(LIB)
+	gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket -o $(PROG)
 
 
 ##########################################################################
diff --git a/mongoose.c b/mongoose.c
index 36a491a7dfe9625b83611200cea0fe6da5303694..176d40969ae8dd9f8a72d4eee1755f86fe0ed995 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -90,6 +90,8 @@ typedef long off_t;
 
 #define ERRNO   GetLastError()
 #define NO_SOCKLEN_T
+#define SSL_LIB   "ssleay32.dll"
+#define CRYPTO_LIB  "libeay32.dll"
 #define DIRSEP '\\'
 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
 #define O_NONBLOCK  0
@@ -172,6 +174,13 @@ typedef struct DIR {
 #include <dirent.h>
 #include <dlfcn.h>
 #include <pthread.h>
+#if defined(__MACH__)
+#define SSL_LIB   "libssl.dylib"
+#define CRYPTO_LIB  "libcrypto.dylib"
+#else
+#define SSL_LIB   "libssl.so"
+#define CRYPTO_LIB  "libcrypto.so"
+#endif
 #define DIRSEP   '/'
 #define IS_DIRSEP_CHAR(c) ((c) == '/')
 #define O_BINARY  0
@@ -230,27 +239,76 @@ typedef struct ssl_ctx_st SSL_CTX;
 #define SSL_FILETYPE_PEM 1
 #define CRYPTO_LOCK  1
 
-extern void SSL_free(SSL *);
-extern int SSL_accept(SSL *);
-extern int SSL_connect(SSL *);
-extern int SSL_read(SSL *, void *, int);
-extern int SSL_write(SSL *, const void *, int);
-extern int SSL_get_error(const SSL *, int);
-extern int SSL_set_fd(SSL *, int);
-extern SSL *SSL_new(SSL_CTX *);
-extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
-extern SSL_METHOD *SSLv23_server_method(void);
-extern int SSL_library_init(void);
-extern void SSL_load_error_strings(void);
-extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
-extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
-extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
-extern void SSL_CTX_free(SSL_CTX *);
-extern unsigned long ERR_get_error(void);
-extern char *ERR_error_string(unsigned long, char *);
-extern int CRYPTO_num_locks(void);
-extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
-extern void CRYPTO_set_id_callback(unsigned long (*)(void));
+// Dynamically loaded SSL functionality
+struct ssl_func {
+  const char *name;   // SSL function name
+  void  (*ptr)(void); // Function pointer
+};
+
+#define SSL_free(x) (* (void (*)(SSL *)) ssl_sw[0].ptr)(x)
+#define SSL_accept(x) (* (int (*)(SSL *)) ssl_sw[1].ptr)(x)
+#define SSL_connect(x) (* (int (*)(SSL *)) ssl_sw[2].ptr)(x)
+#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int))   \
+    ssl_sw[3].ptr)((x),(y),(z))
+#define SSL_write(x,y,z) (* (int (*)(SSL *, const void *,int))  \
+    ssl_sw[4].ptr)((x), (y), (z))
+#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) ssl_sw[5])((x), (y))
+#define SSL_set_fd(x,y) (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)((x), (y))
+#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)(x)
+#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)(x)
+#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)()
+#define SSL_library_init() (* (int (*)(void)) ssl_sw[10].ptr)()
+#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \
+        const char *, int)) ssl_sw[11].ptr)((x), (y), (z))
+#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \
+        const char *, int)) ssl_sw[12].ptr)((x), (y), (z))
+#define SSL_CTX_set_default_passwd_cb(x,y) \
+  (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)((x),(y))
+#define SSL_CTX_free(x) (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)(x)
+#define ERR_get_error() (* (unsigned long (*)(void)) ssl_sw[15].ptr)()
+#define ERR_error_string(x, y) (* (char * (*)(unsigned long, char *)) ssl_sw[16].ptr)((x), (y))
+#define SSL_load_error_strings() (* (void (*)(void)) ssl_sw[17].ptr)()
+
+#define CRYPTO_num_locks() (* (int (*)(void)) crypto_sw[0].ptr)()
+#define CRYPTO_set_locking_callback(x)     \
+  (* (void (*)(void (*)(int, int, const char *, int))) \
+   crypto_sw[1].ptr)(x)
+#define CRYPTO_set_id_callback(x)     \
+  (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)(x)
+
+// set_ssl_option() function updates this array.
+// It loads SSL library dynamically and changes NULLs to the actual addresses
+// of respective functions. The macros above (like SSL_connect()) are really
+// just calling these functions indirectly via the pointer.
+static struct ssl_func ssl_sw[] = {
+  {"SSL_free",   NULL},
+  {"SSL_accept",   NULL},
+  {"SSL_connect",   NULL},
+  {"SSL_read",   NULL},
+  {"SSL_write",   NULL},
+  {"SSL_get_error",  NULL},
+  {"SSL_set_fd",   NULL},
+  {"SSL_new",   NULL},
+  {"SSL_CTX_new",   NULL},
+  {"SSLv23_server_method", NULL},
+  {"SSL_library_init",  NULL},
+  {"SSL_CTX_use_PrivateKey_file", NULL},
+  {"SSL_CTX_use_certificate_file",NULL},
+  {"SSL_CTX_set_default_passwd_cb",NULL},
+  {"SSL_CTX_free",  NULL},
+  {"ERR_get_error",  NULL},
+  {"ERR_error_string", NULL},
+  {"SSL_load_error_strings", NULL},
+  {NULL,    NULL}
+};
+
+// Similar array as ssl_sw. These functions could be located in different lib.
+static struct ssl_func crypto_sw[] = {
+  {"CRYPTO_num_locks",  NULL},
+  {"CRYPTO_set_locking_callback", NULL},
+  {"CRYPTO_set_id_callback", NULL},
+  {NULL,    NULL}
+};
 
 static const char *month_names[] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -291,15 +349,15 @@ struct socket {
 };
 
 struct mg_context {
-  int stop_flag;             // Should we stop event loop
-  SSL_CTX *ssl_ctx;          // SSL context
+  int stop_flag;     // Should we stop event loop
+  SSL_CTX *ssl_ctx;  // SSL context
   const struct mg_config *config; // Mongoose configuration
 
   struct socket *listening_sockets;
 
-  int num_threads;           // Number of threads
-  pthread_mutex_t mutex;     // Protects (max|num)_threads
-  pthread_cond_t  cond;      // Condvar for tracking workers terminations
+  int num_threads;         // Number of threads
+  pthread_mutex_t mutex;   // Protects (max|num)_threads
+  pthread_cond_t  cond;    // Condvar for tracking workers terminations
 
   struct socket queue[20];   // Accepted sockets
   int sq_head;               // Head of the socket queue
@@ -373,6 +431,13 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
   conn->request_info.log_message = NULL;
 }
 
+// Return OpenSSL error message
+static const char *ssl_error(void) {
+  unsigned long err;
+  err = ERR_get_error();
+  return err == 0 ? "" : ERR_error_string(err, NULL);
+}
+
 // Return fake connection structure. Used for logging, if connection
 // is not applicable at the moment of logging.
 static struct mg_connection *fc(struct mg_context *ctx) {
@@ -920,14 +985,12 @@ static int start_thread(struct mg_context *ctx, mg_thread_func_t func,
   return hThread == NULL ? -1 : 0;
 }
 
-#if 0
 static HANDLE dlopen(const char *dll_name, int flags) {
   wchar_t wbuf[PATH_MAX];
   flags = 0; // Unused
   to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
   return LoadLibraryW(wbuf);
 }
-#endif
 
 #if !defined(NO_CGI)
 #define SIGKILL 0
@@ -1125,12 +1188,9 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
     /* How many bytes we send in this iteration */
     k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
 
-#if !defined(NO_SSL)
     if (ssl != NULL) {
       n = SSL_write(ssl, buf + sent, k);
-    } else 
-#endif // !NO_SSL
-    if (fp != NULL) {
+    } else if (fp != NULL) {
       n = fwrite(buf + sent, 1, k, fp);
       if (ferror(fp))
         n = -1;
@@ -1152,12 +1212,9 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
 static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
   int nread;
 
-#if !defined(NO_SSL)
   if (ssl != NULL) {
     nread = SSL_read(ssl, buf, len);
-  } else
-#endif // !NO_SSL
-  if (fp != NULL) {
+  } else if (fp != NULL) {
     nread = fread(buf, 1, (size_t) len, fp);
     if (ferror(fp))
       nread = -1;
@@ -3251,33 +3308,68 @@ static unsigned long ssl_id_callback(void) {
   return (unsigned long) pthread_self();
 }
 
-// Return OpenSSL error message
-static const char *ssl_error(void) {
-  unsigned long err;
-  err = ERR_get_error();
-  return err == 0 ? "" : ERR_error_string(err, NULL);
+static bool_t load_dll(struct mg_context *ctx, const char *dll_name,
+                       struct ssl_func *sw) {
+  union {void *p; void (*fp)(void);} u;
+  void  *dll_handle;
+  struct ssl_func *fp;
+
+  if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
+    cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
+    return MG_FALSE;
+  }
+
+  for (fp = sw; fp->name != NULL; fp++) {
+#ifdef _WIN32
+    // GetProcAddress() returns pointer to function
+    u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
+#else
+    // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
+    // function pointers. We need to use a union to make a cast.
+    u.p = dlsym(dll_handle, fp->name);
+#endif /* _WIN32 */
+    if (u.fp == NULL) {
+      cry(fc(ctx), "%s: cannot find %s", __func__, fp->name);
+      return MG_FALSE;
+    } else {
+      fp->ptr = u.fp;
+    }
+  }
+
+  return MG_TRUE;
 }
 
+// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
 static enum mg_error_t set_ssl_option(struct mg_context *ctx) {
   SSL_CTX *CTX;
   int i, size;
   const char *pem = ctx->config->ssl_certificate;
 
+  if (pem == NULL) {
+    return MG_SUCCESS;
+  }
+
+  if (load_dll(ctx, SSL_LIB, ssl_sw) == MG_FALSE ||
+      load_dll(ctx, CRYPTO_LIB, crypto_sw) == MG_FALSE) {
+    return MG_ERROR;
+  }
+
   // Initialize SSL crap
   SSL_library_init();
   SSL_load_error_strings();
 
   if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
     cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
-    return MG_ERROR;
   } else if (ctx->config->ssl_password_handler != NULL) {
     SSL_CTX_set_default_passwd_cb(CTX, ctx->config->ssl_password_handler);
   }
 
-  if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
+  if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
+        SSL_FILETYPE_PEM) == 0) {
     cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
     return MG_ERROR;
-  } else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
+  } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
+        SSL_FILETYPE_PEM) == 0) {
     cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
     return MG_ERROR;
   }
@@ -3365,12 +3457,10 @@ static void close_socket_gracefully(SOCKET sock) {
 }
 
 static void close_connection(struct mg_connection *conn) {
-#if !defined(NO_SSL)
   if (conn->ssl) {
     SSL_free(conn->ssl);
     conn->ssl = NULL;
   }
-#endif // !NO_SSL
 
   if (conn->client.sock != INVALID_SOCKET) {
     close_socket_gracefully(conn->client.sock);
@@ -3486,7 +3576,6 @@ static void worker_thread(struct mg_context *ctx) {
     conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
     conn->request_info.is_ssl = conn->client.is_ssl;
 
-#if !defined(NO_SSL)
     if (conn->client.is_ssl && (conn->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
       cry(conn, "%s: SSL_new: %s", __func__, ssl_error());
     } else if (conn->client.is_ssl &&
@@ -3494,9 +3583,7 @@ static void worker_thread(struct mg_context *ctx) {
       cry(conn, "%s: SSL_set_fd: %s", __func__, ssl_error());
     } else if (conn->client.is_ssl && SSL_accept(conn->ssl) != 1) {
       cry(conn, "%s: SSL handshake error: %s", __func__, ssl_error());
-    } else
-#endif // !NO_SSL
-    {
+    } else {
       process_new_connection(conn);
     }
 
@@ -3604,12 +3691,10 @@ static void master_thread(struct mg_context *ctx) {
   }
   (void) pthread_mutex_unlock(&ctx->mutex);
 
-#if !defined(NO_SSL)
   // Deallocate SSL context
   if (ctx->ssl_ctx != NULL) {
     SSL_CTX_free(ctx->ssl_ctx);
   }
-#endif // !NO_SSL
 
   // All threads exited, no sync is needed. Destroy mutex and condvars
   (void) pthread_mutex_destroy(&ctx->mutex);
@@ -3667,11 +3752,9 @@ struct mg_context * mg_start(const struct mg_config *config) {
 
   // NOTE(lsm): order is important here. SSL certificates must
   // be initialized before listening ports. UID must be set last.
-  if (set_gpass_option(ctx) == MG_ERROR ||
-#if !defined(NO_SSL)
-      (config->ssl_certificate != NULL && set_ssl_option(ctx) == MG_ERROR) ||
-#endif // !NO_SSL
+  if (set_ssl_option(ctx) == MG_ERROR ||
       set_ports_option(ctx) == MG_ERROR ||
+      set_gpass_option(ctx) == MG_ERROR ||
 #if !defined(_WIN32)
       set_uid_option(ctx) == MG_ERROR ||
 #endif