summaryrefslogtreecommitdiff
path: root/docs/en/services
diff options
context:
space:
mode:
authorMicah Anderson <micah@riseup.net>2016-11-04 10:54:28 -0400
committerMicah Anderson <micah@riseup.net>2016-11-04 10:54:28 -0400
commit34a381efa8f6295080c843f86bfa07d4e41056af (patch)
tree9282cf5d4c876688602705a7fa0002bc4a810bde /docs/en/services
parent0a72bc6fd292bf9367b314fcb0347c4d35042f16 (diff)
parent5821964ff7e16ca7aa9141bd09a77d355db492a9 (diff)
Merge branch 'develop'
Diffstat (limited to 'docs/en/services')
-rw-r--r--docs/en/services/couchdb.html328
-rw-r--r--docs/en/services/couchdb/index.html328
-rw-r--r--docs/en/services/index.html251
-rw-r--r--docs/en/services/monitor.html186
-rw-r--r--docs/en/services/monitor/index.html186
-rw-r--r--docs/en/services/mx.html168
-rw-r--r--docs/en/services/mx/index.html168
-rw-r--r--docs/en/services/openvpn.html178
-rw-r--r--docs/en/services/openvpn/index.html178
-rw-r--r--docs/en/services/soledad.html136
-rw-r--r--docs/en/services/soledad/index.html136
-rw-r--r--docs/en/services/tor.html161
-rw-r--r--docs/en/services/tor/index.html161
-rw-r--r--docs/en/services/webapp.html479
-rw-r--r--docs/en/services/webapp/index.html479
15 files changed, 3523 insertions, 0 deletions
diff --git a/docs/en/services/couchdb.html b/docs/en/services/couchdb.html
new file mode 100644
index 00000000..6de6455c
--- /dev/null
+++ b/docs/en/services/couchdb.html
@@ -0,0 +1,328 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+couchdb - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class='active level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>couchdb</h1>
+
+<div id='summary'>Data storage for all user data.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="couchdb/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="couchdb/index.html#configuration">Configuration</a>
+ <ol>
+ <li>
+ <a href="couchdb/index.html#nighly-dumps">Nighly dumps</a>
+ </li>
+ <li>
+ <a href="couchdb/index.html#plain-couchdb">Plain CouchDB</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="couchdb/index.html#various-tasks">Various Tasks</a>
+ <ol>
+ <li>
+ <a href="couchdb/index.html#re-enabling-blocked-account">Re-enabling blocked account</a>
+ </li>
+ <li>
+ <a href="couchdb/index.html#how-to-find-out-which-userstore-belongs-to-which-identity">How to find out which userstore belongs to which identity?</a>
+ </li>
+ <li>
+ <a href="couchdb/index.html#how-much-disk-space-is-used-by-a-userstore">How much disk space is used by a userstore</a>
+ </li>
+ <li>
+ <a href="couchdb/index.html#migrating-from-bigcouch-to-plain-couchdb">Migrating from BigCouch to plain CouchDB</a>
+ </li>
+ </ol>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Required:</p>
+
+<ul>
+<li>Nodes with <code>couchdb</code> service must also have <code>soledad</code> service, if email is enabled.</li>
+</ul>
+
+
+<p>Suggested:</p>
+
+<ul>
+<li>Nodes with <code>couchdb</code> service communicate heavily with <code>webapp</code> and <code>mx</code>.</li>
+</ul>
+
+
+<p><code>couchdb</code> nodes do not need to be reachable from the public internet, although the <code>soledad</code> service does require this.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<h3><a name="nighly-dumps"></a>Nighly dumps</h3>
+
+<p>You can do a nightly couchdb data dump by adding this to your node config:</p>
+
+<pre><code>"couch": {
+ "backup": true
+}
+</code></pre>
+
+<p>Data will get dumped to <code>/var/backups/couchdb</code>.</p>
+
+<h3><a name="plain-couchdb"></a>Plain CouchDB</h3>
+
+<p>BigCouch is not supported on Platform version 0.8 and higher: only plain CouchDB is possible. For earlier versions, you must do this in order to use plain CouchDB:</p>
+
+<pre><code>"couch": {
+ "master": true,
+ "pwhash_alg": "pbkdf2"
+}
+</code></pre>
+
+<h2><a name="various-tasks"></a>Various Tasks</h2>
+
+<h3><a name="re-enabling-blocked-account"></a>Re-enabling blocked account</h3>
+
+<p>When a user account gets destroyed from the webapp, there&rsquo;s still a leftover doc in the identities db so other people can&rsquo;t claim that account without an admin&rsquo;s intervention. You can remove this username reservation through the webapp.</p>
+
+<p>However, here is how you could do it manually, if you wanted to:</p>
+
+<p>grep the identities db for the email address:</p>
+
+<pre><code>curl -s --netrc-file /etc/couchdb/couchdb.netrc -X GET http://127.0.0.1:5984/identities/_all_docs?include_docs=true|grep test_127@bitmask.net
+</code></pre>
+
+<p>lookup &ldquo;id&rdquo; and &ldquo;rev&rdquo; to delete the doc:</p>
+
+<pre><code>curl -s --netrc-file /etc/couchdb/couchdb.netrc -X DELETE 'http://127.0.0.1:5984/identities/b25cf10f935b58088f0d547fca823265?rev=2-715a9beba597a2ab01851676f12c3e4a'
+</code></pre>
+
+<h3><a name="how-to-find-out-which-userstore-belongs-to-which-identity"></a>How to find out which userstore belongs to which identity?</h3>
+
+<pre><code>/usr/bin/curl -s --netrc-file /etc/couchdb/couchdb.netrc '127.0.0.1:5984/identities/_all_docs?include_docs=true' | grep testuser
+
+{"id":"665e004870ee17aa4c94331ff3ecb173","key":"665e004870ee17aa4c94331ff3ecb173","value":{"rev":"2-2e335a75c4b79a5c2ef5c9950706fe1b"},"doc":{"_id":"665e004870ee17aa4c94331ff3ecb173","_rev":"2-2e335a75c4b79a5c2ef5c9950706fe1b","user_id":"665e004870ee17aa4c94331ff3cd59eb","address":"testuser@example.org","destination":"testuser@example.org","keys": ...
+</code></pre>
+
+<ul>
+<li>search for the &ldquo;user_id&rdquo; field</li>
+<li>in this example <a href="&#x6d;&#x61;&#x69;&#108;&#x74;&#x6f;&#58;&#x74;&#101;&#x73;&#116;&#x75;&#115;&#101;&#114;&#64;&#x65;&#x78;&#97;&#109;&#x70;&#108;&#x65;&#x2e;&#111;&#114;&#x67;">&#x74;&#101;&#x73;&#116;&#x75;&#115;&#x65;&#x72;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#x2e;&#x6f;&#114;&#x67;</a> uses the database user-665e004870ee17aa4c94331ff3cd59eb</li>
+</ul>
+
+
+<h3><a name="how-much-disk-space-is-used-by-a-userstore"></a>How much disk space is used by a userstore</h3>
+
+<p>Beware that this returns the uncompacted disk size (see <a href="http://wiki.apache.org/couchdb/Compaction">http://wiki.apache.org/couchdb/Compaction</a>)</p>
+
+<pre><code>echo "`curl --netrc -s -X GET 'http://127.0.0.1:5984/user-dcd6492d74b90967b6b874100b7dbfcf'|json_pp|grep disk_size|cut -d: -f 2`/1024"|bc
+</code></pre>
+
+<h3><a name="migrating-from-bigcouch-to-plain-couchdb"></a>Migrating from BigCouch to plain CouchDB</h3>
+
+<p><p>At the end of this process, you will have just <em>one</em> node with <code>services</code> property equal to <code>couchdb</code>. If you had a BigCouch cluster before, you will be removing all but one of those machines to consolidate them into one CouchDB machine.</p>
+
+<ol>
+<li><p>if you have multiple nodes with the <code>couchdb</code> service on them, pick one of them to be your CouchDB server, and remove the service from the others. If these machines were only doing BigCouch before, you can remove the nodes completely with <code>leap node rm &lt;nodename&gt;</code> and then you can decommission the servers</p></li>
+<li><p>put the webapp into <a href="webapp.html#maintenance-mode">maintenance mode</a></p></li>
+<li><p>turn off daemons that access the database. For example:</p>
+
+<pre><code class="`"> workstation$ leap ssh &lt;each soledad-node&gt;
+ server# /etc/init.d/soledad-server stop
+
+ workstation$ leap ssh &lt;mx-node&gt;
+ server# /etc/init.d/postfix stop
+ server# /etc/init.d/leap-mx stop
+
+ workstation$ leap ssh &lt;webapp-node&gt;
+ server# /etc/init.d/nickserver stop
+</code></pre>
+
+<p> Alternately, you can create a temporary firewall rule to block access (run on couchdb server):</p>
+
+<pre><code class="`"> server# iptables -A INPUT -p tcp --dport 5984 --jump REJECT
+</code></pre></li>
+<li><p>remove orphaned databases and do a backup of all remaining, active databases. This can take some time and will place several hundred megabytes of data into /var/backups/couchdb. The size and time depends on how many users there are on your system. For example, 15k users took approximately 25 minutes and 308M of space:</p>
+
+<pre><code class="`"> workstation$ leap ssh &lt;couchdb-node&gt;
+ server# cd /srv/leap/couchdb/scripts
+ server# ./cleanup-user-dbs
+ server# time ./couchdb_dumpall.sh
+</code></pre></li>
+<li><p>stop bigcouch:</p>
+
+<pre><code class="`"> server# /etc/init.d/bigcouch stop
+ server# pkill epmd
+</code></pre></li>
+<li><p>remove bigcouch:</p>
+
+<pre><code class="`"> server# apt-get remove bigcouch
+</code></pre></li>
+<li><p>configure your couch node to use plain couchdb instead of bigcouch, you can do this by editing nodes/<couch-node>.json, look for this section:</p>
+
+<pre><code class="`"> "couch": {
+ "mode": "plain"
+ }
+</code></pre>
+
+<p>change it, so it looks like this instead:</p>
+
+<pre><code class="``"> "couch": {
+ "mode": "plain",
+ "pwhash_alg": "pbkdf2"
+ }
+</code></pre></li>
+</ol>
+
+</p>
+
+<p><ol>
+<li><p>restore the backup, this will take approximately the same amount of time as the backup took above:</p>
+
+<pre><code class="`"> server# cd /srv/leap/couchdb/scripts
+ server# time ./couchdb_restoreall.sh
+</code></pre></li>
+<li><p>start services again that were stopped in the beginning:</p>
+
+<pre><code class="`"> workstation$ leap ssh soledad-nodes
+ server# /etc/init.d/soledad-server start
+
+ workstation$ leap ssh mx-node
+ server# /etc/init.d/postfix start
+ server# /etc/init.d/leap-mx start
+
+ workstation$ leap ssh webapp
+ server# /etc/init.d/nickserver start
+</code></pre>
+
+<p> Or, alternately, if you set up the firewall rule instead, now remove it:</p>
+
+<pre><code class="`"> server# iptables -D INPUT -p tcp --dport 5984 --jump REJECT
+</code></pre></li>
+</ol>
+
+</p>
+
+<p><ol>
+<li><p>check if everything is working, including running the test on your deployment machine:</p>
+
+<pre><code class="`"> workstation$ leap test
+</code></pre></li>
+<li><p>Remove old bigcouch data dir <code>/opt</code> after you double checked everything is in place</p></li>
+<li><p>Relax, enjoy a refreshing beverage.</p></li>
+</ol>
+
+</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/couchdb/index.html b/docs/en/services/couchdb/index.html
new file mode 100644
index 00000000..10043db6
--- /dev/null
+++ b/docs/en/services/couchdb/index.html
@@ -0,0 +1,328 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+couchdb - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class='active level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>couchdb</h1>
+
+<div id='summary'>Data storage for all user data.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ <ol>
+ <li>
+ <a href="index.html#nighly-dumps">Nighly dumps</a>
+ </li>
+ <li>
+ <a href="index.html#plain-couchdb">Plain CouchDB</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="index.html#various-tasks">Various Tasks</a>
+ <ol>
+ <li>
+ <a href="index.html#re-enabling-blocked-account">Re-enabling blocked account</a>
+ </li>
+ <li>
+ <a href="index.html#how-to-find-out-which-userstore-belongs-to-which-identity">How to find out which userstore belongs to which identity?</a>
+ </li>
+ <li>
+ <a href="index.html#how-much-disk-space-is-used-by-a-userstore">How much disk space is used by a userstore</a>
+ </li>
+ <li>
+ <a href="index.html#migrating-from-bigcouch-to-plain-couchdb">Migrating from BigCouch to plain CouchDB</a>
+ </li>
+ </ol>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Required:</p>
+
+<ul>
+<li>Nodes with <code>couchdb</code> service must also have <code>soledad</code> service, if email is enabled.</li>
+</ul>
+
+
+<p>Suggested:</p>
+
+<ul>
+<li>Nodes with <code>couchdb</code> service communicate heavily with <code>webapp</code> and <code>mx</code>.</li>
+</ul>
+
+
+<p><code>couchdb</code> nodes do not need to be reachable from the public internet, although the <code>soledad</code> service does require this.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<h3><a name="nighly-dumps"></a>Nighly dumps</h3>
+
+<p>You can do a nightly couchdb data dump by adding this to your node config:</p>
+
+<pre><code>"couch": {
+ "backup": true
+}
+</code></pre>
+
+<p>Data will get dumped to <code>/var/backups/couchdb</code>.</p>
+
+<h3><a name="plain-couchdb"></a>Plain CouchDB</h3>
+
+<p>BigCouch is not supported on Platform version 0.8 and higher: only plain CouchDB is possible. For earlier versions, you must do this in order to use plain CouchDB:</p>
+
+<pre><code>"couch": {
+ "master": true,
+ "pwhash_alg": "pbkdf2"
+}
+</code></pre>
+
+<h2><a name="various-tasks"></a>Various Tasks</h2>
+
+<h3><a name="re-enabling-blocked-account"></a>Re-enabling blocked account</h3>
+
+<p>When a user account gets destroyed from the webapp, there&rsquo;s still a leftover doc in the identities db so other people can&rsquo;t claim that account without an admin&rsquo;s intervention. You can remove this username reservation through the webapp.</p>
+
+<p>However, here is how you could do it manually, if you wanted to:</p>
+
+<p>grep the identities db for the email address:</p>
+
+<pre><code>curl -s --netrc-file /etc/couchdb/couchdb.netrc -X GET http://127.0.0.1:5984/identities/_all_docs?include_docs=true|grep test_127@bitmask.net
+</code></pre>
+
+<p>lookup &ldquo;id&rdquo; and &ldquo;rev&rdquo; to delete the doc:</p>
+
+<pre><code>curl -s --netrc-file /etc/couchdb/couchdb.netrc -X DELETE 'http://127.0.0.1:5984/identities/b25cf10f935b58088f0d547fca823265?rev=2-715a9beba597a2ab01851676f12c3e4a'
+</code></pre>
+
+<h3><a name="how-to-find-out-which-userstore-belongs-to-which-identity"></a>How to find out which userstore belongs to which identity?</h3>
+
+<pre><code>/usr/bin/curl -s --netrc-file /etc/couchdb/couchdb.netrc '127.0.0.1:5984/identities/_all_docs?include_docs=true' | grep testuser
+
+{"id":"665e004870ee17aa4c94331ff3ecb173","key":"665e004870ee17aa4c94331ff3ecb173","value":{"rev":"2-2e335a75c4b79a5c2ef5c9950706fe1b"},"doc":{"_id":"665e004870ee17aa4c94331ff3ecb173","_rev":"2-2e335a75c4b79a5c2ef5c9950706fe1b","user_id":"665e004870ee17aa4c94331ff3cd59eb","address":"testuser@example.org","destination":"testuser@example.org","keys": ...
+</code></pre>
+
+<ul>
+<li>search for the &ldquo;user_id&rdquo; field</li>
+<li>in this example <a href="&#x6d;&#x61;&#x69;&#x6c;&#x74;&#x6f;&#58;&#x74;&#x65;&#115;&#116;&#117;&#x73;&#x65;&#x72;&#x40;&#101;&#x78;&#97;&#109;&#x70;&#108;&#101;&#46;&#111;&#114;&#x67;">&#116;&#x65;&#115;&#116;&#x75;&#x73;&#101;&#114;&#x40;&#x65;&#120;&#97;&#109;&#112;&#x6c;&#x65;&#x2e;&#111;&#114;&#103;</a> uses the database user-665e004870ee17aa4c94331ff3cd59eb</li>
+</ul>
+
+
+<h3><a name="how-much-disk-space-is-used-by-a-userstore"></a>How much disk space is used by a userstore</h3>
+
+<p>Beware that this returns the uncompacted disk size (see <a href="http://wiki.apache.org/couchdb/Compaction">http://wiki.apache.org/couchdb/Compaction</a>)</p>
+
+<pre><code>echo "`curl --netrc -s -X GET 'http://127.0.0.1:5984/user-dcd6492d74b90967b6b874100b7dbfcf'|json_pp|grep disk_size|cut -d: -f 2`/1024"|bc
+</code></pre>
+
+<h3><a name="migrating-from-bigcouch-to-plain-couchdb"></a>Migrating from BigCouch to plain CouchDB</h3>
+
+<p><p>At the end of this process, you will have just <em>one</em> node with <code>services</code> property equal to <code>couchdb</code>. If you had a BigCouch cluster before, you will be removing all but one of those machines to consolidate them into one CouchDB machine.</p>
+
+<ol>
+<li><p>if you have multiple nodes with the <code>couchdb</code> service on them, pick one of them to be your CouchDB server, and remove the service from the others. If these machines were only doing BigCouch before, you can remove the nodes completely with <code>leap node rm &lt;nodename&gt;</code> and then you can decommission the servers</p></li>
+<li><p>put the webapp into <a href="../webapp.html#maintenance-mode">maintenance mode</a></p></li>
+<li><p>turn off daemons that access the database. For example:</p>
+
+<pre><code class="`"> workstation$ leap ssh &lt;each soledad-node&gt;
+ server# /etc/init.d/soledad-server stop
+
+ workstation$ leap ssh &lt;mx-node&gt;
+ server# /etc/init.d/postfix stop
+ server# /etc/init.d/leap-mx stop
+
+ workstation$ leap ssh &lt;webapp-node&gt;
+ server# /etc/init.d/nickserver stop
+</code></pre>
+
+<p> Alternately, you can create a temporary firewall rule to block access (run on couchdb server):</p>
+
+<pre><code class="`"> server# iptables -A INPUT -p tcp --dport 5984 --jump REJECT
+</code></pre></li>
+<li><p>remove orphaned databases and do a backup of all remaining, active databases. This can take some time and will place several hundred megabytes of data into /var/backups/couchdb. The size and time depends on how many users there are on your system. For example, 15k users took approximately 25 minutes and 308M of space:</p>
+
+<pre><code class="`"> workstation$ leap ssh &lt;couchdb-node&gt;
+ server# cd /srv/leap/couchdb/scripts
+ server# ./cleanup-user-dbs
+ server# time ./couchdb_dumpall.sh
+</code></pre></li>
+<li><p>stop bigcouch:</p>
+
+<pre><code class="`"> server# /etc/init.d/bigcouch stop
+ server# pkill epmd
+</code></pre></li>
+<li><p>remove bigcouch:</p>
+
+<pre><code class="`"> server# apt-get remove bigcouch
+</code></pre></li>
+<li><p>configure your couch node to use plain couchdb instead of bigcouch, you can do this by editing nodes/<couch-node>.json, look for this section:</p>
+
+<pre><code class="`"> "couch": {
+ "mode": "plain"
+ }
+</code></pre>
+
+<p>change it, so it looks like this instead:</p>
+
+<pre><code class="``"> "couch": {
+ "mode": "plain",
+ "pwhash_alg": "pbkdf2"
+ }
+</code></pre></li>
+</ol>
+
+</p>
+
+<p><ol>
+<li><p>restore the backup, this will take approximately the same amount of time as the backup took above:</p>
+
+<pre><code class="`"> server# cd /srv/leap/couchdb/scripts
+ server# time ./couchdb_restoreall.sh
+</code></pre></li>
+<li><p>start services again that were stopped in the beginning:</p>
+
+<pre><code class="`"> workstation$ leap ssh soledad-nodes
+ server# /etc/init.d/soledad-server start
+
+ workstation$ leap ssh mx-node
+ server# /etc/init.d/postfix start
+ server# /etc/init.d/leap-mx start
+
+ workstation$ leap ssh webapp
+ server# /etc/init.d/nickserver start
+</code></pre>
+
+<p> Or, alternately, if you set up the firewall rule instead, now remove it:</p>
+
+<pre><code class="`"> server# iptables -D INPUT -p tcp --dport 5984 --jump REJECT
+</code></pre></li>
+</ol>
+
+</p>
+
+<p><ol>
+<li><p>check if everything is working, including running the test on your deployment machine:</p>
+
+<pre><code class="`"> workstation$ leap test
+</code></pre></li>
+<li><p>Remove old bigcouch data dir <code>/opt</code> after you double checked everything is in place</p></li>
+<li><p>Relax, enjoy a refreshing beverage.</p></li>
+</ol>
+
+</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/index.html b/docs/en/services/index.html
new file mode 100644
index 00000000..6d5c68e1
--- /dev/null
+++ b/docs/en/services/index.html
@@ -0,0 +1,251 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+Services - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>Guide to node services</h1>
+
+<div id='summary'></div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#introduction">Introduction</a>
+ </li>
+ <li>
+ <a href="index.html#available-services">Available services</a>
+ </li>
+</ol></div>
+
+<h1><a name="introduction"></a>Introduction</h1>
+
+<p>Every node (server) must have one or more <code>services</code> defined that determines what role the node performs. For example:</p>
+
+<pre><code>workstation$ cat nodes/stallman.json
+{
+ "ip_address": "199.99.99.1",
+ "services": ["webapp", "tor"]
+}
+</code></pre>
+
+<p>Here are common questions to ask when adding a new node to your provider:</p>
+
+<ul>
+<li><strong>many or few?</strong> Some services benefit from having many nodes, while some services are best run on only one or two nodes.</li>
+<li><strong>required or optional?</strong> Some services are required, while others can be left out.</li>
+<li><strong>who does the node communicate with?</strong> Some services communicate very heavily with other particular services. Nodes running these services should be close together.</li>
+<li><strong>public or private network?</strong> Some services communicate with the public internet, while others only need to communicate with other nodes in the infrastructure.</li>
+</ul>
+
+
+<h1><a name="available-services"></a>Available services</h1>
+
+<table class="table table-striped">
+<tr>
+ <th>Service</th>
+ <th>VPN</th>
+ <th>Email</th>
+ <th>Notes</th>
+</tr>
+<tr>
+ <td>webapp</td>
+ <td><i class="fa fa-circle"></i></td>
+ <td><i class="fa fa-circle"></i></td>
+ <td>User control panel, provider API, and support system.</td>
+</tr>
+<tr>
+ <td>couchdb</td>
+ <td><i class="fa fa-circle"></i></td>
+ <td><i class="fa fa-circle"></i></td>
+ <td>Data storage for everything. Private node.</td>
+<td></td>
+</tr>
+<tr>
+ <td>soledad</td>
+ <td><i class="fa fa-circle-o"></i></td>
+ <td><i class="fa fa-circle"></i></td>
+ <td>User data synchronization daemon. Usually paired with <code>couchdb</code> nodes.</td>
+<td></td>
+</tr>
+<tr>
+ <td>mx</td>
+ <td><i class="fa fa-circle-o"></i></td>
+ <td><i class="fa fa-circle"></i></td>
+ <td>Incoming and outgoing MX servers.</td>
+</tr>
+<tr>
+ <td>openvpn</td>
+ <td><i class="fa fa-circle"></i></td>
+ <td><i class="fa fa-circle-o"></i></td>
+ <td>OpenVPN gateways.</td>
+</tr>
+<tr>
+ <td>monitor</td>
+ <td><i class="fa fa-dot-circle-o"></i></td>
+ <td><i class="fa fa-dot-circle-o"></i></td>
+ <td>Nagios monitoring. This service must be on the webapp node.</td>
+</tr>
+<tr>
+ <td>tor</td>
+ <td><i class="fa fa-dot-circle-o"></i></td>
+ <td><i class="fa fa-dot-circle-o"></i></td>
+ <td>Tor exit node.</td>
+</tr>
+</table>
+
+
+<p>Key: <i class="fa fa-circle"> Required</i>, <i class="fa fa-dot-circle-o"> Optional</i>, <i class="fa fa-circle-o"> Not Used</i></p>
+
+<p><div class=' page-summary'>
+<h2>
+<a href='couchdb.html'>couchdb</a>
+</h2>
+<div class='summary'>Data storage for all user data.</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='openvpn.html'>openvpn</a>
+</h2>
+<div class='summary'>OpenVPN egress gateways</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='monitor.html'>monitor</a>
+</h2>
+<div class='summary'>Nagios monitoring and continuous testing.</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='mx.html'>mx</a>
+</h2>
+<div class='summary'>Incoming and outgoing MX servers.</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='soledad.html'>soledad</a>
+</h2>
+<div class='summary'>User data synchronization daemon</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='tor.html'>tor</a>
+</h2>
+<div class='summary'>Tor exit node or hidden service</div>
+</div>
+<div class=' page-summary'>
+<h2>
+<a href='webapp.html'>webapp</a>
+</h2>
+<div class='summary'>leap_web user management application and provider API.</div>
+</div>
+</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/monitor.html b/docs/en/services/monitor.html
new file mode 100644
index 00000000..5ed2e2fc
--- /dev/null
+++ b/docs/en/services/monitor.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+monitor - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class='active level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>monitor</h1>
+
+<div id='summary'>Nagios monitoring and continuous testing.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="monitor/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="monitor/index.html#configuration">Configuration</a>
+ </li>
+ <li>
+ <a href="monitor/index.html#access-nagios-web">Access nagios web</a>
+ </li>
+</ol></div>
+
+<p>The <code>monitor</code> node provides a nagios control panel that will give you a view into the health and status of all the servers and all the services. It will also spam you with alerts if something goes down.</p>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, you can have zero or one <code>monitor</code> nodes defined. It is required that the monitor be on the webapp node. It was not designed to be run as a separate node service.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<ul>
+<li><code>nagios.environments</code>: By default, the monitor node will monitor all servers in all environments. You can <strong>optionally</strong> restrict the environments to the ones you specify.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "nagios": {
+ "environments": ["unstable", "production"]
+ }
+}
+</code></pre>
+
+<h2><a name="access-nagios-web"></a>Access nagios web</h2>
+
+<p>To open the nagios control panel:</p>
+
+<pre><code>workstation$ leap open monitor
+</code></pre>
+
+<p>This will open a web browser window with the appropriate URL, including the nagios username and password.</p>
+
+<p>If the URL does not open because of HSTS or DNS problems, pass the <code>--ip</code> option to <code>leap</code>.</p>
+
+<p>If you are using an older version of <code>leap</code> command that doesn&rsquo;t include <code>leap open</code>, you can determine the nagio parameters manually:</p>
+
+<p>Step 1. find the domain:</p>
+
+<pre><code>workstation$ export DOMAIN=$(leap ls --print webapp.domain monitor | grep . | cut -f3 -d' ')
+</code></pre>
+
+<p>Step 2. find the username:</p>
+
+<pre><code>workstation$ export USERNAME="nagiosadmin"
+</code></pre>
+
+<p>Step 3. find the password:</p>
+
+<pre><code>workstation$ export PASSWORD=$(grep nagios_admin_password secrets.json | cut -f4 -d\")
+</code></pre>
+
+<p>Step 4. put it all together:</p>
+
+<pre><code>workstation$ sensible-browser "https://$USERNAME:$PASSWORD@$DOMAIN/nagios3"
+</code></pre>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/monitor/index.html b/docs/en/services/monitor/index.html
new file mode 100644
index 00000000..f6a16cdf
--- /dev/null
+++ b/docs/en/services/monitor/index.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+monitor - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class='active level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>monitor</h1>
+
+<div id='summary'>Nagios monitoring and continuous testing.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ </li>
+ <li>
+ <a href="index.html#access-nagios-web">Access nagios web</a>
+ </li>
+</ol></div>
+
+<p>The <code>monitor</code> node provides a nagios control panel that will give you a view into the health and status of all the servers and all the services. It will also spam you with alerts if something goes down.</p>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, you can have zero or one <code>monitor</code> nodes defined. It is required that the monitor be on the webapp node. It was not designed to be run as a separate node service.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<ul>
+<li><code>nagios.environments</code>: By default, the monitor node will monitor all servers in all environments. You can <strong>optionally</strong> restrict the environments to the ones you specify.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "nagios": {
+ "environments": ["unstable", "production"]
+ }
+}
+</code></pre>
+
+<h2><a name="access-nagios-web"></a>Access nagios web</h2>
+
+<p>To open the nagios control panel:</p>
+
+<pre><code>workstation$ leap open monitor
+</code></pre>
+
+<p>This will open a web browser window with the appropriate URL, including the nagios username and password.</p>
+
+<p>If the URL does not open because of HSTS or DNS problems, pass the <code>--ip</code> option to <code>leap</code>.</p>
+
+<p>If you are using an older version of <code>leap</code> command that doesn&rsquo;t include <code>leap open</code>, you can determine the nagio parameters manually:</p>
+
+<p>Step 1. find the domain:</p>
+
+<pre><code>workstation$ export DOMAIN=$(leap ls --print webapp.domain monitor | grep . | cut -f3 -d' ')
+</code></pre>
+
+<p>Step 2. find the username:</p>
+
+<pre><code>workstation$ export USERNAME="nagiosadmin"
+</code></pre>
+
+<p>Step 3. find the password:</p>
+
+<pre><code>workstation$ export PASSWORD=$(grep nagios_admin_password secrets.json | cut -f4 -d\")
+</code></pre>
+
+<p>Step 4. put it all together:</p>
+
+<pre><code>workstation$ sensible-browser "https://$USERNAME:$PASSWORD@$DOMAIN/nagios3"
+</code></pre>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/mx.html b/docs/en/services/mx.html
new file mode 100644
index 00000000..8e08cfe0
--- /dev/null
+++ b/docs/en/services/mx.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+mx - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class='active level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>mx</h1>
+
+<div id='summary'>Incoming and outgoing MX servers.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="mx/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="mx/index.html#configuration">Configuration</a>
+ <ol>
+ <li>
+ <a href="mx/index.html#aliases">Aliases</a>
+ </li>
+ </ol>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p><code>mx</code> nodes communicate with the public internet, clients, and <code>couchdb</code> nodes.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<h3><a name="aliases"></a>Aliases</h3>
+
+<p>Using the <code>mx.aliases</code> property, you can specify your own hard-coded email aliases that precedence over the aliases in the user database. The <code>mx.aliases</code> property consists of a hash, where source address points to one or more destination addresses.</p>
+
+<p>For example:</p>
+
+<p><code>services/mx.json</code>:</p>
+
+<pre><code>"mx": {
+ "aliases": {
+ "rook": "crow",
+ "robin": "robin@bird.org",
+ "flock": ["junco@bird.org", "robin", "crow"],
+ "chickadee@avian.org": "chickadee@bird.org",
+ "flicker": ["flicker@bird.org", "flicker@deliver.local"]
+ }
+}
+</code></pre>
+
+<p>This example demonstrates several of the features with <code>mx.aliases</code>:</p>
+
+<ol>
+<li>alias lists: by specifying an array of destination addresses, as in the case of &ldquo;flock&rdquo;, the single email will get copied to each address.</li>
+<li>chained resolution: alias resolution will recursively continue until there are no more matching aliases. For example, &ldquo;flock&rdquo; is resolved to &ldquo;robin&rdquo;, which then gets resolved to &ldquo;<a href="&#x6d;&#x61;&#105;&#x6c;&#x74;&#111;&#58;&#114;&#111;&#x62;&#x69;&#110;&#x40;&#98;&#105;&#x72;&#100;&#x2e;&#111;&#114;&#103;">&#114;&#111;&#x62;&#105;&#x6e;&#x40;&#x62;&#x69;&#114;&#x64;&#46;&#x6f;&#x72;&#x67;</a>&rdquo;.</li>
+<li>virtual domains: by specifying the full domain, as in the case of &ldquo;<a href="&#109;&#x61;&#105;&#108;&#x74;&#x6f;&#x3a;&#x63;&#104;&#x69;&#x63;&#x6b;&#97;&#x64;&#101;&#101;&#x40;&#97;&#118;&#105;&#97;&#110;&#x2e;&#111;&#x72;&#x67;">&#x63;&#x68;&#x69;&#99;&#107;&#x61;&#x64;&#101;&#101;&#64;&#x61;&#x76;&#105;&#97;&#x6e;&#x2e;&#x6f;&#x72;&#103;</a>&rdquo;, the alias will work for any domain you want. Of course, the MX record for that domain must point to appropriate MX servers, but otherwise you don&rsquo;t need to do any additional configuration.</li>
+<li>local delivery: for testing purposes, it is often useful to copy all incoming mail for a particular address and send those copies to another address. You can do this by adding &ldquo;@deliver.local&rdquo; as one of the destination addresses. When &ldquo;@local.delivery&rdquo; is found, alias resolution stops and the mail is delivered to that username.</li>
+</ol>
+
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/mx/index.html b/docs/en/services/mx/index.html
new file mode 100644
index 00000000..6899e0cc
--- /dev/null
+++ b/docs/en/services/mx/index.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+mx - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class='active level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>mx</h1>
+
+<div id='summary'>Incoming and outgoing MX servers.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ <ol>
+ <li>
+ <a href="index.html#aliases">Aliases</a>
+ </li>
+ </ol>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p><code>mx</code> nodes communicate with the public internet, clients, and <code>couchdb</code> nodes.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<h3><a name="aliases"></a>Aliases</h3>
+
+<p>Using the <code>mx.aliases</code> property, you can specify your own hard-coded email aliases that precedence over the aliases in the user database. The <code>mx.aliases</code> property consists of a hash, where source address points to one or more destination addresses.</p>
+
+<p>For example:</p>
+
+<p><code>services/mx.json</code>:</p>
+
+<pre><code>"mx": {
+ "aliases": {
+ "rook": "crow",
+ "robin": "robin@bird.org",
+ "flock": ["junco@bird.org", "robin", "crow"],
+ "chickadee@avian.org": "chickadee@bird.org",
+ "flicker": ["flicker@bird.org", "flicker@deliver.local"]
+ }
+}
+</code></pre>
+
+<p>This example demonstrates several of the features with <code>mx.aliases</code>:</p>
+
+<ol>
+<li>alias lists: by specifying an array of destination addresses, as in the case of &ldquo;flock&rdquo;, the single email will get copied to each address.</li>
+<li>chained resolution: alias resolution will recursively continue until there are no more matching aliases. For example, &ldquo;flock&rdquo; is resolved to &ldquo;robin&rdquo;, which then gets resolved to &ldquo;<a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#x3a;&#x72;&#x6f;&#x62;&#105;&#x6e;&#64;&#x62;&#105;&#x72;&#100;&#46;&#111;&#x72;&#x67;">&#114;&#111;&#98;&#x69;&#x6e;&#x40;&#98;&#x69;&#x72;&#x64;&#46;&#x6f;&#x72;&#x67;</a>&rdquo;.</li>
+<li>virtual domains: by specifying the full domain, as in the case of &ldquo;<a href="&#x6d;&#97;&#105;&#108;&#116;&#x6f;&#x3a;&#x63;&#x68;&#105;&#x63;&#x6b;&#97;&#x64;&#x65;&#101;&#x40;&#x61;&#118;&#x69;&#97;&#x6e;&#46;&#x6f;&#114;&#x67;">&#99;&#104;&#105;&#x63;&#x6b;&#97;&#100;&#x65;&#101;&#64;&#97;&#x76;&#x69;&#97;&#x6e;&#x2e;&#x6f;&#114;&#103;</a>&rdquo;, the alias will work for any domain you want. Of course, the MX record for that domain must point to appropriate MX servers, but otherwise you don&rsquo;t need to do any additional configuration.</li>
+<li>local delivery: for testing purposes, it is often useful to copy all incoming mail for a particular address and send those copies to another address. You can do this by adding &ldquo;@deliver.local&rdquo; as one of the destination addresses. When &ldquo;@local.delivery&rdquo; is found, alias resolution stops and the mail is delivered to that username.</li>
+</ol>
+
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/openvpn.html b/docs/en/services/openvpn.html
new file mode 100644
index 00000000..e5fe1128
--- /dev/null
+++ b/docs/en/services/openvpn.html
@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+openvpn - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class='active level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>openvpn</h1>
+
+<div id='summary'>OpenVPN egress gateways</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="openvpn/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="openvpn/index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, <code>openvpn</code> service should not be combined with other services on the same node.</p>
+
+<p>Unlike most of the other node types, the <code>openvpn</code> nodes do not need access to the database and does not ever communicate with any other nodes (except for the <code>monitor</code> node, if used). So, <code>openvpn</code> nodes can be placed anywhere without regard to the other nodes.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p><em>Essential configuration</em></p>
+
+<ul>
+<li><code>openvpn.gateway_address</code>: The address that OpenVPN daemon is bound to and that VPN clients connect to.</li>
+<li><code>ip_address</code>: The main IP of the server, and the egress address for outgoing traffic.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "ip_address": "1.1.1.1",
+ "openvpn": {
+ "gateway_address": "2.2.2.2"
+ }
+}
+</code></pre>
+
+<p>In this example, VPN clients will connect to 2.2.2.2, but their traffic will appear to come from 1.1.1.1.</p>
+
+<p>Why are two IP addresses needed? Without this, traffic between two VPN users on the same gateway will not get encrypted. This is because the VPN on every client must be configured to allow cleartext traffic for the IP address that is the VPN gateway.</p>
+
+<p><em>Optional configuration</em></p>
+
+<p>Here is the default configuration:</p>
+
+<pre><code>"openvpn": {
+ "configuration": {
+ "auth": "SHA1",
+ "cipher": "AES-128-CBC",
+ "fragment": 1400,
+ "keepalive": "10 30",
+ "tls-cipher": "DHE-RSA-AES128-SHA",
+ "tun-ipv6": true
+ },
+ "ports": ["80", "443", "53", "1194"],
+ "protocols": ["tcp", "udp"]
+}
+</code></pre>
+
+<p>You may want to change the ports so that only 443 or 80 are used. It is probably best to not modify the <code>openvpn.configuration</code> options for now.</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/openvpn/index.html b/docs/en/services/openvpn/index.html
new file mode 100644
index 00000000..4a9dc993
--- /dev/null
+++ b/docs/en/services/openvpn/index.html
@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+openvpn - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class='active level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>openvpn</h1>
+
+<div id='summary'>OpenVPN egress gateways</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, <code>openvpn</code> service should not be combined with other services on the same node.</p>
+
+<p>Unlike most of the other node types, the <code>openvpn</code> nodes do not need access to the database and does not ever communicate with any other nodes (except for the <code>monitor</code> node, if used). So, <code>openvpn</code> nodes can be placed anywhere without regard to the other nodes.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p><em>Essential configuration</em></p>
+
+<ul>
+<li><code>openvpn.gateway_address</code>: The address that OpenVPN daemon is bound to and that VPN clients connect to.</li>
+<li><code>ip_address</code>: The main IP of the server, and the egress address for outgoing traffic.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "ip_address": "1.1.1.1",
+ "openvpn": {
+ "gateway_address": "2.2.2.2"
+ }
+}
+</code></pre>
+
+<p>In this example, VPN clients will connect to 2.2.2.2, but their traffic will appear to come from 1.1.1.1.</p>
+
+<p>Why are two IP addresses needed? Without this, traffic between two VPN users on the same gateway will not get encrypted. This is because the VPN on every client must be configured to allow cleartext traffic for the IP address that is the VPN gateway.</p>
+
+<p><em>Optional configuration</em></p>
+
+<p>Here is the default configuration:</p>
+
+<pre><code>"openvpn": {
+ "configuration": {
+ "auth": "SHA1",
+ "cipher": "AES-128-CBC",
+ "fragment": 1400,
+ "keepalive": "10 30",
+ "tls-cipher": "DHE-RSA-AES128-SHA",
+ "tun-ipv6": true
+ },
+ "ports": ["80", "443", "53", "1194"],
+ "protocols": ["tcp", "udp"]
+}
+</code></pre>
+
+<p>You may want to change the ports so that only 443 or 80 are used. It is probably best to not modify the <code>openvpn.configuration</code> options for now.</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/soledad.html b/docs/en/services/soledad.html
new file mode 100644
index 00000000..be372401
--- /dev/null
+++ b/docs/en/services/soledad.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+soledad - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class='active level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>soledad</h1>
+
+<div id='summary'>User data synchronization daemon</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="soledad/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="soledad/index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, the platform is designed for <code>soledad</code> and <code>couchdb</code> services to be combined (e.g. every <code>soledad</code> node should also be a <code>couchdb</code> node). <code>soledad</code> nodes might work in isolation, but this is not tested.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p>There are no options to configure for <code>soledad</code> nodes.</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/soledad/index.html b/docs/en/services/soledad/index.html
new file mode 100644
index 00000000..33e72046
--- /dev/null
+++ b/docs/en/services/soledad/index.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+soledad - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class='active level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>soledad</h1>
+
+<div id='summary'>User data synchronization daemon</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, the platform is designed for <code>soledad</code> and <code>couchdb</code> services to be combined (e.g. every <code>soledad</code> node should also be a <code>couchdb</code> node). <code>soledad</code> nodes might work in isolation, but this is not tested.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p>There are no options to configure for <code>soledad</code> nodes.</p>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/tor.html b/docs/en/services/tor.html
new file mode 100644
index 00000000..f649c086
--- /dev/null
+++ b/docs/en/services/tor.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+tor - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class='active level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>tor</h1>
+
+<div id='summary'>Tor exit node or hidden service</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="tor/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="tor/index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Nodes with <code>tor</code> service will run a Tor exit or hidden service, depending on what other service it is paired with:</p>
+
+<ul>
+<li><code>tor</code> + <code>openvpn</code>: when combined with <code>openvpn</code> nodes, <code>tor</code> will create a Tor exit node to provide extra cover traffic for the VPN. This can be especially useful if there are VPN gateways without much traffic.</li>
+<li><code>tor</code> + <code>webapp</code>: when combined with a <code>webapp</code> node, the <code>tor</code> service will make the webapp and the API available via .onion hidden service.</li>
+<li><code>tor</code> stand alone: a regular Tor exit node.</li>
+</ul>
+
+
+<p>If activated, you can list the hidden service .onion addresses this way:</p>
+
+<p> leap ls &ndash;print tor.hidden_service.address tor</p>
+
+<p>Then just add &lsquo;.onion&rsquo; to the end of the printed addresses.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<ul>
+<li><code>tor.bandwidth_rate</code>: the max bandwidth allocated to Tor, in KB per second, when used as an exit node.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "tor": {
+ "bandwidth_rate": 6550
+ }
+}
+</code></pre>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/tor/index.html b/docs/en/services/tor/index.html
new file mode 100644
index 00000000..8fecf152
--- /dev/null
+++ b/docs/en/services/tor/index.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+tor - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class='active level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>tor</h1>
+
+<div id='summary'>Tor exit node or hidden service</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ </li>
+</ol></div>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Nodes with <code>tor</code> service will run a Tor exit or hidden service, depending on what other service it is paired with:</p>
+
+<ul>
+<li><code>tor</code> + <code>openvpn</code>: when combined with <code>openvpn</code> nodes, <code>tor</code> will create a Tor exit node to provide extra cover traffic for the VPN. This can be especially useful if there are VPN gateways without much traffic.</li>
+<li><code>tor</code> + <code>webapp</code>: when combined with a <code>webapp</code> node, the <code>tor</code> service will make the webapp and the API available via .onion hidden service.</li>
+<li><code>tor</code> stand alone: a regular Tor exit node.</li>
+</ul>
+
+
+<p>If activated, you can list the hidden service .onion addresses this way:</p>
+
+<p> leap ls &ndash;print tor.hidden_service.address tor</p>
+
+<p>Then just add &lsquo;.onion&rsquo; to the end of the printed addresses.</p>
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<ul>
+<li><code>tor.bandwidth_rate</code>: the max bandwidth allocated to Tor, in KB per second, when used as an exit node.</li>
+</ul>
+
+
+<p>For example:</p>
+
+<pre><code>{
+ "tor": {
+ "bandwidth_rate": 6550
+ }
+}
+</code></pre>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/webapp.html b/docs/en/services/webapp.html
new file mode 100644
index 00000000..6c853c22
--- /dev/null
+++ b/docs/en/services/webapp.html
@@ -0,0 +1,479 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+webapp - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='tor.html'>tor</a>
+</li>
+<li class='active level1'>
+<a class='' href='webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>webapp</h1>
+
+<div id='summary'>leap_web user management application and provider API.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="webapp/index.html#introduction">Introduction</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#configuration">Configuration</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#invite-codes">Invite codes</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#customization">Customization</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#customization-tutorial">Customization tutorial</a>
+ <ol>
+ <li>
+ <a href="webapp/index.html#override-translations">Override translations</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#override-static-pages">Override static pages</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#add-a-custom-header">Add a custom header</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="webapp/index.html#custom-fork">Custom Fork</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#maintenance-mode">Maintenance mode</a>
+ </li>
+ <li>
+ <a href="webapp/index.html#known-problems">Known problems</a>
+ </li>
+</ol></div>
+
+<h2><a name="introduction"></a>Introduction</h2>
+
+<p>The service <code>webapp</code> will install the web application <a href="https://leap.se/git/leap_web.git">leap_web</a>. It has performs the following functions:</p>
+
+<ul>
+<li>REST API for user registration and authentication via the Bitmask client.</li>
+<li>Admin interface to manage users.</li>
+<li>Client certificate distribution and renewal.</li>
+<li>User support help tickets.</li>
+</ul>
+
+
+<p>Coming soon:</p>
+
+<ul>
+<li>Billing.</li>
+<li>Customizable and localized user documentation.</li>
+</ul>
+
+
+<p>The leap_web application is written in Ruby on Rails 3, using CouchDB as the backend data store.</p>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, the platform only supports a single <code>webapp</code> node, although we hope to change this in the future.</p>
+
+<ul>
+<li><code>webapp</code> nodes communicate heavily with <code>couchdb</code> nodes, but the two can be on separate servers.</li>
+<li>The <code>monitor</code> service, if enabled, must be on the same node as <code>webapp</code>.</li>
+</ul>
+
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p>Essential options:</p>
+
+<ul>
+<li><code>webapp.admin</code>: An array of usernames that will be blessed with administrative permissions. These admins can delete users, answer help tickets, and so on. These usernames are for users that have registered through the webapp or through the Bitmask client application, NOT the sysadmin usernames lists in the provider directory <code>users</code>.</li>
+</ul>
+
+
+<p>Other options:</p>
+
+<ul>
+<li><code>webapp.engines</code>: A list of the engines you want enabled in leap_web. Currently, only &ldquo;support&rdquo; is available, and it is enabled by default.</li>
+<li><code>webapp.invite_required</code>: If true, registration requires an invite code. Default is <code>false</code>.</li>
+</ul>
+
+
+<p>For example, <code>services/webapp.json</code>:</p>
+
+<pre><code>{
+ "webapp": {
+ "admins": ["joehill", "ali", "mack_the_turtle"]
+ }
+}
+</code></pre>
+
+<p>By putting this in <code>services/webapp.json</code>, all the <code>webapp</code> nodes will inherit the same admin list.</p>
+
+<p>There are many options in <code>provider.json</code> that also control how the webapp behaves. See <a href="../guide/provider-configuration.html">Provider Configuration</a> for details.</p>
+
+<h2><a name="invite-codes"></a>Invite codes</h2>
+
+<p>Enabling the invite code functionality will require new users to provide a valid invite code while signing up for a new account. This is turned off by default, allowing all new users to create an account.</p>
+
+<p>Set the <code>invite_code</code> option to <code>true</code> in <code>services/webapp.json</code>:</p>
+
+<pre><code>{
+ "webapp": {
+ "invite_required": true
+ }
+}
+</code></pre>
+
+<p>This only works with LEAP platform 0.8 or higher.</p>
+
+<p>Run <code>leap deploy</code> to enable the option.</p>
+
+<p>You can then generate invite codes by logging into the web application with an admin user.</p>
+
+<p>Alternately, you can also generate invite codes with the command line:</p>
+
+<pre><code>workstation$ leap ssh bumblebee
+bumblebee# cd /srv/leap/webapp/
+bumblebee# sudo -u leap-webapp RAILS_ENV=production bundle exec rake "generate_invites[NUM,USES]"
+</code></pre>
+
+<p>Where <code>bumblebee</code> should be replaced with the name of your webapp node.</p>
+
+<p>The <strong>NUM</strong> specifies the amount of codes to generate. The <strong>USES</strong> parameter is optional: By default, all new invite codes can be used once and will then become invalid. If you provide another value for <strong>USES</strong>, you can set a different amount of maximum uses for the codes you generate.</p>
+
+<h2><a name="customization"></a>Customization</h2>
+
+<p>The provider directory <code>files/webapp</code> can be used to customize the appearance of the webapp. All the files in this directory will get sync'ed to the <code>/srv/leap/webapp/config/customization</code> directory of the deployed webapp node.</p>
+
+<p>Files in the <code>files/webapp</code> can override view files, locales, and stylesheets in the leap_web app:</p>
+
+<p>For example:</p>
+
+<pre><code>stylesheets/ -- override files in Rails.root/app/assets/stylesheets
+ tail.scss -- included before all others
+ head.scss -- included after all others
+
+public/ -- overrides files in Rails.root/public
+ favicon.ico -- custom favicon
+ img/ -- customary directory to put images in
+
+views/ -- overrides files Rails.root/app/views
+ home/
+ index.html.haml -- this file is what shows up on
+ the home page
+ pages/
+ privacy-policy.en.md -- this file will override
+ the default privacy policy
+ terms-of-service.en.md -- this file will override
+ the default TOS.
+
+locales/ -- overrides files in Rails.root/config/locales
+ en.yml -- overrides for English
+ de.yml -- overrides for German
+ and so on...
+</code></pre>
+
+<p>To interactively develop your customizations before you deploy them, you have two options:</p>
+
+<ol>
+<li>Edit a <code>webapp</code> node. This approach involves directly modifying the contents of the directory <code>/srv/leap/webapp/config/customization</code> on a deployed <code>webapp</code> node. This can, and probably should be, a &ldquo;local&rdquo; node. When doing this, you may need to restart leap_web in order for changes to take effect (<code>touch /srv/leap/webapp/tmp/restart.txt</code>).</li>
+<li>Alternately, you can install leap_web to run on your computer and edit files in <code>config/customization</code> locally. This approach does not require a provider or a <code>webapp</code> node. For more information, see the <a href="https://github.com/leapcode/leap_web">leap_web README</a>.</li>
+</ol>
+
+
+<p>NOTE: If you add a <code>tails.scss</code> or <code>head.scss</code> file, then you usually need to run <code>rake tmp:clear</code> and restart rails in order for the new stylesheet to get recognized. You should only need to do this once.</p>
+
+<p>Once you have what you want, then copy these files to the local provider directory <code>files/webapp</code> so that they will be installed each time you deploy.</p>
+
+<h2><a name="customization-tutorial"></a>Customization tutorial</h2>
+
+<p>This mini-tutorial will walk you through creating a custom &ldquo;branding&rdquo; of the leap_web application. We will be creating a provider called &ldquo;Prehistoric Computer.&rdquo;</p>
+
+<p>Here are the files we are going to create:</p>
+
+<pre><code>leap_web/config/customization
+├── locales
+│   ├── en.yml
+│   └── es.yml
+├── public
+│   ├── favicon.ico
+│   └── img
+│   └── masthead.png
+├── stylesheets
+│   └── tail.scss
+└── views
+ └── pages
+ ├── privacy-policy.en.md
+ └── privacy-policy.es.md
+</code></pre>
+
+<p>All these files are available in the source code in the <a href="https://github.com/leapcode/leap_web/tree/develop/config/customization.example">customization.example</a> directory.</p>
+
+<p>Remember, these files may live different places:</p>
+
+<ul>
+<li><code>user@localmachine$ leap_web/config/customization</code>: This will be the path if you have checked out a local copy of leap_web.git and are running <code>rails server</code> locally in order to test your customizations.</li>
+<li><code>user@localmachine$ PROVIDER/files/webapp</code>: This is the local provider directory where the files should be put so that they get correctly deployed to webapp nodes.</li>
+<li><code>root@webappnode# /srv/leap/webapp/config/customization</code>: This is where the files in the local provider directory <code>PROVIDER/files/webapp</code> get copied to after a <code>leap deploy</code> to a live webapp nodes.</li>
+</ul>
+
+
+<h3><a name="override-translations"></a>Override translations</h3>
+
+<p>You can add additional locale files in order to change the text used in the existing application and to add translations for string that you added to the application.</p>
+
+<p>In this example, we will be altering the default text for the &ldquo;login_info&rdquo; string. In <code>config/locales/en/home.en.yml</code> there is this entry:</p>
+
+<pre><code>en:
+ login_info: "Log in to change your account settings, create support tickets, and manage payments."
+</code></pre>
+
+<p>We are going to override this with some custom text in English and Spanish:</p>
+
+<p><code>leap_web/config/customization/locale/en.yml</code>:</p>
+
+<pre><code>en:
+ login_info: Authenticate to change your "Prehistoric Computer" settings.
+</code></pre>
+
+<p><code>leap_web/config/customization/locale/es.yml</code>:</p>
+
+<pre><code>es:
+ login_info: Autenticar a cambiar la configuración de "Computer Prehistoria."
+</code></pre>
+
+<p>Now, the home page of leap_web will use these new strings instead of the default. Remember that you must restart rails in order for new locale files to take effect.</p>
+
+<h3><a name="override-static-pages"></a>Override static pages</h3>
+
+<p>You can also override any of the static files included with leap_web, such as the privacy policy or terms of service.</p>
+
+<p>Here is how we would create a custom privacy policy in English and Spanish:</p>
+
+<p><code>leap_web/config/customization/views/pages/privacy-policy.en.md</code>:</p>
+
+<pre><code># Custom Privacy Policy
+This is our privacy policy.
+</code></pre>
+
+<p><code>leap_web/config/customization/views/pages/privacy-policy.es.md</code>:</p>
+
+<pre><code># Custom Política de Privacidad
+Esta es nuestra política de privacidad.
+</code></pre>
+
+<h3><a name="add-a-custom-header"></a>Add a custom header</h3>
+
+<p>Now we will add a custom header to every page. First, we add the images:</p>
+
+<pre><code>leap_web/config/customization
+ ├── public
+ ├── favicon.ico
+ └── img
+ └── masthead.png
+</code></pre>
+
+<p>You can create your own, or use the example files in <a href="https://github.com/leapcode/leap_web/tree/develop/config/customization.example">https://github.com/leapcode/leap_web/tree/develop/config/customization.example</a></p>
+
+<p>Now, we add some custom CSS so that we can style the masthead:</p>
+
+<p><code>leap_web/config/customization/stylesheets/tail.scss</code></p>
+
+<pre><code>$custom-color: #66bbaa;
+
+a {
+ color: $custom-color;
+}
+
+//
+// MASTHEAD
+//
+
+#masthead {
+ background-color: $custom-color;
+ border-bottom: none;
+
+ // make the masthead clickable by replacing the
+ // site name link with the masthead image:
+ .title {
+ padding: 0px;
+ .sitename a {
+ display: block;
+ background: url(/img/masthead.png) 0 0 no-repeat;
+ font-size: 0px;
+ height: 100px;
+ background-size: auto 100px;
+ }
+ }
+}
+
+// make the home page masthead slightly larger
+body.home #masthead {
+ .sitename a {
+ height: 150px;
+ background-size: auto 150px;
+ }
+}
+
+//
+// FOOTER
+//
+
+#footer .links {
+ background-color: $custom-color;
+}
+</code></pre>
+
+<p>NOTE: If you add a <code>tails.scss</code> or <code>head.scss</code> file, then you usually need to run <code>rake tmp:clear</code> and restart rails in order for the new stylesheet to get recognized. You should only need to do this once.</p>
+
+<h2><a name="custom-fork"></a>Custom Fork</h2>
+
+<p>Sometimes it is easier to maintain your own fork of the leap_web app. You can keep your customizations in that fork instead of in the provider <code>files/webapp</code> directory. Or, perhaps you want to add an engine to the application that modifies the app&rsquo;s behavior.</p>
+
+<p>To deploy your own leap_web, modify the provider file <code>common.json</code>:</p>
+
+<pre><code>{
+ "sources": {
+ "webapp": {
+ "revision": "origin/develop",
+ "source": "https://github.com/leapcode/leap_web",
+ "type": "git"
+ }
+ }
+}
+</code></pre>
+
+<p>To target only particular environment, modify instead <code>common.ENV.json</code>, where ENV is the name of the environment.</p>
+
+<p>See <a href="https://github.com/leapcode/leap_web/blob/develop/doc/DEVELOP.md">https://github.com/leapcode/leap_web/blob/develop/doc/DEVELOP.md</a> for notes on getting started hacking on leap_web.</p>
+
+<h2><a name="maintenance-mode"></a>Maintenance mode</h2>
+
+<p>You can put the webapp into maintenance mode by simply dropping a html file to <code>/srv/leap/webapp/public/system/maintenance.html</code>. For example:</p>
+
+<pre><code>workstation$ leap ssh webappnode
+server# echo "Temporarily down for maintenance. We will be back soon." &gt; /srv/leap/webapp/public/system/maintenance.html
+</code></pre>
+
+<h2><a name="known-problems"></a>Known problems</h2>
+
+<ul>
+<li>Client certificates are generated without a CSR. The problem is that this makes the web
+application extremely vulnerable to denial of service attacks. This was not an issue until we
+started to allow the possibility of anonymously fetching a client certificate without
+authenticating first.</li>
+<li>By its very nature, the user database is vulnerable to enumeration attacks. These are
+very hard to prevent, because our protocol is designed to allow query of a user database via
+proxy in order to provide network perspective.</li>
+</ul>
+
+
+</div>
+</div>
+</body>
+</html>
diff --git a/docs/en/services/webapp/index.html b/docs/en/services/webapp/index.html
new file mode 100644
index 00000000..acdc098c
--- /dev/null
+++ b/docs/en/services/webapp/index.html
@@ -0,0 +1,479 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>
+webapp - LEAP Platform Documentation
+</title>
+<meta content='width=device-width, initial-scale=1.0' name='viewport'>
+<meta charset='UTF-8'>
+<base href="" />
+<style>
+ body {
+ background: #444;
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ margin: 0px;
+ }
+ #sidebar {
+ flex: 0 0 250px;
+ background: white;
+ margin-right: 10px;
+ padding: 20px;
+ }
+ #sidebar ul {
+ list-style-type: none;
+ padding-left: 0px;
+ margin: 0;
+ }
+ #sidebar li { padding: 4px }
+ #sidebar li a { text-decoration: none }
+ #sidebar li.active { background: #444 }
+ #sidebar li.active a { color: white }
+ #sidebar li.level1 { padding-left: 20px }
+ #sidebar li.level2 { padding-left: 40px }
+ #main {
+ flex: 1 1 auto;
+ background: white;
+ padding: 20px;
+ }
+ #title-box {
+ padding-bottom: 20px;
+ border-bottom: 5px solid #eee;
+ }
+ #title-box h1 {
+ margin-top: 0px;
+ }
+ pre {
+ padding: 10px;
+ background: #eef;
+ }
+ code {
+ background: #eef;
+ }
+ table {border-collapse: collapse}
+ table td {
+ border: 1px solid #ccc;
+ padding: 4px;
+ vertical-align: top;
+ }
+</style>
+</head>
+<body>
+<div id='sidebar'>
+<ul>
+<li class=''>
+<a href='../../../index.html'>Home</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../guide.html'>Guide</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../tutorials.html'>Tutorials</a>
+</li>
+<li class='semi-active level0'>
+<a class='' href='../../services.html'>Services</a>
+</li>
+<li class=' level1'>
+<a class='' href='../couchdb.html'>couchdb</a>
+</li>
+<li class=' level1'>
+<a class='' href='../openvpn.html'>openvpn</a>
+</li>
+<li class=' level1'>
+<a class='' href='../monitor.html'>monitor</a>
+</li>
+<li class=' level1'>
+<a class='' href='../mx.html'>mx</a>
+</li>
+<li class=' level1'>
+<a class='' href='../soledad.html'>soledad</a>
+</li>
+<li class=' level1'>
+<a class='' href='../tor.html'>tor</a>
+</li>
+<li class='active level1'>
+<a class='' href='../webapp.html'>webapp</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../upgrading.html'>Upgrading</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../troubleshooting.html'>Troubleshooting</a>
+</li>
+<li class=' level0'>
+<a class='' href='../../details.html'>Details</a>
+</li>
+</ul>
+</div>
+<div id='main'>
+<div id='title-box'>
+<h1>webapp</h1>
+
+<div id='summary'>leap_web user management application and provider API.</div>
+</div>
+<div id='content-box'>
+<div id="TOC"><ol>
+ <li>
+ <a href="index.html#introduction">Introduction</a>
+ </li>
+ <li>
+ <a href="index.html#topology">Topology</a>
+ </li>
+ <li>
+ <a href="index.html#configuration">Configuration</a>
+ </li>
+ <li>
+ <a href="index.html#invite-codes">Invite codes</a>
+ </li>
+ <li>
+ <a href="index.html#customization">Customization</a>
+ </li>
+ <li>
+ <a href="index.html#customization-tutorial">Customization tutorial</a>
+ <ol>
+ <li>
+ <a href="index.html#override-translations">Override translations</a>
+ </li>
+ <li>
+ <a href="index.html#override-static-pages">Override static pages</a>
+ </li>
+ <li>
+ <a href="index.html#add-a-custom-header">Add a custom header</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="index.html#custom-fork">Custom Fork</a>
+ </li>
+ <li>
+ <a href="index.html#maintenance-mode">Maintenance mode</a>
+ </li>
+ <li>
+ <a href="index.html#known-problems">Known problems</a>
+ </li>
+</ol></div>
+
+<h2><a name="introduction"></a>Introduction</h2>
+
+<p>The service <code>webapp</code> will install the web application <a href="https://leap.se/git/leap_web.git">leap_web</a>. It has performs the following functions:</p>
+
+<ul>
+<li>REST API for user registration and authentication via the Bitmask client.</li>
+<li>Admin interface to manage users.</li>
+<li>Client certificate distribution and renewal.</li>
+<li>User support help tickets.</li>
+</ul>
+
+
+<p>Coming soon:</p>
+
+<ul>
+<li>Billing.</li>
+<li>Customizable and localized user documentation.</li>
+</ul>
+
+
+<p>The leap_web application is written in Ruby on Rails 3, using CouchDB as the backend data store.</p>
+
+<h2><a name="topology"></a>Topology</h2>
+
+<p>Currently, the platform only supports a single <code>webapp</code> node, although we hope to change this in the future.</p>
+
+<ul>
+<li><code>webapp</code> nodes communicate heavily with <code>couchdb</code> nodes, but the two can be on separate servers.</li>
+<li>The <code>monitor</code> service, if enabled, must be on the same node as <code>webapp</code>.</li>
+</ul>
+
+
+<h2><a name="configuration"></a>Configuration</h2>
+
+<p>Essential options:</p>
+
+<ul>
+<li><code>webapp.admin</code>: An array of usernames that will be blessed with administrative permissions. These admins can delete users, answer help tickets, and so on. These usernames are for users that have registered through the webapp or through the Bitmask client application, NOT the sysadmin usernames lists in the provider directory <code>users</code>.</li>
+</ul>
+
+
+<p>Other options:</p>
+
+<ul>
+<li><code>webapp.engines</code>: A list of the engines you want enabled in leap_web. Currently, only &ldquo;support&rdquo; is available, and it is enabled by default.</li>
+<li><code>webapp.invite_required</code>: If true, registration requires an invite code. Default is <code>false</code>.</li>
+</ul>
+
+
+<p>For example, <code>services/webapp.json</code>:</p>
+
+<pre><code>{
+ "webapp": {
+ "admins": ["joehill", "ali", "mack_the_turtle"]
+ }
+}
+</code></pre>
+
+<p>By putting this in <code>services/webapp.json</code>, all the <code>webapp</code> nodes will inherit the same admin list.</p>
+
+<p>There are many options in <code>provider.json</code> that also control how the webapp behaves. See <a href="../../guide/provider-configuration.html">Provider Configuration</a> for details.</p>
+
+<h2><a name="invite-codes"></a>Invite codes</h2>
+
+<p>Enabling the invite code functionality will require new users to provide a valid invite code while signing up for a new account. This is turned off by default, allowing all new users to create an account.</p>
+
+<p>Set the <code>invite_code</code> option to <code>true</code> in <code>services/webapp.json</code>:</p>
+
+<pre><code>{
+ "webapp": {
+ "invite_required": true
+ }
+}
+</code></pre>
+
+<p>This only works with LEAP platform 0.8 or higher.</p>
+
+<p>Run <code>leap deploy</code> to enable the option.</p>
+
+<p>You can then generate invite codes by logging into the web application with an admin user.</p>
+
+<p>Alternately, you can also generate invite codes with the command line:</p>
+
+<pre><code>workstation$ leap ssh bumblebee
+bumblebee# cd /srv/leap/webapp/
+bumblebee# sudo -u leap-webapp RAILS_ENV=production bundle exec rake "generate_invites[NUM,USES]"
+</code></pre>
+
+<p>Where <code>bumblebee</code> should be replaced with the name of your webapp node.</p>
+
+<p>The <strong>NUM</strong> specifies the amount of codes to generate. The <strong>USES</strong> parameter is optional: By default, all new invite codes can be used once and will then become invalid. If you provide another value for <strong>USES</strong>, you can set a different amount of maximum uses for the codes you generate.</p>
+
+<h2><a name="customization"></a>Customization</h2>
+
+<p>The provider directory <code>files/webapp</code> can be used to customize the appearance of the webapp. All the files in this directory will get sync'ed to the <code>/srv/leap/webapp/config/customization</code> directory of the deployed webapp node.</p>
+
+<p>Files in the <code>files/webapp</code> can override view files, locales, and stylesheets in the leap_web app:</p>
+
+<p>For example:</p>
+
+<pre><code>stylesheets/ -- override files in Rails.root/app/assets/stylesheets
+ tail.scss -- included before all others
+ head.scss -- included after all others
+
+public/ -- overrides files in Rails.root/public
+ favicon.ico -- custom favicon
+ img/ -- customary directory to put images in
+
+views/ -- overrides files Rails.root/app/views
+ home/
+ index.html.haml -- this file is what shows up on
+ the home page
+ pages/
+ privacy-policy.en.md -- this file will override
+ the default privacy policy
+ terms-of-service.en.md -- this file will override
+ the default TOS.
+
+locales/ -- overrides files in Rails.root/config/locales
+ en.yml -- overrides for English
+ de.yml -- overrides for German
+ and so on...
+</code></pre>
+
+<p>To interactively develop your customizations before you deploy them, you have two options:</p>
+
+<ol>
+<li>Edit a <code>webapp</code> node. This approach involves directly modifying the contents of the directory <code>/srv/leap/webapp/config/customization</code> on a deployed <code>webapp</code> node. This can, and probably should be, a &ldquo;local&rdquo; node. When doing this, you may need to restart leap_web in order for changes to take effect (<code>touch /srv/leap/webapp/tmp/restart.txt</code>).</li>
+<li>Alternately, you can install leap_web to run on your computer and edit files in <code>config/customization</code> locally. This approach does not require a provider or a <code>webapp</code> node. For more information, see the <a href="https://github.com/leapcode/leap_web">leap_web README</a>.</li>
+</ol>
+
+
+<p>NOTE: If you add a <code>tails.scss</code> or <code>head.scss</code> file, then you usually need to run <code>rake tmp:clear</code> and restart rails in order for the new stylesheet to get recognized. You should only need to do this once.</p>
+
+<p>Once you have what you want, then copy these files to the local provider directory <code>files/webapp</code> so that they will be installed each time you deploy.</p>
+
+<h2><a name="customization-tutorial"></a>Customization tutorial</h2>
+
+<p>This mini-tutorial will walk you through creating a custom &ldquo;branding&rdquo; of the leap_web application. We will be creating a provider called &ldquo;Prehistoric Computer.&rdquo;</p>
+
+<p>Here are the files we are going to create:</p>
+
+<pre><code>leap_web/config/customization
+├── locales
+│   ├── en.yml
+│   └── es.yml
+├── public
+│   ├── favicon.ico
+│   └── img
+│   └── masthead.png
+├── stylesheets
+│   └── tail.scss
+└── views
+ └── pages
+ ├── privacy-policy.en.md
+ └── privacy-policy.es.md
+</code></pre>
+
+<p>All these files are available in the source code in the <a href="https://github.com/leapcode/leap_web/tree/develop/config/customization.example">customization.example</a> directory.</p>
+
+<p>Remember, these files may live different places:</p>
+
+<ul>
+<li><code>user@localmachine$ leap_web/config/customization</code>: This will be the path if you have checked out a local copy of leap_web.git and are running <code>rails server</code> locally in order to test your customizations.</li>
+<li><code>user@localmachine$ PROVIDER/files/webapp</code>: This is the local provider directory where the files should be put so that they get correctly deployed to webapp nodes.</li>
+<li><code>root@webappnode# /srv/leap/webapp/config/customization</code>: This is where the files in the local provider directory <code>PROVIDER/files/webapp</code> get copied to after a <code>leap deploy</code> to a live webapp nodes.</li>
+</ul>
+
+
+<h3><a name="override-translations"></a>Override translations</h3>
+
+<p>You can add additional locale files in order to change the text used in the existing application and to add translations for string that you added to the application.</p>
+
+<p>In this example, we will be altering the default text for the &ldquo;login_info&rdquo; string. In <code>config/locales/en/home.en.yml</code> there is this entry:</p>
+
+<pre><code>en:
+ login_info: "Log in to change your account settings, create support tickets, and manage payments."
+</code></pre>
+
+<p>We are going to override this with some custom text in English and Spanish:</p>
+
+<p><code>leap_web/config/customization/locale/en.yml</code>:</p>
+
+<pre><code>en:
+ login_info: Authenticate to change your "Prehistoric Computer" settings.
+</code></pre>
+
+<p><code>leap_web/config/customization/locale/es.yml</code>:</p>
+
+<pre><code>es:
+ login_info: Autenticar a cambiar la configuración de "Computer Prehistoria."
+</code></pre>
+
+<p>Now, the home page of leap_web will use these new strings instead of the default. Remember that you must restart rails in order for new locale files to take effect.</p>
+
+<h3><a name="override-static-pages"></a>Override static pages</h3>
+
+<p>You can also override any of the static files included with leap_web, such as the privacy policy or terms of service.</p>
+
+<p>Here is how we would create a custom privacy policy in English and Spanish:</p>
+
+<p><code>leap_web/config/customization/views/pages/privacy-policy.en.md</code>:</p>
+
+<pre><code># Custom Privacy Policy
+This is our privacy policy.
+</code></pre>
+
+<p><code>leap_web/config/customization/views/pages/privacy-policy.es.md</code>:</p>
+
+<pre><code># Custom Política de Privacidad
+Esta es nuestra política de privacidad.
+</code></pre>
+
+<h3><a name="add-a-custom-header"></a>Add a custom header</h3>
+
+<p>Now we will add a custom header to every page. First, we add the images:</p>
+
+<pre><code>leap_web/config/customization
+ ├── public
+ ├── favicon.ico
+ └── img
+ └── masthead.png
+</code></pre>
+
+<p>You can create your own, or use the example files in <a href="https://github.com/leapcode/leap_web/tree/develop/config/customization.example">https://github.com/leapcode/leap_web/tree/develop/config/customization.example</a></p>
+
+<p>Now, we add some custom CSS so that we can style the masthead:</p>
+
+<p><code>leap_web/config/customization/stylesheets/tail.scss</code></p>
+
+<pre><code>$custom-color: #66bbaa;
+
+a {
+ color: $custom-color;
+}
+
+//
+// MASTHEAD
+//
+
+#masthead {
+ background-color: $custom-color;
+ border-bottom: none;
+
+ // make the masthead clickable by replacing the
+ // site name link with the masthead image:
+ .title {
+ padding: 0px;
+ .sitename a {
+ display: block;
+ background: url(/img/masthead.png) 0 0 no-repeat;
+ font-size: 0px;
+ height: 100px;
+ background-size: auto 100px;
+ }
+ }
+}
+
+// make the home page masthead slightly larger
+body.home #masthead {
+ .sitename a {
+ height: 150px;
+ background-size: auto 150px;
+ }
+}
+
+//
+// FOOTER
+//
+
+#footer .links {
+ background-color: $custom-color;
+}
+</code></pre>
+
+<p>NOTE: If you add a <code>tails.scss</code> or <code>head.scss</code> file, then you usually need to run <code>rake tmp:clear</code> and restart rails in order for the new stylesheet to get recognized. You should only need to do this once.</p>
+
+<h2><a name="custom-fork"></a>Custom Fork</h2>
+
+<p>Sometimes it is easier to maintain your own fork of the leap_web app. You can keep your customizations in that fork instead of in the provider <code>files/webapp</code> directory. Or, perhaps you want to add an engine to the application that modifies the app&rsquo;s behavior.</p>
+
+<p>To deploy your own leap_web, modify the provider file <code>common.json</code>:</p>
+
+<pre><code>{
+ "sources": {
+ "webapp": {
+ "revision": "origin/develop",
+ "source": "https://github.com/leapcode/leap_web",
+ "type": "git"
+ }
+ }
+}
+</code></pre>
+
+<p>To target only particular environment, modify instead <code>common.ENV.json</code>, where ENV is the name of the environment.</p>
+
+<p>See <a href="https://github.com/leapcode/leap_web/blob/develop/doc/DEVELOP.md">https://github.com/leapcode/leap_web/blob/develop/doc/DEVELOP.md</a> for notes on getting started hacking on leap_web.</p>
+
+<h2><a name="maintenance-mode"></a>Maintenance mode</h2>
+
+<p>You can put the webapp into maintenance mode by simply dropping a html file to <code>/srv/leap/webapp/public/system/maintenance.html</code>. For example:</p>
+
+<pre><code>workstation$ leap ssh webappnode
+server# echo "Temporarily down for maintenance. We will be back soon." &gt; /srv/leap/webapp/public/system/maintenance.html
+</code></pre>
+
+<h2><a name="known-problems"></a>Known problems</h2>
+
+<ul>
+<li>Client certificates are generated without a CSR. The problem is that this makes the web
+application extremely vulnerable to denial of service attacks. This was not an issue until we
+started to allow the possibility of anonymously fetching a client certificate without
+authenticating first.</li>
+<li>By its very nature, the user database is vulnerable to enumeration attacks. These are
+very hard to prevent, because our protocol is designed to allow query of a user database via
+proxy in order to provide network perspective.</li>
+</ul>
+
+
+</div>
+</div>
+</body>
+</html>