diff --git a/ctrl/web.ini b/ctrl/web.ini
new file mode 100644
index 0000000000000000000000000000000000000000..5e17c292d79e90d1c870a8398f2db7bbe2c3dd99
--- /dev/null
+++ b/ctrl/web.ini
@@ -0,0 +1,47 @@
+; web.ini, from ecWeb v2 for Synchronet BBS 3.15+
+; by Derek Mullin (echicken -at- bbs.electronicchicken.com)
+
+; This stuff could be folded into the [Web] section of sbbs.ini later on, with
+; some small modifications needed to the ecWeb scripts.
+
+; The path to the document root of your webserver
+; (Later on we could just use the existing RootDirectory key from sbbs.ini, but
+; it's useful to keep the two separate for testing purposes right now.)
+webRoot = /sbbs/web/root/ecWeb
+
+; The URL of your BBS (this would be a good place to add in an alternate port
+; number or an FQDN other than what you set in SCFG that also points here.)
+; (Redundant to some settings in sbbs.ini, but necessary for the time being)
+webUrl = 'http://' + system.inet_addr + '/ecWeb/'
+
+; The name of a subdirectory of the 'themes' folder
+theme = stocktastic
+
+; Text to put in the page header and footer respectively. SSJS expressions can
+; be used here, text and HTML are okay if surrounded by quotes.
+headerText = '<a class=link href=/>' + system.name + '</a>';
+footerText = system.version_notice
+
+; What account should be used for unauthenticated browsing? (Suggestion: use an
+; account that has read-only access to every message base you want to be public
+; but cannot post anywhere.)
+; Note: I may need to cause the CAPTCHA to appear on forum posting forums if
+; this user is logged in and people want their guestUser to be able to post.
+; Seems unnecessary to me if people would just configure guest access sensibly.
+guestUser = guest
+
+; The cookie will expire this many seconds after the user's latest page load
+sessionTimeout = 43200
+
+; How many of the most recent messages (per sub-board) will be included in the
+; thread-sorting process. Forum performance will improve significantly as this
+; number is lowered. Set to 0 to sort *all* messages.
+maxMessages = 500
+
+; How many letters long should the captcha be?
+captchaLength = 5
+
+; Which file in the 'pages' directory handles forum functions
+; (This is a bit convoluted, but it saves hard-coding a link to the forum since
+; now the 'pages' sidebar widget will handle that.)
+forumPage = 001-forum.ssjs
diff --git a/exec/load/webInit.ssjs b/exec/load/webInit.ssjs
new file mode 100644
index 0000000000000000000000000000000000000000..6122cbfbba2df77d0de3e2624799c36dbe63ef1d
--- /dev/null
+++ b/exec/load/webInit.ssjs
@@ -0,0 +1,49 @@
+// webInit.ssjs, by echicken -at- bbs.electronicchicken.com
+
+// Some bootstrapping stuff for the web interface, kept in exec/load/ so that
+// layout.ssjs can find it.  Loads the web interface configuration into the
+// webIni object, logs in the current user.
+
+load('sbbsdefs.js');
+
+var f = new File(system.ctrl_dir + 'web.ini');
+f.open("r");
+var webIni = f.iniGetObject();
+f.close();
+
+if(http_request.query.hasOwnProperty('username') && http_request.query.hasOwnProperty('password')) {
+	var UID = system.matchuser(http_request.query.username);
+	var u = new User(UID);
+	if(u && http_request.query.password.toString().toUpperCase() == u.security.password) {
+		set_cookie('synchronet', UID, time() + webIni.sessionTimeout, system.inet_addr, "/");
+		login(u.alias, u.security.password);
+	}
+} else if(http_request.header.hasOwnProperty('cookie') && http_request.header.cookie.match(/synchronet\=\d+/) != null && !http_request.query.hasOwnProperty('logout')) {
+	var UID = http_request.header.cookie.match(/\d+/);
+	var u = new User(UID);
+	if(u.ip_address == client.ip_address) {
+		set_cookie('synchronet', UID, time() + webIni.sessionTimeout, system.inet_addr, "/");
+		login(u.alias, u.security.password);
+	}
+}
+
+if(user.number == 0) {
+	var guestUID = system.matchuser(webIni.guestUser);
+	var u = new User(guestUID);
+	set_cookie('synchronet', guestUID, time() + webIni.sessionTimeout, system.inet_addr, "/");
+	login(u.alias, u.security.password);
+}
+
+// Yeah, this kinda sucks, but it works.
+if(http_request.query.hasOwnProperty('callback')) {
+	if(http_request.query.hasOwnProperty('username') && user.alias == webIni.guestUser) {
+		if(http_request.query.callback.toString().match(/\?/) != null) {
+			var loc = http_request.query.callback + "&loginfail=true";
+		} else {
+			var loc = http_request.query.callback + "?loginfail=true";
+		}
+	} else {
+		var loc = http_request.query.callback;
+	}
+	print("<html><head><script type=text/javascript>window.location='" + loc + "'</script></head></html>");
+}
\ No newline at end of file