14.04 http://tech.oeru.org/ en Protecting your users with Let's Encrypt SSL Certs http://tech.oeru.org/protecting-your-users-lets-encrypt-ssl-certs <span class="field field--name-title field--type-string field--label-hidden">Protecting your users with Let&#039;s Encrypt SSL Certs</span> <div class="field field-node--field-blog-tags field-name-field-blog-tags field-type-entity-reference field-label-above"> <h3 class="field__label">Blog tags</h3> <div class="field__items"> <div class="field__item field__item--lets-encrypt"> <span class="field__item-wrapper"><a href="/taxonomy/term/17" hreflang="en">let&#039;s encrypt</a></span> </div> <div class="field__item field__item--install"> <span class="field__item-wrapper"><a href="/taxonomy/term/11" hreflang="en">install</a></span> </div> <div class="field__item field__item--ubuntu-linux"> <span class="field__item-wrapper"><a href="/taxonomy/term/12" hreflang="en">ubuntu linux</a></span> </div> <div class="field__item field__item--_404"> <span class="field__item-wrapper"><a href="/taxonomy/term/13" hreflang="en">14.04</a></span> </div> <div class="field__item field__item--_604"> <span class="field__item-wrapper"><a href="/taxonomy/term/27" hreflang="en">16.04</a></span> </div> <div class="field__item field__item--_804"> <span class="field__item-wrapper"><a href="/taxonomy/term/68" hreflang="en">18.04</a></span> </div> <div class="field__item field__item--_004"> <span class="field__item-wrapper"><a href="/taxonomy/term/75" hreflang="en">20.04</a></span> </div> </div> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/1" lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Thu 08/07/2021 - 14:23</span> <div class="clearfix text-formatted field field-node--body field-name-body field-type-text-with-summary field-label-hidden"> <div class="field__items"> <div class="field__item"><p><a class="visually-hidden focusable skip-link" href="https://tech.oeru.org/node/add/blog_post#main-content">Sk</a>For any website that requires anyone (users or even just a few admins) to transfer secrets to and from it, you want to ensure the data is end-to-end encrypted. Today various browsers (like Firefox) give warnings when you're sending secret data (like passwords) "in the clear", namely unencrypted. In early 2017, Google <a href="http://searchengineland.com/google-starts-giving-ranking-boost-secure-httpsssl-sites-199446">added further urgency</a> to doing the right thing for your users. </p> <p>In the past, getting an SSL certificate to achieve encryption for your domain (the little "lock" icon in browser address bar indicating that your communication with the site is encrypted), was a complicated, expensive proposition, requiring a lot of annoying and time consuming "identity verification" (sometimes via post in the dark old days) and a fee of, in some cases, a couple hundred dollars per year paid to your "SSL Cert Provider" to pay for those administrative services along with the software needed to gin up a long prime number to act as your encryption key (the long string of characters making up your SSL certificate).</p> <p>Thankfully, thanks to the efforts of the <a href="https://letsencrypt.org" title="Let's Encrypt - democratising SSL and making it ubquitous.">Let's Encrypt</a> community, the process is both far far easier, and free of cost. Now there really isn't an excuse for not having an SSL certificate on your site.</p> <p>Members of the Let's Encrypt community have provided a range of useful open source tools you can use to create and maintain certificates on your hosting infrastructure (e.g. the Virtual Machine (VM) on which you're installing web services detailed in the howtos on this site!). In this case we're going to use a tool, "<a href="https://certbot.eff.org/">certbot</a>" provided by the good folks at the <a href="https://eff.org">Electronic Frontier Foundation</a>.</p> <p>For VMs running Ubuntu 18.04 or more recent Long Term Support (LTS) versions of the Ubuntu Linux platform, you should be able to just run:</p> <p><code>sudo apt-get install letsencrypt</code></p> <p>For VMs running Ubuntu 14.04 or 16.04 which are what we use, the install is easy - at your VM command line, run:</p> <pre> <code>sudo add-apt-repository ppa:certbot/certbot sudo apt-get update sudo apt-get install certbot </code></pre> <p>We run Nginx on our VMs, which makes one or more hosted services (normally running in Docker containers) available on the Internet. Strictly speaking, we don't use full "end-to-end" encryption - in our case, on the server-end the encryption terminates at the Nginx server. We, perhaps cavalierly, assume that transfer between the host machine and a Docker container running on that host will be implicitly secure... The only way it could be compromised is if the VM itself is compromised, in which case, the Docker containers running on it could be, too. Avoiding having secure transfer between Nginx on the VM host and the various Docker containers also substantially simplifies setting up each application.</p> <p>Thanks to a service which Nginx provides SNI (or <a href="https://en.wikipedia.org/wiki/Server_Name_Indication">Server Name Indication</a>) - Apache and a few other web servers also provide this - which removes the historical limitation that meant you could only have one SSL certificate per IP address on a web server. The only downside of SNI is that some older browsers (and platforms) don't support it. Since those older technologies are rapidly dying out and it's quite expensive and difficult to have a single IP address for each SSL service on a server, we accept this compromise.</p> <h2>The Let's Encrypt Cert Process</h2> <p>Here's (roughly) how the process works:</p> <ol><li>Point your domain (via A or CNAME record) to point to the/an external IP address on your VM.</li> <li>Set up a domain (or domains) for non-secure hosting (on port 80) via your Nginx instance.</li> <li>The domain's configuration must include a special directory reserved for Let's Encrypt verification content.</li> <li>You request that certbot (on the VM) acquires a certificate for that domain (or domains) at which point <ol><li>the certbot writes a file with a hard-to-guess name to that special directory and requests that the Let's Encrypt infrastructure checks the domain name from outside</li> <li>Let's Encrypt checks that domain name and special directory to see that the expected number appears there, thus verifying that the requesting party actually has the ability to set content at this hard-to-guess filename, and therefore has legitimate claim to being the party controlling the domain name and server.</li> <li>Let's Encrypt registers the certificate request in the name of the party running the certbot (so it can, for example, send emails to the administrator warning them that the certificate needs to be renewed - which happens every 8 weeks or so), and</li> <li>Let's Encrypt sends verification back to your VM's certbot telling it to complete the certificate generation, which it then (digitally) signs in the name of the Let's Encrypt Certificate Authority (which, in turn, is recognised by almost all web browsers out-of-the-box - no mean feat, I can tell you).</li> </ol></li> <li>You get an alert telling you that you have created a valid SSL certificate.</li> <li>You alter your Nginx domain configuration to <ol><li>redirect connections to port 80 (un-encrypted) to port 443 (encrypted), and</li> <li>you set up the 443 configuration including your new certificates.</li> </ol></li> <li>You reload your Nginx configuration, and your site will now be end-to-end encrypted.</li> </ol><h2>The Let's Encrypt Snippet</h2> <p>To make it easy to include the relevant directory info, I recommend that you create a new file in your Nginx configuration (substitute your preferred text editor for "vim" in the following - "nano" is a good choice if you haven't already got a preference):</p> <p><code>sudo mkdir /etc/nginx/includes<br /> sudo vim /etc/nginx/includes/letsencrypt.conf</code></p> <p>and make sure it has the following content (note, I learned this thanks to <a href="https://community.letsencrypt.org/t/how-to-nginx-configuration-to-enable-acme-challenge-support-on-all-http-virtual-hosts/5622">someone else's howto</a> on the global Internet knowledge commons :))</p> <p><code># Rule for legitimate ACME Challenge requests<br /> location ^~ /.well-known/acme-challenge/ {<br />     default_type "text/plain";<br />     # this can be any directory, but this name keeps it clear<br />     root /var/www/letsencrypt;<br /> }</code></p> <p><code># Hide /acme-challenge subdirectory and return 404 on all requests.<br /> # It is somewhat more secure than letting Nginx return 403.<br /> # Ending slash is important!<br /> location = /.well-known/acme-challenge/ {<br />     return 404;<br /> }</code></p> <p>Next, make sure your directory exists (note - you only need to do this once per VM) - it shouldn't need an special permissions - it'll be written by the "root" user, and needs to be readable by the Nginx user, usually "www-data" on a Debian or Ubuntu Linux instance.</p> <p><code>mkdir /var/www/letsencrypt</code></p> <h2>Example Nginx Domain Configuration - unencrypted</h2> <p>Here's an example of a pre-cert Nginx domain configuration for example.org and <a href="http://www.example.org">www.example.org</a> (I usually name the configuration file after the main domain it concerns, so my file would be /etc/nginx/sites-available/example.org) - this should also let you do initial test of your app to make sure it works, before adding the additional complexity of SSL. (<em>Replace example.com (and <a href="http://www.example.com">www.example.com</a>) with your own domain!</em>):</p> <p><code>server {</code></p> <p><code>    listen 80; # this is one of our external IPs on the server.<br />     #listen   [::]:80 default ipv6only=on; ## listen for ipv6<br /><br />     # this root directory isn't really relevant in a proxy situation</code><br /><code>    # so I usually set it to the system default<br />     root /usr/share/nginx/www;<br />     index index.html index.htm;<br /><br />     server_name example.org www.example.org;<br /><br />     access_log /var/log/nginx/example.org_access.log;<br />     error_log /var/log/nginx/example.org_error.log;</code></p> <p><code>    # this is where we include the snippet<br />     include /etc/nginx/includes/letsencrypt.conf;</code></p> <p><code>    # this is just an example of a "proxy" configuration<br />     # for, say, a Docker-based service, exposed on the VM's<br />     # local port 8081<br />     location / {<br />         proxy_read_timeout      300;<br />         proxy_connect_timeout   300;<br />         proxy_redirect          off;<br />         proxy_set_header    Host                $http_host;<br />         proxy_set_header    X-Real-IP           $remote_addr;<br />         proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;<br />         proxy_set_header    X-Forwarded-Proto   $scheme;<br />         proxy_pass      http://127.0.0.1:8081;<br />     }</code><br /><code>}</code></p> <p>You can make sure that the configuration is visible to Nginx by adding it into the "sites-enabled" directory via a file link</p> <p><code>sudo ln -sf /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled </code></p> <p>Test things to make sure the new configuration doesn't have typos or bad references:</p> <p><code>sudo nginx -t</code></p> <p>and if not, make it live:</p> <p><code>sudo service nginx reload</code></p> <p>You should now be able to go to <a href="http://example.com">http://example.com</a> (or your domain) and you'll hopefully get your proxied application (if it's set up) or an Nginx error (see you nginx error file for more info!).</p> <p>Now it's time to request the certificate!</p> <h2>Example Certbot invocation</h2> <p>Once cerbot is installed, and a domain is configured, it's pretty straightforward to get a certificate.</p> <p>On the first invocation of certbot, you might get a coloured interface that requests your user details (e.g. name and email address) so that Let's Encrypt can register them for the purposes of future emails. They email if one of your certificates is on the verge of expiring, or if there's been a change to Let's Encrypt policy or process. It's worth being on the list. </p> <p>You can request your certificate with the following:</p> <p><code>sudo certbot certonly --webroot -w /var/www/letsencrypt -d example.org -d www.example.org</code></p> <p>If it works, it gratifyingly results in a message that starts with "Congratulations"!</p> <h2>Example Nginx Domain Configuration - unencrypted</h2> <p>Once you've got your certificate, you can reference it in your configuration. We normally set up a redirect from the unencrypted version of the site to the encrypted on (except for the Let's Encrypt verification directory!):</p> <p><code>server {<br />     listen 80; # listen on port 80 on all IPv4 addresses</code><br /><code>    listen [::]:80; # listen on port 80 on all IPv6 addresses</code><br /><code> <br />     root /var/www/html;<br />     index index.html index.htm;<br /><br />     server_name example.org www.example.org;<br /><br />     access_log /var/log/nginx/example.org_access.log;<br />     error_log /var/log/nginx/example.org_error.log;</code></p> <p><code>    include /etc/nginx/includes/letsencrypt.conf;</code></p> <p><code>    # a 302 is a "soft" redirect. A 301 can never be reversed.<br />     location / {<br />         return 302 https://chat.oeru.org$request_uri;<br />     }       <br /> }<br /><br /> server {</code><br /><span style="font-family:monospace"><span style="color:#000000;background-color:#ffffff;">    listen 443 ssl; # listen on port 443 on all IPv4 addresses</span></span><br /><span style="font-family:monospace"><span style="color:#000000;background-color:#ffffff;">    listen [::]:443 ssl; # listen on port 443 on all IPv6 addresses</span></span><br /><br /><code>    # this is a deprecated rule, not required in Ubuntu 20.04's nginx<br />     # ssl on; <br />     ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;<br />     ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;</code><br /><code>    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br />     ssl_dhparam /etc/ssl/certs/dhparam.pem;<br />     keepalive_timeout 20s;</code></p> <p><code>    access_log /var/log/nginx/example.org_access.log;<br />     error_log /var/log/nginx/example.org_error.log;</code></p> <p><code>    root /var/www/html;<br />     index index.html index.htm;</code><br /><br /><code>    server_name example.org www.example.org;<br />    <br />     # this is just an example of a "proxy" configuration<br />     # for, say, a Docker-based service, exposed on the VM's<br />     # local port 8081<br />     location / {<br />         proxy_read_timeout      300;<br />         proxy_connect_timeout   300;<br />         proxy_redirect          off;<br />         proxy_set_header    Host                $http_host;<br />         proxy_set_header    X-Real-IP           $remote_addr;<br />         proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;<br />         proxy_set_header    X-Forwarded-Proto   $scheme;<br />         proxy_pass      http://127.0.0.1:8081;<br />     }</code><br /><code>}</code></p> <p>Note - you also need to set up the <code>ssl_dhparam</code> file for this configuration to work. You can do this based on <a href="https://michael.lustfield.net/nginx/getting-a-perfect-ssl-labs-score" title="Setting hp ssl_dhparam">these instructions</a> after installing OpenSSL tools:</p> <p><code>sudo apt-get install openssl</code></p> <p>by running (warning - this can take quite a long time, 5-15 minutes in my experience - the system needs to generate sufficient <a href="https://en.wikipedia.org/wiki/Entropy">entropy</a> to achieve acceptable randomness):</p> <pre class="literal-block"> <code>openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096</code> </pre> <p>When you've set up the file, you can enable it:</p> <p><code>sudo ln -sf /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled</code></p> <p>Test the file to ensure there aren't any syntax errors before reloading nginx:</p> <p><code>sudo nginx -t</code></p> <p>If this shows an error, you'll need to fix the file. If all's well, reload nginx to enable the new configuration:</p> <p><code>sudo service nginx reload</code></p> <p>You should now be able to point your browser at your domain name, and it should automatically redirect you to <a href="https://example.org">https://example.org</a> - and (based on the above configuration, <a href="https://www.example.org">https://www.example.org</a> should work too. You might want to redirect <a href="http://www.example.org">www.example.org</a> to example.org or visa versa).</p> <p>A word to the wise - if it doesn't work, check your firewall settings!</p> <p><strong>Update:</strong> discovered this <a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04">very well done how-to</a> on Let's Encrypt that offers additional background to this one.</p> <h2>Ongoing Certificate Maintenance</h2> <p>One of the nice things about EFF's certbot is that when it's installed, it also installs a nightly cron task (see <code>/etc/cron.d/certbot</code>) which checks all domains registered on the server for renewals. Assuming your domains have been configured in Nginx as described above, renewals should occur automatically, and you'll just receive a periodic email to let you know that they've happened.</p> <p>If you want to check your renewal status, you can run this:</p> <pre> <code>sudo certbot renew --dry-run</code></pre> <p>Good on you for securing your users and your site!</p> </div> </div> </div> <section class="field field-node--field-blog-comments field-name-field-blog-comments field-type-comment field-label-above comment-wrapper"> <a name="comments"></a> <div class="comment-form-wrapper"> <h2 class="comment-form__title">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=11&amp;2=field_blog_comments&amp;3=comment" token="u_cC5Zw8SKo5_CwG7txdoRLRmx6G2xIvWYWTc95IdY0"></drupal-render-placeholder> </div> </section> Thu, 08 Jul 2021 02:23:06 +0000 dave 11 at http://tech.oeru.org Installing Rocket.Chat with Docker on Ubuntu Linux 14.04 http://tech.oeru.org/installing-rocketchat-docker-ubuntu-linux-1404 <span class="field field--name-title field--type-string field--label-hidden">Installing Rocket.Chat with Docker on Ubuntu Linux 14.04</span> <div class="field field-node--field-blog-tags field-name-field-blog-tags field-type-entity-reference field-label-above"> <h3 class="field__label">Blog tags</h3> <div class="field__items"> <div class="field__item field__item--install"> <span class="field__item-wrapper"><a href="/taxonomy/term/11" hreflang="en">install</a></span> </div> <div class="field__item field__item--ubuntu-linux"> <span class="field__item-wrapper"><a href="/taxonomy/term/12" hreflang="en">ubuntu linux</a></span> </div> <div class="field__item field__item--_404"> <span class="field__item-wrapper"><a href="/taxonomy/term/13" hreflang="en">14.04</a></span> </div> <div class="field__item field__item--docker"> <span class="field__item-wrapper"><a href="/taxonomy/term/16" hreflang="en">docker</a></span> </div> <div class="field__item field__item--rocketchat"> <span class="field__item-wrapper"><a href="/taxonomy/term/18" hreflang="en">rocket.chat</a></span> </div> <div class="field__item field__item--lets-encrypt"> <span class="field__item-wrapper"><a href="/taxonomy/term/17" hreflang="en">let&#039;s encrypt</a></span> </div> <div class="field__item field__item--mongodb"> <span class="field__item-wrapper"><a href="/taxonomy/term/14" hreflang="en">mongodb</a></span> </div> </div> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/1" lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Thu 24/11/2016 - 10:59</span> <div class="field field-node--field-image field-name-field-image field-type-image field-label-hidden has-multiple"> <figure class="field-type-image__figure image-count-1"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2016-11/RocketChat_0.png?itok=6K_Ym-ms" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The Rocket.Chat desktop app showing a typical conversation thread.&quot;}" role="button" title="The Rocket.Chat desktop app showing a typical conversation thread." data-colorbox-gallery="gallery-field_image-srzaqQCEwl0" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The Rocket.Chat desktop app showing a typical conversation thread.&quot;}"><img src="/sites/default/files/styles/medium/public/2016-11/RocketChat_0.png?itok=LfyOwZNW" width="220" height="168" alt="The Rocket.Chat desktop app showing a typical conversation thread." loading="lazy" typeof="foaf:Image" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-2"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2016-11/RocketChat2.png?itok=DkgkxTvj" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;A glimps of Rocket.Chat&#039;s adminisrative power and flexibility.&quot;}" role="button" title="A glimps of Rocket.Chat&#039;s adminisrative power and flexibility." data-colorbox-gallery="gallery-field_image-srzaqQCEwl0" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;A glimps of Rocket.Chat&#039;s adminisrative power and flexibility.&quot;}"><img src="/sites/default/files/styles/medium/public/2016-11/RocketChat2.png?itok=fT_PGRZH" width="220" height="169" alt="A glimps of Rocket.Chat&#039;s adminisrative power and flexibility." loading="lazy" typeof="foaf:Image" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-3"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2016-11/RocketChat3_0.png?itok=FDIRKt6_" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;An example of editing a post and other post-level tools.&quot;}" role="button" title="An example of editing a post and other post-level tools." data-colorbox-gallery="gallery-field_image-srzaqQCEwl0" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;An example of editing a post and other post-level tools.&quot;}"><img src="/sites/default/files/styles/medium/public/2016-11/RocketChat3_0.png?itok=9I8anoyq" width="220" height="169" alt="An example of editing a post and other post-level tools." loading="lazy" typeof="foaf:Image" class="image-style-medium" /> </a> </div> </figure> </div> <div class="clearfix text-formatted field field-node--body field-name-body field-type-text-with-summary field-label-hidden"> <div class="field__items"> <div class="field__item"><p><a href="http://rocket.chat" title="The ROcket.Chat main site">Rocket.Chat</a> is a modern, open source messaging application which is functionally similar to a popular (and heavily marketed) proprietary tool called Slack. Rocket.Chat is built on a powerful open source real-time collaboration platform called <a href="https://www.meteor.com/" title="Open source state-based collaborative app building framework, written in Javascript">Meteor</a> (which, in turn, is built on the <a href="https://nodejs.org">Node.JS</a> open source framework), which supports real-time collaborative applications. The real-time collaboration means that if multiple people are using an app at the same time, even if they're spread across the world, they'll see the changes others are making in real-time.</p> <p>The OERu <a href="https://chat.oeru.org">has a Rocket.Chat instance</a> that has been getting very positive feedback from our Open Education Resource designers and collaborators, who use it to communicate with us at the OER Foundation, and with their fellow collaborators. There are currently about 20 channels to which users can subscribe and in which they can participate, dedicated to different topics of discussion.</p> <p>Rocket.Chat instances store their data in another open source tool, a key-value storage engine called <a href="https://www.mongodb.com/">MongoDB</a> - these instructions assume that you have already got a running MongoDB installed, and to facilitate that, we've provided this <a href="/node/3">handy MongoDB install guide</a> as a companion.</p> <p>This guide will cover both configuring and launching a Docker container with a working instance of Rocket.Chat. It will, in turn, be linked to another Docker container running MongoDB, and both will be capable of sending email via external authenticating email server. External user access to Rocket.Chat is provided by the Nginx web server (as a forward proxy). User interaction with Rocket.Chat is (and should always be) encrypted via recognised SSL certificates using the brilliant (and gratis) <a href="http://letsencrypt.org">Let's Encrypt</a> service.</p> <p>This instruction set assumes that you have command-line access (via SSH, in most cases) to your server, running Ubuntu Linux 14.04, probably a Virtual Machine hosted in a data centre somewhere - a very inexpensive way to do this is, for example, via <a href="https://digitalocean.com">DigitalOcean</a> (for the record, we have no relationship with DigitalOcean, I simply have substantial experience with their services), but there are many many options worldwide. These instructions will need to be modified slightly for other versions of Linux (e.g. Debian 8 or Ubuntu 16.04 or CentOS or others), but should be mostly valid. We'd be grateful to hear about anyone else's experiences in the comments below!</p> <h2>Installing Docker</h2> <p>See our instructions in the <a href="/node/3">MongoDB blog post</a>.</p> <h2>Installing Rocket.Chat</h2> <p>First, we would normally create a rocketchat user to create a place for any persistent data required for the app:</p> <p><code>sudo adduser rocketchat</code></p> <p>Although Rocket.Chat stores almost everything in the MongoDB you've already set up, it can store uploaded files in a designated directory so they survive updates to the Docker image:</p> <p><code>sudo -u rocketchat mkdir /home/rocketchat/uploads</code></p> <p>Assuming you've got Docker installed properly, to install the official Rocket.Chat Docker image, you can just run:</p> <p><code>docker pull rocketchat/rocket.chat</code></p> <p>Then you can launch it by running this by first launching your MongoDB container, and then running this (assumes you've named your MongoDB instance "mongodb" as per our <a href="/node/3">instructions</a>):</p> <p><code>docker run -d --name rocketchat -p 8051:3000 \<br />          -h [your_RocketChat_domain] \<br />          -v /home/rocketchat/uploads:</code><code>/var/www/rocket.chat/uploads \<br />          -e "MAIL_URL=[outgoing_mail_server]" \<br />          --link mongodb:mongo -e "MONGO_URL=mongodb://mongo/chat" \<br />          -e "ROOT_URL=http://[your_RocketChat_domain]" \<br />          --restart unless-stopped rocketchat/rocket.chat</code></p> <p><strong>Note: Please copy and paste the exact text of your "docker run" command into a reference file (I usually have a "README.oeru" reference file in the home directory of each Docker-based app I run)  as you will want to refer to it when doing upgrades!</strong></p> <p>You'll need to make sure you set appropriate values for [your_RocketChat_domain] and details for an SMTP (outgoing mail) server, because Rocket.Chat needs to send emails related to things like account registration, forgotten passwords, and configurable notifications, for example to alert you that you've been mentioned in discussions.</p> <p>You can use either a local mail server on the Docker host, in which case you'd put the local IP address of your server, as it would be seen by the Docker container, so 172.17.42.1 is the default IP of a Docker host. You could also use an authenticating SMTP server, and specify the details like this: <code>smtp://[username]:[password]@[IP-or-domainname]:[port, usually 25, 465, or 587].</code> Here's a what a made-up example might look like:</p> <p><code>-e "MAIL_URL=smtp://smtpmail:blahdiblah88@mail.oeru.org:25"</code></p> <p>Note, the <code>--restart unless-stopped</code> will ensure that this container is restarted on a reboot unless it's explicitly stopped, like via a <code>docker stop rocketchat</code>, like you might to update the Docker container.</p> <h2>Setting up Nginx as a proxy server</h2> <p>Having set up the Docker container, which is listening on port 8051 on the Docker container's <em>host</em>, you'll need to set up a reverse proxy on that host to make the site visible to the broader internet on your public IP address (you'll want to make sure the domain you specified above points to that IP address or is a CNAME to a domain that does).</p> <p>Once you've got that, you can proceed. In /etc/nginx/sites-available, I create a file called plan (as we use plan.oeru.org as our domain). Note, I use "vim" as my text editor. If you don't know it, perhaps use "nano" instead. It's much less powerful, but easier to use...</p> <p><code>sudo vim /etc/nginx/sites-available/chat</code></p> <p>Here're the contents - you'll want to change the domain name to suit your own choices. Similarly the names of SSL files and logs. The following file has a chunk in the middle commented out with "#s". More on that below:</p> <p><code>server {</code></p> <p><code>        listen 80; # this is one of our external IPs on the server.<br />         #listen   [::]:80 default ipv6only=on; ## listen for ipv6<br /><br />         root /usr/share/nginx/www;<br />         index index.html index.htm;<br /><br />         server_name chat.oeru.org;<br /><br />         access_log /var/log/nginx/chat.oeru.org_access.log;<br />         error_log /var/log/nginx/chat.oeru.org_error.log;<br /><br />         location /.well-known {<br />                 root /var/www/html;<br />                 default_type text/plain;<br />         }<br /><br /> #        location / {<br /> #                return 301 https://chat.oeru.org$request_uri;<br /> #        }       <br /> #}<br /> #<br /> #server {<br /> #        listen 443 ssl;<br /> #        ssl on;<br /> #        ssl_certificate /etc/letsencrypt/live/chat.oeru.org/fullchain.pem;<br /> #        ssl_certificate_key /etc/letsencrypt/live/chat.oeru.org/privkey.pem;</code><br /><code># </code><code>       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br /> #        ssl_dhparam /etc/ssl/certs/dhparam.pem;<br /> #        keepalive_timeout 20s;<br /> #<br /> #        access_log /var/log/nginx/chat.oeru.org_access.log;<br /> #        error_log /var/log/nginx/chat.oeru.org_error.log;</code><br /><code>#        root /var/www/html;<br /> #        index index.html index.htm;</code><br /><code>#        server_name chat.oeru.org;<br /> #<br /> #        location /.well-known {<br /> #                root /var/www/html;<br /> #                default_type text/plain;<br /> #        }</code></p> <p><code>        location / {<br />                 proxy_read_timeout      300;<br />                 proxy_connect_timeout   300;<br />                 proxy_redirect          off;<br />                 proxy_set_header    Host                $http_host;<br />                 proxy_set_header    X-Real-IP           $remote_addr;<br />                 proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;<br />                 proxy_set_header    X-Forwarded-Proto   $scheme;<br />                 proxy_pass      http://127.0.0.1:8081;<br />         }</code><br /><code>}</code></p> <p>When you've set up the file, you can enable it:</p> <p><code>sudo ln -sf /etc/nginx/sites-available/chat /etc/nginx/sites-enabled</code></p> <p>Test the file to ensure there aren't any syntax errors before reloading nginx:</p> <p><code>sudo nginx -t</code></p> <p>If this shows an error, you'll need to fix the file. If all's well, reload nginx to include the new configuration:</p> <p><code>sudo service nginx reload</code></p> <p>You should now be able to point your browser at your domain name, and you should get your Rocket.Chat site via the HTTP (not encrypted) protocol.</p> <p>A word to the wise - if it doesn't work, check your firewall settings!</p> <p>In the next step, we'll sort out your SSL certificate from <a href="https://letsencrypt.org/" title="Let's Encrypt - libre and gratis SSL certificates">Let's Encrypt</a>.</p> <h2>Protecting your users</h2> <p>Have a look at our <a href="/protecting-your-users-lets-encrypt-ssl-certs">Let's Encrypt howto</a>.</p> <h2>Upgrading Rocket.Chat</h2> <p>You should periodically upgrade Rocket.Chat, say every couple months, to benefit from improved features... The upgrade process usually means a few minutes of down time for the site, so pick a time when it isn't likely to be heavily used... You'll normally want to upgrade any dependent Docker containers at the same time (like <a href="/node/3">your MongoDB</a> and <a href="/node/4">Wekan</a>) so we have a <a href="/node/6">dedicated Upgrade article</a> for that.</p> </div> </div> </div> <section class="field field-node--field-blog-comments field-name-field-blog-comments field-type-comment field-label-above comment-wrapper"> <a name="comments"></a> <div class="comment-form-wrapper"> <h2 class="comment-form__title">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=5&amp;2=field_blog_comments&amp;3=comment" token="y1jeKMWHoaChSEAGVwc5uZ-gT13uvOFBkFRfOSdeB9g"></drupal-render-placeholder> </div> </section> Wed, 23 Nov 2016 21:59:47 +0000 dave 5 at http://tech.oeru.org Installing Wekan with Docker on Ubuntu Linux 14.04 http://tech.oeru.org/installing-wekan-docker-ubuntu-linux-1404 <span class="field field--name-title field--type-string field--label-hidden">Installing Wekan with Docker on Ubuntu Linux 14.04</span> <div class="field field-node--field-blog-tags field-name-field-blog-tags field-type-entity-reference field-label-above"> <h3 class="field__label">Blog tags</h3> <div class="field__items"> <div class="field__item field__item--install"> <span class="field__item-wrapper"><a href="/taxonomy/term/11" hreflang="en">install</a></span> </div> <div class="field__item field__item--ubuntu-linux"> <span class="field__item-wrapper"><a href="/taxonomy/term/12" hreflang="en">ubuntu linux</a></span> </div> <div class="field__item field__item--_404"> <span class="field__item-wrapper"><a href="/taxonomy/term/13" hreflang="en">14.04</a></span> </div> <div class="field__item field__item--mongodb"> <span class="field__item-wrapper"><a href="/taxonomy/term/14" hreflang="en">mongodb</a></span> </div> <div class="field__item field__item--wekan"> <span class="field__item-wrapper"><a href="/taxonomy/term/15" hreflang="en">wekan</a></span> </div> <div class="field__item field__item--docker"> <span class="field__item-wrapper"><a href="/taxonomy/term/16" hreflang="en">docker</a></span> </div> <div class="field__item field__item--lets-encrypt"> <span class="field__item-wrapper"><a href="/taxonomy/term/17" hreflang="en">let&#039;s encrypt</a></span> </div> </div> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/1" lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Thu 27/10/2016 - 14:12</span> <div class="field field-node--field-image field-name-field-image field-type-image field-label-hidden has-multiple"> <figure class="field-type-image__figure image-count-1"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2016-11/Wekan.png?itok=DTYp9TJz" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;OERu&#039;s Wekan instance&quot;}" role="button" title="OERu&#039;s Wekan instance" data-colorbox-gallery="gallery-field_image-srzaqQCEwl0" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;OERu&#039;s Wekan instance&quot;}"><img src="/sites/default/files/styles/medium/public/2016-11/Wekan.png?itok=a6RIb_sO" width="220" height="112" alt="OERu&#039;s Wekan instance" loading="lazy" typeof="foaf:Image" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-2"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2016-11/Wekan2.png?itok=CFI0It_1" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Editing a task, setting participants and priorites&quot;}" role="button" title="Editing a task, setting participants and priorites" data-colorbox-gallery="gallery-field_image-srzaqQCEwl0" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Editing a task, setting participants and priorites&quot;}"><img src="/sites/default/files/styles/medium/public/2016-11/Wekan2.png?itok=IfrWQAmQ" width="220" height="113" alt="Editing a task, setting participants and priorites" loading="lazy" typeof="foaf:Image" class="image-style-medium" /> </a> </div> </figure> </div> <div class="clearfix text-formatted field field-node--body field-name-body field-type-text-with-summary field-label-hidden"> <div class="field__items"> <div class="field__item"><p><a href="https://wekan.org">Wekan</a> is an excellent, easy-to-use "kanban board" project management support tool, suitable for all manner of projects. For those who have used the highly marketed Trello kanban service, Wekan is functionally similar open source alternative that organisations can host and control for themselves. They can also enhance it in whatever ways they are moved to do so. We encourage our partner institutions to consider this path as a way of reducing costs as well as increasing freedom and privacy. To make migrating a win-win, we have also found that Wekan is able to import entire Trello boards, preserving your data. (Update: 2017-05-24 we've just published an <a href="/docker-compose-better-way-deploy-rocketchat-wekan-and-mongodb">easier way to run</a> Wekan and MongoDB)</p> <p>The OERu <a href="https://plan.oeru.org">provides a Wekan instance</a> that has proven very popular with our Open Education Resource designers and collaborators.</p> <p>Wekan instances store their data in another open source tool, a key-value storage engine called <a href="https://www.mongodb.com/">MongoDB</a> - these instructions assume that you have already got a running MongoDB installed, and to facilitate that, we've provided this <a href="/node/3">handy MongoDB install guide</a> as a companion.</p> <p>This guide will cover both configuring and launching a Docker container with a working instance of Wekan. It will, in turn, be linked to another Docker container running MongoDB, and both will be capable of sending email via external authenticating email server. External user access to Wekan is provided by the Nginx web server (as a forward proxy). User interaction with Wekan is (and should always be) encrypted via recognised SSL certificates using the brilliant (and gratis) <a href="http://letsencrypt.org">Let's Encrypt</a> service.</p> <p>This instruction set assumes that you have command-line access (via SSH, in most cases) to your server, running Ubuntu Linux 14.04, probably a Virtual Machine hosted in a data centre somewhere - a very inexpensive way to do this is, for example, via <a href="https://digitalocean.com">DigitalOcean</a> (for the record, we have no relationship with DigitalOcean, I simply have substantial experience with their services), but there are many many options worldwide. These instructions will need to be modified slightly for other versions of Linux (e.g. Debian 8 or Ubuntu 16.04 or CentOS or others), but should be mostly valid. We'd be grateful to hear about anyone else's experiences in the comments below!</p> <h2>Installing Docker</h2> <p>See our instructions in the <a href="/node/3">MongoDB blog post</a>.</p> <h2>Installing Wekan</h2> <p>First, we would normally create a wekan user:</p> <p><code>sudo adduser wekan</code></p> <p>and then create a directory in that user's space to store Wekan-related data (so it survives updates to the Docker image):</p> <p>sudo -u wekan mkdir /home/wekan/public</p> <p>Assuming you've got Docker installed properly, to install the official Wekan Docker image, you can just run:</p> <p><code>docker pull mquandalle/wekan</code></p> <p>Then you can launch it by running this by first launching your MongoDB container, and then running this (assumes you've named your MongoDB instance "mongodb" as per our <a href="/node/3">instructions</a>):</p> <p><code>docker run -d --name wekan -p 127.0.0.1:5555:80 \<br />          -h [your_Wekan_domain] -e "VIRTUAL_HOST=[your_Wekan_domain]" \<br />          -v /home/wekan/public:/built_app/programs/web.browser/app \<br />          -e "MAIL_URL=[outgoing_mail_server]" \<br />          --link mongodb:mongo -e "MONGO_URL=mongodb://mongo/plan" \<br />          -e "ROOT_URL=http://[your_Wekan_domain]" \<br />          --restart unless-stopped mquandalle/wekan</code></p> <p><strong>Note: Please copy and paste the exact text of your "docker run" command into a reference file (I usually have a "README.oeru" reference file in the home directory of each Docker-based app I run)  as you will want to refer to it when doing upgrades!</strong></p> <p>You'll need to make sure you set appropriate values for [your_Wekan_domain] and details for an SMTP (outgoing mail) server, because Wekan needs to send emails. You can use either a local mail server on the Docker host, in which case you'd put the local IP address of your server, as it would be seen by the Docker container, so 172.17.42.1 is the default IP of a Docker host. You could also use an authenticating SMTP server, and specify the details like this: <code>smtp://[username]:[password]@[IP-or-domainname]:[port, usually 25, 465, or 587].</code> Here's a what a made-up example might look like:</p> <p><code>-e "MAIL_URL=smtp://smtpmail:blahdiblah88@mail.oeru.org:25"</code></p> <p>Note, the <code>--restart unless-stopped</code> will ensure that this container is restarted on a reboot unless it's explicitly stopped, like via a <code>docker stop wekan</code>, like you might to update the Docker container.</p> <h2>Setting up Nginx as a proxy server</h2> <p>Having set up the Docker container, which is listening on port 5555 on the Docker container's <em>host</em>, you'll need to set up a reverse proxy on that host to make the site visible to the broader internet on your public IP address (you'll want to make sure the domain you specified above points to that IP address or is a CNAME to a domain that does).</p> <p>Once you've got that, you can proceed. In /etc/nginx/sites-available, I create a file called plan (as we use plan.oeru.org as our domain). Note, I use "vim" as my text editor. If you don't know it, perhaps use "nano" instead. It's much less powerful, but easier to use...</p> <p><code>sudo vim /etc/nginx/sites-available/plan</code></p> <p>Here're the contents - you'll want to change the domain name to suit your own choices. Similarly the names of SSL files and logs. The following file has a chunk in the middle commented out with "#s". More on that below:</p> <p><blockcode><code># from https://github.com/wekan/wekan/wiki/Install-Wekan-Docker-in-production<br /> upstream websocket {<br />         server 127.0.0.1:5555;<br /> }</code></blockcode></p> <p><blockcode><code>map $http_upgrade $connection_upgrade {<br />         default upgrade;<br />         '' close;<br /> }</code></blockcode></p> <p><blockcode><code>server {<br />         listen  80; # this is one of our external IPs on the server.<br />         #listen   [::]:80 default ipv6only=on; ## listen for ipv6<br /><br />         root /usr/share/nginx/www;<br />         index index.html index.htm;<br /><br />         server_name plan.oeru.org;<br /><br />         access_log /var/log/nginx/plan.oeru.org_access.log;<br />         error_log /var/log/nginx/plan.oeru.org_error.log;<br /><br />         location /.well-known {<br />                 root /var/www/html;<br />                 default_type text/plain;<br />         }<br /><br /> #        location / {<br /> #                return 301 https://plan.oeru.org$request_uri;<br /> #        }       <br /> #}<br /> #<br /> #server {<br /> #        listen 443 ssl;<br /> #        ssl on;<br /> #        ssl_certificate /etc/letsencrypt/live/plan.oeru.org/fullchain.pem;<br /> #        ssl_certificate_key /etc/letsencrypt/live/plan.oeru.org/privkey.pem;</code><br /><code># </code><code>       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br /> #        ssl_dhparam /etc/ssl/certs/dhparam.pem;<br /> #        keepalive_timeout 20s;<br /> #<br /> #        access_log /var/log/nginx/plan.oeru.org_access.log;<br /> #        error_log /var/log/nginx/plan.oeru.org_error.log;</code></blockcode><blockcode><br /><code>#        root /var/www/html;<br /> #        index index.html index.htm;</code></blockcode><blockcode><br /><code>#        server_name plan.oeru.org;<br /> #<br /> #        location /.well-known {<br /> #                root /var/www/html;<br /> #                default_type text/plain;<br /> #        }</code></blockcode></p> <p><blockcode><code>        location / {<br />                 proxy_read_timeout      300;<br />                 proxy_connect_timeout   300;<br />                 proxy_redirect          off;<br />                 proxy_set_header    X-Real-IP           $remote_addr;<br />                 proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;<br />                 proxy_set_header    X-Forwarded-Proto   $scheme;<br />                 proxy_pass      http://127.0.0.1:5555;<br />                 proxy_set_header Host           $host;<br />         }</code></blockcode></p> <p><blockcode><code>        location ~ websocket$ {<br />                 proxy_pass http://websocket;<br />                 proxy_http_version 1.1;<br />                 proxy_set_header Upgrade $http_upgrade;<br />                 proxy_set_header Connection $connection_upgrade;<br />         }<br /> }</code></blockcode></p> <p>When you've set up the file, you can enable it:</p> <p><code>sudo ln -sf /etc/nginx/sites-available/plan /etc/nginx/sites-enabled</code></p> <p>Test the file to ensure there aren't any syntax errors before reloading nginx:</p> <p><code>sudo nginx -t</code></p> <p>If this shows an error, you'll need to fix the file. If all's well, reload nginx to include the new configuration:</p> <p><code>sudo service nginx reload</code></p> <p>You should now be able to point your browser at your domain name, and you should get your Wekan site via the HTTP (not encrypted) protocol.</p> <p>A word to the wise - if it doesn't work, check your firewall settings!</p> <p>In the next step, we'll sort out your SSL certificate from <a href="https://letsencrypt.org/" title="Let's Encrypt - libre and gratis SSL certificates">Let's Encrypt</a>.</p> <h2>Protecting your users</h2> <p>Have a look at our <a href="/protecting-your-users-lets-encrypt-ssl-certs">Let's Encrypt howto</a>.</p> <h2>Upgrading Wekan</h2> <p>You should periodically upgrade Wekan, say every couple months, to benefit from improved features... The upgrade process usually means a few minutes of down time for the site, so pick a time when it isn't likely to be heavily used... You'll normally want to upgrade any dependent Docker containers at the same time (like <a href="/node/3">your MongoDB</a> and <a href="/node/5">Rocket.Chat</a>) so we have a <a href="/node/6">dedicated Upgrade article</a> for that.</p> <p> </p> </div> </div> </div> <section class="field field-node--field-blog-comments field-name-field-blog-comments field-type-comment field-label-above comment-wrapper"> <a name="comments"></a> <div class="comment-form-wrapper"> <h2 class="comment-form__title">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=4&amp;2=field_blog_comments&amp;3=comment" token="uc1Lb6EN7BABm6o1LG_bvkNtKR1zMSzFvkh2eSYvs90"></drupal-render-placeholder> </div> </section> Thu, 27 Oct 2016 01:12:48 +0000 dave 4 at http://tech.oeru.org Installing MongoDB with Docker on Ubuntu Linux 14.04 http://tech.oeru.org/installing-mongodb-docker-ubuntu-linux-1404 <span class="field field--name-title field--type-string field--label-hidden">Installing MongoDB with Docker on Ubuntu Linux 14.04</span> <div class="field field-node--field-blog-tags field-name-field-blog-tags field-type-entity-reference field-label-above"> <h3 class="field__label">Blog tags</h3> <div class="field__items"> <div class="field__item field__item--install"> <span class="field__item-wrapper"><a href="/taxonomy/term/11" hreflang="en">install</a></span> </div> <div class="field__item field__item--ubuntu-linux"> <span class="field__item-wrapper"><a href="/taxonomy/term/12" hreflang="en">ubuntu linux</a></span> </div> <div class="field__item field__item--_404"> <span class="field__item-wrapper"><a href="/taxonomy/term/13" hreflang="en">14.04</a></span> </div> <div class="field__item field__item--docker"> <span class="field__item-wrapper"><a href="/taxonomy/term/16" hreflang="en">docker</a></span> </div> <div class="field__item field__item--mongodb"> <span class="field__item-wrapper"><a href="/taxonomy/term/14" hreflang="en">mongodb</a></span> </div> </div> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/1" lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Thu 27/10/2016 - 14:06</span> <div class="clearfix text-formatted field field-node--body field-name-body field-type-text-with-summary field-label-hidden"> <div class="field__items"> <div class="field__item"><p>This post describes installing <a href="https://www.mongodb.com/">MongoDB</a> (and backing it up and restoring from backup) in a Docker container on an Ubuntu Linux 14.04 virtual machine. (Update: 2017-05-24 we've just published an <a href="/docker-compose-better-way-deploy-rocketchat-wekan-and-mongodb">easier way to run</a> MongoDB and Rocket.Chat and Wekan which depend on it)</p> <p>The motivation for installing MongoDB is that it is the key-value based data container engine used by two compelling web technologies, <a href="https://rocket.chat">Rocket.Chat</a> and <a href="http://wekan.org">Wekan</a>, that the OER Foundation has deployed for the OERu as <a href="https://chat.oeru.org">https://chat.oeru.org</a> and <a href="https://plan.oeru.org">https://plan.oeru.org.</a></p> <h2>Installing Docker</h2> <p>Rather than trying to write a comprehensive guide to installing Docker, I'll instead recommend that you have a look at <a href="https://docs.docker.com/engine/installation/linux/ubuntulinux/">this one</a> provided by the Docker community. It also covers installing on other versions of Ubuntu which might be helpful for some. Once you've got a working Docker container install going on your server, you can continue to the next step...</p> <p>Note: the idea with Docker is that <em>nothing important is stored <strong>in</strong> the container itself. </em>That means that you can blow it away at any time without losing any important data. You can do that to quickly upgrade it, or to change its properties. You simply re-launch the container making sure it points properly to the persistent stuff you want it to use.</p> <h2>Installing MongoDB</h2> <p>Once you've got Docker working on your virtual machine, getting the MongoDB docker container (where it's preinstalled and ready to go) is simple:</p> <p><code>docker pull mongo</code></p> <p>This will install the latest version of the MongoDB container from docker.io.</p> <h2>Launching MongoDB</h2> <p>I recommend setting up a per-container user to help keep things well segmented. You can create a "mongo" user:</p> <p><code>sudo adduser mongo</code></p> <p>This creates a directory /home/mongo and that's where we'll get the Mongo container to store the data we want to keep persistent.</p> <p>We can create "data" and "backups" directories in which it should store its data and save its backups respectively:</p> <p><code>sudo mkdir /home/mongo/data<br /> sudo mkdir /home/mongo/backup</code>s</p> <p>Then you can launch the container:</p> <p><code>docker run --name mongodb --restart unless-stopped \<br /> -v /home/mongo/data:/data/db -v /home/mongo/backups:/backups -d mongo --smallfiles</code></p> <p>You should be able to check it's running by typing</p> <p><code>docker ps</code></p> <p>and looking for the reference to "mongodb" (that's the "name" we've assigned to this instance of the "mongo" container).</p> <p>You can even log into the container and poke around the filesystem if you like, using the container's "id":</p> <p><code>ID=`docker ps | grep mongo | cut --characters=1-12`<br /> docker exec -it $ID bash</code></p> <p>which will drop you at the command line in the container. You can exit with "exit" or CTRL-D.</p> <p>If things go wrong, you can run this:</p> <p><code>ID=`docker ps | grep mongo | cut --characters=1-12`<br /> docker inspect $ID | grep log </code></p> <p>Which will give you a result like this (your filenames will be different):</p> <p><code>"LogPath": "/var/lib/docker/containers/539072b8fb976b5048bd13e90074ea4b43166b81c3d69d1720b4746785f7d917/539072b8fb976b5048bd13e90074ea4b43166b81c3d69d1720b4746785f7d917-json.log",</code></p> <p>In which case, you can look at the log file to see what's gone wrong:</p> <p><code>less +G /var/lib/docker/containers/539072b8fb976b5048bd13e90074ea4b43166b81c3d69d1720b4746785f7d917/539072b8fb976b5048bd13e90074ea4b43166b81c3d69d1720b4746785f7d917-json.log</code><br /><br /> You can exit less by hitting "q" or CTRL-C.</p> <h2>Backing up MongoDB</h2> <p>Backing up MongoDB requires a somewhat circuitous process. Here's what I do (after quite a bit of head scratching and web searching - Note: these backups are not directly related to the "backups" directory created above. More on that in the script below.):</p> <p>On the host VM, I create a directory for backups - I use /home/backup</p> <p><code>sudo mkdir /home/backup</code></p> <p>and I create a bin directory in /home/mongo</p> <p><code>sudo mkdir /home/mongo/bin</code></p> <p>and I create a script file with my preferred editor (I use vim, you could use nano instead if vim scares you):</p> <p><code>sudo vim /home/mongo/bin/mongo_backup.sh</code></p> <p>In it, I put the following:</p> <p><blockcode>#!/bin/bash<br /> #<br /> # backup all the mongo DBs hosted on this server, in a docker container<br /> #<br /> # useful reference: <a href="https://docs.mongodb.org/manual/core/backups/">https://docs.mongodb.org/manual/core/backups/</a><br /> #<br /> # in event of a disaster, this could be useful:<br /> # <a href="https://docs.mongodb.org/manual/tutorial/recover-data-following-unexpected-shutdown/">https://docs.mongodb.org/manual/tutorial/recover-data-following-unexpec…</a><br /> #<br /> # script copyright <a href="mailto:dave@davelane.nz">dave@davelane.nz</a> - available under terms of GPL v2 or later,<br /> # see <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">https://www.gnu.org/licenses/old-licenses/gpl-2.0.html</a><br /> #<br /> # Note: I've commented out some "echo" statements below that might be useful if you're<br /> # debugging this script...<br /> DATE=`date '+%Y%m%d-%H%M%S'`<br /> # this is the local backup directory - gets cleared out after every backup...<br /> DIR=/home/mongo/backups<br /> # the archive dir, with a past archive as well.<br /> ARCHDIR=/home/backup/mongodb<br /> PREV=$ARCHDIR/previous<br /> LATEST=$ARCHDIR/latest<br /> #<br /> # this is the backup directory on the Docker host<br /> DDIR=/backups</blockcode><blockcode><br /> # 1. get mongo container (this assumes only one running on the machine, with "mongo" in is name!)<br /> ID=`docker ps | grep "mongo" | cut -c 1-12`<br /> ##echo "working with ID = $ID"<br /> #<br /> # 2. back up databases<br /> # 2.1 backup to the local $DDIR on the Docker host<br /> MSG=`docker exec -i $ID mongodump --quiet --out $DDIR`<br /> ##echo $MSG<br /> # go into local backup dir<br /> CWD=`pwd`<br /> cd $DIR<br /> # 2.2. get list of backup databases<br /> DBS=`find $DIR -mindepth 1 -maxdepth 1 -type d -exec basename {} \;`<br /> for DB in $DBS<br /> do<br />     ARCH="${DB}.tgz"<br />     if [ -f $PREV/$ARCH ] ; then<br />         ##echo "explicitly jettison old backup of $PREV/$ARCH"<br />         rm $PREV/$ARCH<br />     else<br />         echo "***no previous version of $ARCH in $PREV on $DATE"<br />     fi<br />     if [ -f $LATEST/$ARCH ] ; then<br />         ##echo "move previous $LATEST/$ARCH into $PREV (overwritting old)"<br />     mv $LATEST/$ARCH $PREV/$ARCH<br />     else<br />         echo "***no latest backup $ARCH in $LATEST on $DATE"<br />     fi<br />     ##echo "archiving contents of $DB into $LATEST/$ARCH"<br />     tar cvfz $LATEST/$ARCH $DB<br />     #echo "removing $DB *.json and *.bson and the dir"<br />     rm -f $DB/*.bson $DB/*.json<br />     rmdir $DB<br /> done<br /> # return to where we started<br /> cd $CWD<br /> # exit with a happy 0, which shows we were successful!<br /> exit 0</blockcode></p> <p>Save that file, and then run this to fix the ownership of the file and make the script executable:</p> <p><code>sudo chown -R mongo:mongo /home/mongo/*<br /> sudo chmod a+x /home/mongo/bin/mongo_backup.sh</code></p> <p>You can try running the script to make sure it creates a backup of your mongo database (such as it is! There might not be much there yet, if you haven't got any apps installed that use MongoDB - you can wait until after that before testing. If you run it twice, you should see both a "latest" and "previous" backup directory containing suitably dated directories - this provides extra data security):</p> <p><code>sudo /home/mongo/bin/mongo_backup.sh</code></p> <p>Once you're happy that's working, set up a cron job to make it run daily... Again, edit a file with your preferred text editor:</p> <p><code>sudo vim /etc/cron.d/mongodb-backup</code></p> <p>and fill it with the following (replacing [an email that will get to you!] appropriately):<blockcode></blockcode></p> <p><blockcode>#<br /> # cron.d/mongodb-backup -- backups up the Mongo DBs running in a docker container<br /> #<br /> #<br /> MAILTO=[and email that will get to you!]</blockcode><br /><blockcode># run daily at 12:17pm as the root user<br /> 17 12 * * *  root  /home/mongo/bin/mongo_backup.sh</blockcode></p> <h2>Recovering a MongoDB database</h2> <p>In the event that you ever have to recover or transfer a MongoDB database, aka container, you can do so like this (sort of the reverse of the backup script):</p> <p>work out the name of the container you want to restore and copy the backup of the database directory (e.g. rocketchat or wekan) into /home/mongo/backups - to be clear: for MongoDB, a "database" is represented as a directory of files holding all the relevant data.</p> <p>Then log into Docker instance:</p> <p><code>ID=`docker ps | grep mongo | cut --characters=1-12`<br /> docker exec -it $ID bash</code></p> <p>and on <em>the Docker container's command line</em> run this, replacing the [names] appropriately below. Note, you might want to change the database name from the backup's original to a new name, so they don't need to be the same (but they can be):</p> <p><code>mongorestore --db [recovered DB Name] --drop /backups/[backed up DB Name]/</code></p> <h2>Upgrading MongoDB</h2> <p>Note, if you have other apps in other containers that depend on MongoDB, it's usually most convenient to upgrade them all at the same time. Look at our instructions for, for example, <a href="/node/4">running Wekan</a>, to see how to upgrade MongoDB.</p> </div> </div> </div> <section class="field field-node--field-blog-comments field-name-field-blog-comments field-type-comment field-label-above comment-wrapper"> <a name="comments"></a> <h2 class="comment-field__title">Blog comments</h2> <article data-comment-user-id="0" id="comment-808" about="/comment/808" typeof="schema:Comment" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 property="schema:name" datatype="" class="comment__title"> <a href="/comment/808#comment-808" class="permalink" rel="bookmark" hreflang="en">Really helpful post - thx I…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1626295748"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span rel="schema:author"><span lang="" typeof="schema:Person" property="schema:name" datatype="">Keith W (not verified)</span></span> </span> <span class="comment__pubdate">Thu 15/07/2021 - 08:48 <span property="schema:dateCreated" content="2021-07-14T20:48:05+00:00" class="rdf-meta hidden"></span> </span> </div> </div> <div class="comment__content"> <div property="schema:text" class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div property="schema:text" class="field__item"><p>Really helpful post - thx</p> <p>I had to remove the --smallfiles from the command to start the docker/mongo container</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=808&amp;1=default&amp;2=en&amp;3=" token="Sh_mgCZYbrsaXx1CurCBCrXOI0AlzIl15Wz7WrNX1Rg"></drupal-render-placeholder> </div> </div> </article> <div class="comment-form-wrapper"> <h2 class="comment-form__title">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=3&amp;2=field_blog_comments&amp;3=comment" token="sakYYvZOls5kfGBdE8P9OqUsJ8weSKuhrRjDRw2dR04"></drupal-render-placeholder> </div> </section> Thu, 27 Oct 2016 01:06:55 +0000 dave 3 at http://tech.oeru.org