diff --git a/web/root/blogs/blog_config.js b/web/root/blogs/blog_config.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed903a1e553ba43983f7a783eeb3bf0d0e00144d
--- /dev/null
+++ b/web/root/blogs/blog_config.js
@@ -0,0 +1,53 @@
+// User editable settings...
+
+// Internal code of the message base
+var msg_code="GENERAL";
+
+// Number of posts to show per page.
+var max_posts=16;
+
+// Minimum number of characters in an exerpt
+var min_chars=400;
+
+//
+// Don't change stuff down here.
+//
+
+// User name of the blogger
+var parameters=http_request.path_info.substr(1).split("/");
+var poster=parameters[0];
+var year=parameters[1];
+var month=parameters[2];
+var day=parameters[3];
+var msgid=parameters[4];
+var subject=parameters[5];
+if(poster.indexOf("/")>=0) {
+	poster=poster.substr(0,poster.indexOf("/"));
+}
+
+var pnum=system.matchuser(poster);
+if(pnum==0) {
+	write("<html><head><title>Error</title></head><body>Error getting UserID for "+poster+"!</body></html>");
+	exit(1);
+}
+
+var msgbase = new MsgBase(msg_code);
+if(!msgbase.open()) {
+	write("<html><head><title>Error</title></head><body>Error opening "+msg_code+"!</body></html>");
+	exit(1);
+}
+
+if(msgid != undefined && msgid != "") {
+	if(subject==undefined || subject=="") {
+		var hdr=msgbase.get_msg_header(parseInt(msgid));
+		http_reply.status="301 Moved Permanently";
+		http_reply.header["Location"]="http://"+http_request.host+http_request.virtual_path+poster+"/"+format("%04d",year)+"/"+format("%02d",month)+"/"+format("%02d",day)+"/"+msgid+"/"+clean_subject(hdr.subject);
+		exit(0);
+	}
+}
+
+function clean_subject(sub)
+{
+	sub=sub.replace(/[^a-zA-Z0-9]/g,"_");
+	return(sub);
+}
diff --git a/web/root/blogs/blog_item.xjs b/web/root/blogs/blog_item.xjs
new file mode 100644
index 0000000000000000000000000000000000000000..bf9fcd294850419a596db7ee02dd8460f98a9ba7
--- /dev/null
+++ b/web/root/blogs/blog_item.xjs
@@ -0,0 +1,74 @@
+<?xjs
+load("/synchronet/src/web/root/blog/blog_config.js");
+?>
+
+<html>
+<head>
+<title>The Blogifier!</title>
+</head>
+<body>
+
+<p>
+  Welcome to the <?xjs write(msgbase.cfg.name); ?> Blogifier for <?xjs write(poster); ?>
+</p>
+
+<?xjs
+var hdr=msgbase.get_msg_header(i);
+if(hdr.from_ext != pnum) {
+	http_reply.status="404 Not Found";
+	write("<html><head><title>Not found</title></head><body>The requested URL cannot be found.</body></hmtl>");
+	exit(0);
+}
+
+if(hdr.thread_back) {
+	http_reply.status="404 Not Found";
+	write("<html><head><title>Not found</title></head><body>The requested URL cannot be found.</body></hmtl>");
+	exit(0);
+}
+
+var date=new Date(hdr.date);
+if(year != undefined && year != "") {
+	if(date.getFullYear() != year) {
+		http_reply.status="404 Not Found";
+		write("<html><head><title>Not found</title></head><body>The requested URL cannot be found.</body></hmtl>");
+		exit(0);
+	}
+	if(month != undefined && month != "") {
+		if(date.getMonth()+1 != month) {
+			http_reply.status="404 Not Found";
+			write("<html><head><title>Not found</title></head><body>The requested URL cannot be found.</body></hmtl>");
+			exit(0);
+		}
+		if(day != undefined && day != "") {
+			if(date.getDate() != day) {
+				http_reply.status="404 Not Found";
+				write("<html><head><title>Not found</title></head><body>The requested URL cannot be found.</body></hmtl>");
+				exit(0);
+			}
+		}
+	}
+}
+
+this_year=date.getFullYear();
+this_month=date.getMonth()+1;
+this_day=date.getDate();
+
+var body=msgbase.get_msg_body(i, true);
+body=html_encode(body,true,true,false,false);
+body=body.split("&#13;&#10;&#13;&#10;").join("</p><p>");
+body=body.split("&#13;&#10;").join(" ");
+?>
+
+<b><?xjs write(hdr.subject); ?></b> (<?xjs write(date); ?>)<br>
+<p><?xjs write(body); ?></p>
+
+<hr>
+
+<?xjs
+
+?>
+
+<hr>
+
+</body>
+</html>
diff --git a/web/root/blogs/index.xjs b/web/root/blogs/index.xjs
new file mode 100644
index 0000000000000000000000000000000000000000..f9ce0b7e6818a0c684109089794b5b79e5335057
--- /dev/null
+++ b/web/root/blogs/index.xjs
@@ -0,0 +1,73 @@
+<?xjs
+load("/synchronet/src/web/root/blog/blog_config.js");
+if(msgid != undefined && msgid != "") {
+	xjs_load("blog_item.xjs");
+	exit(0);
+}
+?>
+
+<html>
+<head>
+<title>The Blogifier!</title>
+</head>
+<body>
+
+<p>
+  Welcome to the <?xjs write(msgbase.cfg.name); ?> Blogifier for <?xjs write(poster); ?>
+</p>
+
+<?xjs
+for(i=msgbase.last_msg; i>=msgbase.first_msg; i--) {
+	var hdr=msgbase.get_msg_header(i);
+	if(hdr.from_ext != pnum)
+		continue;
+	if(hdr.thread_back)
+		continue;
+	var date=new Date(hdr.date);
+	if(year != undefined && year != "") {
+		if(date.getFullYear() != year)
+			continue;
+		if(month != undefined && month != "") {
+			if(date.getMonth()+1 != month)
+				continue;
+			if(day != undefined && day != "") {
+				if(date.getDate() != day)
+					continue;
+			}
+		}
+	}
+	this_year=date.getFullYear();
+	this_month=date.getMonth()+1;
+	this_day=date.getDate();
+
+	var body=msgbase.get_msg_body(i, true);
+	j=min_chars;
+	while(j<body.length && body.substr(j, 1)!=" ")
+		j++;
+	if(j<body.length)
+		var read_more=true;
+	exerpt=body.substr(0,j);
+	exerpt=html_encode(exerpt,true,true,false,false);
+	exerpt=exerpt.split("&#13;&#10;&#13;&#10;").join("</p><p>");
+	exerpt=exerpt.split("&#13;&#10;").join(" ");
+?>
+
+<b><?xjs write(hdr.subject); ?></b> (<?xjs write(date); ?>)<br>
+<p><?xjs write(exerpt); if(read_more) write("<b>...</b>"); ?></p>
+
+<p><a href="<?xjs 
+write("http://"+http_request.host+http_request.virtual_path+poster+"/"+format("%04d",this_year)+"/"+format("%02d",this_month)+"/"+format("%02d",this_day)+"/"+i+"/"+clean_subject(hdr.subject));
+?>">Comments...</a></p>
+
+<?xjs
+
+?>
+
+<hr>
+
+<?xjs
+}
+?>
+
+</body>
+</html>