onlyoffice http://tech.oeru.org/ en Install NextCloud Hub and OnlyOffice on Ubuntu 22.04 with Docker Compose http://tech.oeru.org/install-nextcloud-hub-and-onlyoffice-ubuntu-2204-docker-compose <span class="field field--name-title field--type-string field--label-hidden">Install NextCloud Hub and OnlyOffice on Ubuntu 22.04 with Docker Compose</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--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--mariadb"> <span class="field__item-wrapper"><a href="/taxonomy/term/48" hreflang="en">mariadb</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--docker-compose"> <span class="field__item-wrapper"><a href="/taxonomy/term/49" hreflang="en">docker-compose</a></span> </div> <div class="field__item field__item--nextcloud"> <span class="field__item-wrapper"><a href="/taxonomy/term/51" hreflang="en">nextcloud</a></span> </div> <div class="field__item field__item--onlyoffice"> <span class="field__item-wrapper"><a href="/taxonomy/term/69" hreflang="en">onlyoffice</a></span> </div> <div class="field__item field__item--nginx"> <span class="field__item-wrapper"><a href="/taxonomy/term/30" hreflang="en">nginx</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--redis"> <span class="field__item-wrapper"><a href="/taxonomy/term/21" hreflang="en">redis</a></span> </div> <div class="field__item field__item--productivity"> <span class="field__item-wrapper"><a href="/taxonomy/term/52" hreflang="en">productivity</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" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Mon 29/05/2023 - 11:50</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/2023-06/Screenshot%202023-05-31%20at%2016-23-11%20Dashboard%20-%20FOSSDLE%20NextCloud.png?itok=f5dB1mPK" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The user &#039;dashboard&#039; view of NextCloud with user-specific content designed to indicate recent, timely, or important content for the user looking at it. &quot;}" role="button" title="The user &#039;dashboard&#039; view of NextCloud with user-specific content designed to indicate recent, timely, or important content for the user looking at it. " data-colorbox-gallery="gallery-field_image-6QjKsnuVoeQ" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The user &#039;dashboard&#039; view of NextCloud with user-specific content designed to indicate recent, timely, or important content for the user looking at it. &quot;}"><img src="/sites/default/files/styles/medium/public/2023-06/Screenshot%202023-05-31%20at%2016-23-11%20Dashboard%20-%20FOSSDLE%20NextCloud.png?itok=lBbW70zi" width="220" height="182" alt="The user &#039;dashboard&#039; view of NextCloud with user-specific content designed to indicate recent, timely, or important content for the user looking at it. " loading="lazy" 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/2023-06/Screenshot%202023-05-31%20at%2016-21-55%20ONLYOFFICE%20Docs%20Community%20Edition.png?itok=CsEu3-io" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Default page for the OnlyOffice service, providing the commands to create the &#039;secret&#039; key required for external services wanting to integrate with it, like our NextCloud instance. &quot;}" role="button" title="Default page for the OnlyOffice service, providing the commands to create the &#039;secret&#039; key required for external services wanting to integrate with it, like our NextCloud instance. " data-colorbox-gallery="gallery-field_image-6QjKsnuVoeQ" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Default page for the OnlyOffice service, providing the commands to create the &#039;secret&#039; key required for external services wanting to integrate with it, like our NextCloud instance. &quot;}"><img src="/sites/default/files/styles/medium/public/2023-06/Screenshot%202023-05-31%20at%2016-21-55%20ONLYOFFICE%20Docs%20Community%20Edition.png?itok=sWLT0Lju" width="164" height="220" alt="Default page for the OnlyOffice service, providing the commands to create the &#039;secret&#039; key required for external services wanting to integrate with it, like our NextCloud instance. " loading="lazy" 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/2023-06/Screenshot%202023-05-31%20at%2016-30-39%20ONLYOFFICE%20-%20Administration%20settings%20-%20FOSSDLE%20NextCloud.png?itok=xGW97X5D" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;NextCloud&#039;s admin settings page, only visible to users with &#039;admin&#039; privileges. &quot;}" role="button" title="NextCloud&#039;s admin settings page, only visible to users with &#039;admin&#039; privileges. " data-colorbox-gallery="gallery-field_image-6QjKsnuVoeQ" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;NextCloud&#039;s admin settings page, only visible to users with &#039;admin&#039; privileges. &quot;}"><img src="/sites/default/files/styles/medium/public/2023-06/Screenshot%202023-05-31%20at%2016-30-39%20ONLYOFFICE%20-%20Administration%20settings%20-%20FOSSDLE%20NextCloud.png?itok=F6Bvm1Lb" width="146" height="220" alt="NextCloud&#039;s admin settings page, only visible to users with &#039;admin&#039; privileges. " loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-4"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2023-06/Screenshot%202023-05-31%20at%2016-29-48%20ONLYOFFICE%20-%20Administration%20settings%20-%20FOSSDLE%20NextCloud.png?itok=bV7eXn4L" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The OnlyOffice configuration page, into which we put the URL of our OnlyOffice service, and our secret key. &quot;}" role="button" title="The OnlyOffice configuration page, into which we put the URL of our OnlyOffice service, and our secret key. " data-colorbox-gallery="gallery-field_image-6QjKsnuVoeQ" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The OnlyOffice configuration page, into which we put the URL of our OnlyOffice service, and our secret key. &quot;}"><img src="/sites/default/files/styles/medium/public/2023-06/Screenshot%202023-05-31%20at%2016-29-48%20ONLYOFFICE%20-%20Administration%20settings%20-%20FOSSDLE%20NextCloud.png?itok=RnF69S-5" width="220" height="182" alt="The OnlyOffice configuration page, into which we put the URL of our OnlyOffice service, and our secret key. " loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-5"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2023-06/Screenshot%202023-05-31%20at%2016-28-04%205763-Article%20Text-37303-1-18-20211004-cgoode%20dlane-edit.docx%20-%20OERu%20NextCloud.png?itok=BwJ_Rg2W" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;A complex document being collaboratively edited (with track-changes turned on) on OnlyOffice. This was a peer reviewed journal article we wrote about using Free and Open Source Software tools for learners&#039; benefit. &quot;}" role="button" title="A complex document being collaboratively edited (with track-changes turned on) on OnlyOffice. This was a peer reviewed journal article we wrote about using Free and Open Source Software tools for learners&#039; benefit. " data-colorbox-gallery="gallery-field_image-6QjKsnuVoeQ" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;A complex document being collaboratively edited (with track-changes turned on) on OnlyOffice. This was a peer reviewed journal article we wrote about using Free and Open Source Software tools for learners&#039; benefit. &quot;}"><img src="/sites/default/files/styles/medium/public/2023-06/Screenshot%202023-05-31%20at%2016-28-04%205763-Article%20Text-37303-1-18-20211004-cgoode%20dlane-edit.docx%20-%20OERu%20NextCloud.png?itok=XBn0matl" width="220" height="182" alt="A complex document being collaboratively edited (with track-changes turned on) on OnlyOffice. This was a peer reviewed journal article we wrote about using Free and Open Source Software tools for learners&#039; benefit. " loading="lazy" 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>This is another update of my previous posts (installing <a href="/node/17">NextCloud with Collabora Office Online on Ubuntu 16.04</a> and then <a href="/node/29">NextCloud with OnlyOffice on Ubuntu 18.04</a>). I'm updating it thanks to my colleague in edtech, Stephen Downes' heroic videos showing how he went through this process using my 18.04 instructions on 22.04, running into a few minor issues... this update seeks to remedy the problems he encountered with the older tutorial. Remember, all these Free and Open Source Software projects are progressing and improving relentlessly, which means the they way they behaved a few years ago is not likely to be <em>exactly</em> the way they behave now. In particular, <a href="https://nextcloud.com">NextCloud</a> is leaping from strength to strength, benefiting from the <a href="https://nextcloud.com/blog/european-governments-work-with-nextcloud-to-build-digitally-sovereign-office/">well-founded concern held by many in the EU</a> about data sovereignty and the market domination (and exploitation) of US-based multinationals like Amazon, Google, Microsoft, Dropbox, and others.</p> <p>There're a few productivity packages that can be used in conjunction with NextCloud to provide comparable functionality to, for example, GoogleDocs + GoogleDrive or Microsoft Office 365 + Microsoft OneDrive, including Collabora Office (which we've used in the past). But the best companion productivity suite for NextCloud, in my opinion, is <a href="https://onlyoffice.com">OnlyOffice</a>. The application itself (for the tech focused reader, they've built an entirely <a href="https://github.com/ONLYOFFICE/">new application ecosystem</a> primarily using modern Javascript frameworks) is impressive in both capabilities and polish. The only real caveat I've come across is that it uses, by default, the <a href="https://openstandards.nz/case-study-microsofts-ooxml-standard">'fauxpen' standard formats</a> developed by Microsoft rather than the true open standard formats of <a href="https://en.wikipedia.org/wiki/OpenDocument">OpenDocumentFormat</a>. But in a world where, sadly, most people don't even know what a file format is, any software that doesn't read and write the incumbent monopolist's format with great fidelity is dead in the water. On that count, OnlyOffice is impressive. NextCloud + OnlyOffice - even better together (<em>without</em> a single US multinational tech giant involved. NextCloud development is led from Germany, OnlyOffice's development is led by a team in <a href="https://www.onlyoffice.com/about.aspx">Latvia</a>)!</p> <p>The beauty of the open source software model is that we can connect complementary applications, like NextCloud and OnlyOffice - developed by completely separate communities - to create a tightly integrated, highly functional, diverse computing platform. This combination, along with a bunch of other NextCloud "apps", is the equal of something like Google Apps (which includes Google Docs and Google Drive), but is under your control, not Google's. To me, that's a crucial difference.</p> <p>With the release of NextCloud 26.0 (current as of this writing), NextCloud has the option of installing <a href="https://nextcloud.com/office/">NextCloud Office</a> (which is just a bundled OnlyOffice installation) alongside it, creating something called "NextCloud Hub". It's pretty impressive, but I've found that managing the OnlyOffice install is problematic and somewhat inflexible, so I've opted to stay with having an independent (rather than bundled) OnlyOffice instance, but it's on the same server but managed as a different service. That's what we'll be setting up here!</p> <ul class="table-of-contents"><li> <p><a href="#tips-for-this-tutorial">Tips for this tutorial</a></p> </li> <li> <p><a href="#create-a-virtual-private-server">Create a Virtual Private Server</a></p> <ul><li> <p><a href="#vps-properties">VPS Properties:</a></p> </li> </ul></li> <li> <p><a href="#key-variables-for-you-nextcloud-and-onlyoffice-instances">Key variables for you NextCloud and OnlyOffice instances</a></p> <ul><li> <p><a href="#get-your-domain-lined-up">Get your Domain lined up</a></p> </li> </ul></li> <li> <p><a href="#editing-files">Editing files</a></p> <ul><li> <p><a href="#set-up-an-unprivileged-user-for-yourself">Set up an unprivileged user for yourself</a></p> </li> </ul></li> <li> <p><a href="#configure-the-vps">Configure the VPS</a></p> <ul><li> <p><a href="#configuring-your-firewall">Configuring your firewall</a></p> </li> <li> <p><a href="#install-the-nginx">Install the Nginx</a></p> </li> </ul></li> <li> <p><a href="#outgoing-vps-email-optional">Outgoing VPS Email (optional)</a></p> </li> <li> <p><a href="#installing-docker-compose-and-lets-encrypt">Installing Docker Compose and Let's Encrypt</a></p> </li> <li> <p><a href="#installing-mariadb">Installing MariaDB</a></p> </li> <li> <p><a href="#configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice">Configuring Nginx reverse proxy for NextCloud and OnlyOffice</a></p> </li> <li> <p><a href="#lets-encrypt-setup">Let's Encrypt setup</a></p> <ul><li> <p><a href="#nextcloud-proxy-configuration">NextCloud Proxy Configuration</a></p> </li> <li> <p><a href="#onlyoffice-proxy-configuration">OnlyOffice Proxy Configuration</a></p> </li> <li> <p><a href="#requesting-lets-encrypt-certificates">Requesting Let's Encrypt certificates</a></p> </li> </ul></li> <li> <p><a href="#prepare-your-docker-compose-host">Prepare your Docker Compose host</a></p> </li> <li> <p><a href="#nextcloud-install">NextCloud Install</a></p> <ul><li> <p><a href="#install-the-nextcloud-docker-recipe">Install the NextCloud Docker recipe</a></p> </li> <li> <p><a href="#the-nextcloud-nginx-configuration">The NextCloud Nginx configuration</a></p> </li> <li> <p><a href="#the-onlyoffice-docker-configuration">The OnlyOffice Docker configuration</a></p> </li> </ul></li> <li> <p><a href="#firing-up-your-nextcloud">Firing up your NextCloud!</a></p> <ul><li> <p><a href="#the-nextcloud-source-code-if-necessary">The NextCloud source code (if necessary)</a></p> </li> </ul></li> <li> <p><a href="#configuring-database-access">Configuring database access</a></p> </li> <li> <p><a href="#configuring-the-admin-user">Configuring the Admin user</a></p> </li> <li> <p><a href="#configuring-outgoing-email">Configuring Outgoing Email</a></p> </li> <li> <p><a href="#setting-up-onlyoffice">Setting up OnlyOffice</a></p> </li> <li> <p><a href="#configuring-onlyoffice-integration-with-nextcloud">Configuring OnlyOffice Integration with NextCloud</a></p> </li> <li> <p><a href="#keeping-the-whole-thing-up-to-date">Keeping the whole thing up-to-date</a></p> </li> <li> <p><a href="#backing-up-nextcloud">Backing up NextCloud</a></p> </li> <li> <p><a href="#backup-onlyoffice">Backup OnlyOffice</a></p> </li> </ul><h2><a id="user-content-tips-for-this-tutorial" href="#tips-for-this-tutorial" name="tips-for-this-tutorial" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Tips for this tutorial</h2> <p>This tutorial is aimed at adventuresome would-be system administrators. I endeavour not to assume any specialised knowledge on your part, and try to provide useful tips and exposition along the way to help you build a valid mental model of what you're doing. At the same, this is not a trivial process. Luckily, if you try it out, and decide not to follow through, so long as you <em>delete your VPS</em>, you should not be out-of-pocket by more than a few cents.</p> <p>If this is your first attempt at 'self-hosting', and you <em>do</em> follow through, this could be the start of a new era in your technical status - you could realised that self-hosting 'agency' you always wanted. People with that skill set are in hot demand among most organisations, especially in the NGO/charitable spaces. Plus, I'll be very impressed by your <a href="https://www.merriam-webster.com/dictionary/moxie">moxie</a>!</p> <p>With this tutorial, I'm assuming you've got a computer with an Internet connection, that can run SSH (all modern systems should do that) and you can copy-and-paste stuff from this tutorial (in your browser) into either a terminal window (in which you're SSH'd into your VPS) or into a text editor. Note, if you find it difficult to paste into a terminal window, try using CTRL+SHIFT+V (CTRL+V is already used as a short-cut for something else in UNIX terminals since long before the Windows world started using CTRL+C and CTRL+V).</p> <p>When I provide files you need to copy, look for the placeholders with values you need to substitute (search-and-replace) in square brackets - [] - with your own values. I assume you'll be able to do that in a text editor on your desktop.</p> <h2><a id="user-content-create-a-virtual-private-server" href="#create-a-virtual-private-server" name="create-a-virtual-private-server" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Create a Virtual Private Server</h2> <p>The first step is to create a place to host the NextCloud and OnlyOffice instances. You can run them on a local piece of hardware of sufficient capacity, but make sure you've got a <em>fast</em> and symmetrical (as fast to upload as to download!) connection. If (as with most residential Internet services) your upload is much slower than your download (often 1:10 ratio) your server is going to be very slow for external people, especially if streaming video. Also, don't undertake this unless you have a flat-rate data connection.</p> <p>The more cost-effective approach in our experience, is to secure a low cost commodity Linux Virtual Private Server running Ubuntu Linux 22.04 (the latest "Long Term Support" version). That's what we'll assume you're running for this tutorial. We have used quite a few Linux VPSs commodity providers. Known good options are Digital Ocean (who recently raised their prices significantly), Linode, Vultr, Hetzner, and TurnkeyLinux. There are many (hundreds) of other credible options. We recommend you find one hosted in the network epicentre (which isn't necessarily the same as the 'geographic' epicentre) of your audience. For the record, we've just shifted our hosting to Hetzner as they've got the benefit of not being US-owned (They're German, and therefore don't expose us to the egregiously over-reaching US <a href="https://en.wikipedia.org/wiki/CLOUD_Act">Cloud</a> and <a href="https://proprivacy.com/guides/what-is-the-partiot-act">Patriot</a> Acts) and their pricing is pretty unbeatable.</p> <p>If you have trouble getting a VPS, you might find <a href="https://vimeo.com/684028258">this video</a> I created for provisioning a VPS, using Digital Ocean as an example. In my experience, the process for provisioning VPSs on other platforms is very similar. You'll find this process <em>much</em> easier than using either Microsoft Azure or Amazon AWS, which we do not recommend. Their systems are unnecessarily complex, proprietary (they will lock you in), and 10-20 times more expensive than commodity hosting options already listed.</p> <h3><a id="user-content-vps-properties" href="#vps-properties" name="vps-properties" class="heading-permalink" aria-hidden="true" title="Permalink"></a>VPS Properties:</h3> <p>We recommend that, for a NextCloud instance of modest size (say up to 50 users) you provision a VPS with the following spec. You should be able to upgrade those specs in realtime if required, except for your disk space. You can, however, provision a secondary storage space (you can start small and increase it as you need to). I will cover setting this up, as it'll make your life far far easier in the medium-long term.</p> <ul><li>4-8 GB RAM</li> <li>2-4 Virtual CPUs</li> <li>80-160 GB Disk space (NVME disk is faster than SSD which is faster than spinning disk space)</li> <li>running Ubuntu Linux 22.04 (the current Long Term Support version)</li> <li>extra storage - 20-40GB extra space (can be expanded on fairly short notice)</li> </ul><p>You'll need to create an account for yourself on your chosen hosting provider (it's a good idea to use Two Factor Authentication, aka 2FA, on your hosting account so that no one can log in as you and, say, delete your server unexpectedly - you'll find instructions on how to set up 2FA on your hosting provider's site) and create an Ubuntu @2.04 (or the most recent 'Long Term Support' (LTS) version) - 24.04 is likely to come out in April 2024) in the 'zone' nearest to you (or your primary audience, if that's different).</p> <p>If you don't already have an SSH key on your computer, I encourage you to <a href="https://helpdeskgeek.com/how-to/how-to-generate-ssh-keys-on-windows-mac-and-linux/">create one</a> and specify the <strong>public key</strong> in the process of creating your server - specifying the 'public key' of your SSH identity during the server creation process that should allow you to log in without needing a password!</p> <p>You'll need to note the server's <strong>IPv4</strong> address (it'll be a series of 4 numbers, 0-254, separated by full stops, e.g. 103.99.72.244), and you should also be aware that your server will have a newer <strong>IPv6</strong> address, which will be a set of 8 four <em>hex character</em> values (each hex character can have one of 16 values: 0-9,A-F) separated by colons, e.g. 2604:A880:0002:00D0:0000:0000:20DE:9001. With one or the other of those IPs, you should be able to <a href="https://www.digitalocean.com/community/tutorials/how-to-use-ssh-to-connect-to-a-remote-server-in-ubuntu">log into your new server via SSH</a>. If you're on a UNIX command line (e.g. a Linux or MacOS desktop), do this in a terminal. On Windows, I understand people use a tool called Putty for SSH, in which case follow the app's instructions.</p> <p><code>ssh [your server IPv4 or IPv6]</code></p> <p>followed by the ENTER key (that'll be true for any line of commands I provide).</p> <p>In some cases, depending on your hosting provider, you'll have a password to enter, or if you've specified your pre-existing public SSH key, you shouldn't need to enter a password at all, you should be logged in. To check what user you care, you can type</p> <p><code>whoami</code></p> <p>If it returns <code>root</code> (there's also a convention of using a '#' as the command prompt), you're the root or super-admin of the server. If not, you're a normal user (some hosting providers have a convention of giving you a default user called "ubuntu" or perhaps "debian") with a prompt that is, by convention, a '$'.</p> <p>Now that you're logged in, it's worth doing an upgrade of your server's Ubuntu system! Do that as follows (this works regardless of whether your a root user or an unprivileged user with 'sudo' ability):</p> <p><code>sudo apt update &amp;&amp; sudo apt dist-upgrade</code></p> <p>Usually the user, even if it's not the root user, will have the ability to use the <code>sudo</code> command modifier - that means "<em>do</em> this action as the root (aka the 'Super User', thus '<em>su</em>' in 'sudo' for short) user" - if you're a non-root user, you'll likely be asked to enter your password as a security precaution the first time you run a command prefaced by <code>sudo</code>. Enter it, and it should run the command. Plus, the system shouldn't bother you for it again unless you leave your terminal unused for a while (usually 5 minutes) and come back to it.</p> <p>At this point, I also like to install a cool software package called 'etckeeper' which records configuration changes on your VPS for future reference (it can be life-saving if trying to recover from an administrative mess-up!):</p> <p><code>sudo apt install etckeeper</code></p> <p>which will also install some dependencies, including the very important (and relevant later on) 'git' version control system.</p> <h2><a id="user-content-key-variables-for-you-nextcloud-and-onlyoffice-instances" href="#key-variables-for-you-nextcloud-and-onlyoffice-instances" name="key-variables-for-you-nextcloud-and-onlyoffice-instances" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Key variables for you NextCloud and OnlyOffice instances</h2> <p>To set up your services, you'll need a few crucial bits of information related to your system's identity and external systems you'll need it to interact with. For example, as mentioned before, you'll need a domain name. For the rest of this tutorial, we'll use the convention of representing those variables as a name inside [], or, for the domain name you've picked, [domain name].</p> <p>Here's a list of variables you'll need to know to complete the rest of this tutorial:</p> <ul><li> <strong>[ipv4]</strong> and <strong>[ipv6]</strong> - your VPS' IPv4 and IPv6 addresses (the latter can be ignored if your cloud provider doesn't support IPv6 addresses) as described above.</li> <li> <strong>[nextcloud domain]</strong> and <strong>[onlyoffice domain]</strong> - the fully qualified domain names or subdomains of a base <strong>[domain name]</strong> by which you want your services to be accessed. You must have full domain management ability on this domain. Example: nextcloud.oeru.org - that's the nextcloud subdomain of the oeru.org domain. *Authenticating SMTP details - this is required so your services can send emails to users - crucial things like email address validation and password recovery emails... <ul><li> <strong>[smtp server]</strong> - the domain name or IPv4 or IPv6 address of an SMTP server</li> <li> <strong>[smtp port]</strong> - the port number on the server that is listening for your connection. By convention it's likely to be 465 or 587, or possibly 25.</li> <li> <strong>[smtp reply-to-email]</strong> - a monitored email to which people can send email related to this WordPress site, e.g. notifications@<strong>[domain name]</strong> </li> <li> <strong>[smtp user]</strong> - the username (often an email address) used to authenticate against your SMTP server, provided by your email provider.</li> <li> <strong>[smtp password]</strong> - the accompanying password, provided by your email provider.</li> </ul></li> <li> <strong>[your email]</strong> - an email address to which system-related emails can be sent to you, perhaps something like webmaster@[domain name].</li> <li> <strong>[vps username]</strong> - the username you use on your server (by convention, these are one word, and all lower case).</li> <li> <strong>[redis password]</strong> - this is a random secret that secure access to your webserver's cached data - I use a <a href="/node/43">randomly generated alphanumeric password</a>.</li> <li> <strong>[onlyoffice secret]</strong> - this comes from your actual install, and you can get it when the time comes.</li> <li>The MariaDB credentials for your NextCloud system (which stores a lot of stuff in MariaDB or MySQL by default) <ul><li> <strong>[db name]</strong> - the name of your MariaDB database for NextCloud - usually 'nextcloud'.</li> <li> <strong>[db user]</strong> - the user who can manage your database.</li> <li> <strong>[db password]</strong> - the user's password.</li> </ul></li> </ul><h3><a id="user-content-get-your-domain-lined-up" href="#get-your-domain-lined-up" name="get-your-domain-lined-up" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Get your Domain lined up</h3> <p>You will want to have a domain to point at your server, so you don't have to remember the IP number. There're are thousands of domain "registrars" in the world who'll help you do that... You just need to "register" a name, and you pay yearly fee (usually between USD10-30 depending on the country and the "TLD" (Top Level Domain. There're national ones like .nz, .au, .uk, .tv, .sa, .za, etc., or international domains (mostly associated with the US) like .com, .org, .net, and a myriad of others. Countries decide on how much their domains wholesale for and registrars add a margin for the registration service).</p> <p>Here in NZ, I use the services of Metaname (they're local to me in Christchurch, and I know them personally and trust their technical capabilities). If you're not sure who to use, ask your friends. Someone's bound to have recommendations (either positive or negative, in which case you'll know who to avoid).</p> <p>Once you have selected and registered your domain, you can 'manage your Zone' to set up (usually through a web interface provided by the registrar) an <strong>A Record</strong> which associates your website's name to the <strong>IPv4</strong> address of your server. So you should just be able to enter your server's IPv4 address, the domain name (or sub-domain) you want to use for the web service you want to set up.</p> <p>Nowadays, <em>if your Domain Name host offers it (some don't, meaning you might be better off with a different one),</em> it's also important to define an <strong>IPv6</strong> record, which is called an <strong>AAAA Record</strong>... you put in your IPv6 address instead of your IPv4 one.</p> <p>You might be asked to set a "Time-to-live" (which has to do with the length of time Domain Name Servers are asked to "cache" the association that the A Record specifies) in which case you can put in 3600 seconds or an hour depending on the time units your registrar's interface requests... but in most cases that'll be set to a default of an hour automatically.</p> <h2><a id="user-content-editing-files" href="#editing-files" name="editing-files" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Editing files</h2> <p>In the rest of this tutorial, we're going to be editing quite a few files via the command line. If you're new to this, I recommend using the 'nano' text editor which is installed by default on Ubuntu Linux systems. It's fairly simple, and all of its options are visible in the text-based interface. I tend to use a far more powerful but far less beginner-friendly editor called 'vim'. There're other editors people might choose, too. To use your preferred editor for the rest of the tutorial, enter the following to set an environment variable EDIT, specifying your preferred editor, e.g.:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>EDIT</span>=$<span>(</span><span>which</span> <span>nano</span><span>)</span></pre></div></div> <p>or, if you're like me</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>EDIT</span>=$<span>(</span><span>which</span> <span>vim</span><span>)</span></pre></div></div> <p>so that subsequent references to $EDIT will invoke your preferred editor. Note the command <code>$(which nano)</code> is a script which finds the full path to the named command, in this case 'nano'. Putting a command inside the $() means 'replace with the value the script returns', so it sets the value of EDIT to the path of the nano command in this case.</p> <p>To test (at any time) whether you session still knows your $EDIT command, run</p> <p><code>echo $EDIT</code></p> <p>if it returns the path to your preferred editor, you're good to go. If not, just reassert the EDIT= line from above!</p> <p><em>Note: if you log out and back in again, change users, or create a new terminal tab/session, you'll need to reassert the EDIT value.</em></p> <h3><a id="user-content-set-up-an-unprivileged-user-for-yourself" href="#set-up-an-unprivileged-user-for-yourself" name="set-up-an-unprivileged-user-for-yourself" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Set up an unprivileged user for yourself</h3> <p>You should be able to test that your A and AAAA Records have been set correctly by logging into your server via SSH using your domain name rather than the IPv4 or IPv6 address you used previously. It should (after you accept the SSH warning that the server's name has a new name) work the same way your original SSH login did.</p> <p>This will log you into your server as it did the first time, either as 'root' or the default unprivileged user. It's not considered good practice to access your server as root (it's too easy to completely screw it up by accident). It's a good idea to create your own separate 'non-root' user who has 'sudo' privileges and the ability to log in via SSH. If you are <em>currently logged in as 'root'</em>, you can create a normal user for yourself via (replace [vps username] with your chosen username - in my case, I'd use <code>U=dave</code>):</p> <p><code>U=[vps username]</code><br /><code>adduser $U</code><br /><code>adduser $U ssh</code><br /><code>adduser $U admin</code><br /><code>adduser $U sudo</code></p> <p>You'll also want to a set a password for user [vps username] (we have a tutorial on <a href="/node/43">creating good passwords</a>):</p> <p><code>passwd $U</code></p> <p>then become that user temporarily (note, the root user can 'become' another user without needing to enter a password) and create an SSH key and, in the process, the <code>.ssh</code> directory (directories starting with a '.' are normally 'hidden' - you can show them in a directory listing via <code>ls -a</code>) for the file into which to put your public SSH key:</p> <p><code>su $U</code></p> <p>after which you need to re-run your EDIT command: <code>EDIT=$(which nano)</code></p> <p>and then run <code>ssh-keygen -t rsa -b 2048</code><br /><code>$EDIT ~/.ssh/authorized_keys</code></p> <p>and in that file, copy and paste (without spaces on either end) your <em>current computer's</em> <strong>public</strong> ssh key (<em>never publish</em> your private key anywhere!), save and close the file.</p> <p>and then leave the 'su' state, back to the superuser:</p> <p><code>CTRL+D</code> or type <code>exit</code></p> <p>From that point, you should be able to SSH to your server via <code>ssh [vps username]@[domain name]</code> without needing to enter a password.</p> <p>These instructions use 'sudo' in front of commands because I assume you're using a non-root user. The instructions will still work fine even if you're logged in as 'root' (the 'sudo' will be ignored as it's unnecessary).</p> <h2><a id="user-content-configure-the-vps" href="#configure-the-vps" name="configure-the-vps" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configure the VPS</h2> <p>First things first. Let's make sure you've got the time zone set appropriately for your instance. It'll probably default to 'UTC' (Greenwich Mean Time). For our servers, I tend to pick 'Pacific/Auckland' which is our time zone. Run this</p> <p><code>sudo dpkg-reconfigure tzdata</code></p> <p>and pick the appropriate timezone. You can just leave it running UTC, but you might find it tricky down the track if, for example, you're looking at logs and having to constantly convert the times into your timezone.</p> <h3><a id="user-content-configuring-your-firewall" href="#configuring-your-firewall" name="configuring-your-firewall" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring your firewall</h3> <p>In the name of safety from the get-go, let's configure our firewall. We work on the basis of explicitly allowing in <em>only</em> what we want to let in (i.e. a 'default deny' policy).</p> <p>First we'll enable the use of SSH through the firewall (<em>not doing this could lock us out of your machine!</em>)</p> <p><code>sudo ufw allow ssh</code><br /></p> <p>while we're here, we'll also enable data transfer from the internal (to the VPS) Docker virtual network and the IP range it uses for Docker containers:</p> <p><code>sudo ufw allow in on docker0</code><br /><code>sudo ufw allow from 172.0.0.0/8 to any</code></p> <p>Then we'll enable forwarding from internal network interfaces as required for Docker containers to be able to talk to the outside world:</p> <p><code>sudo $EDIT /etc/default/ufw</code></p> <p>and copy the line <code>DEFAULT_FORWARD_POLICY="DROP"</code> tweak it to look like this (commenting out the default, but leaving it there for future reference!):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>#DEFAULT_FORWARD_POLICY="DROP"</span> <span>DEFAULT_FORWARD_POLICY</span>=<span>"ACCEPT"</span></pre></div></div> <p>and then save and exit the file (CTRL-X and then 'Y' if your editor is nano).</p> <p>You also have to edit <code>/etc/ufw/sysctl.conf</code> and remove the "#" at the start of the following lines, so they look like this:</p> <p><code>sudo $EDIT /etc/ufw/sysctl.conf</code></p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span># Uncomment this to allow this host to route packets between interfaces</span> net<span>/</span>ipv4<span>/</span><span>ip_forward</span>=<span>1</span> net<span>/</span>ipv6<span>/</span>conf<span>/</span>default<span>/</span><span>forwarding</span>=<span>1</span> net<span>/</span>ipv6<span>/</span>conf<span>/</span>all<span>/</span><span>forwarding</span>=<span>1</span></pre></div></div> <p>Then we need to restart the network stack to apply that configuration change</p> <p><code>sudo systemctl restart systemd-networkd</code></p> <p>(on older Ubuntu systems this would have been done via <code>sudo service networking restart</code>...)</p> <p>Next we have to enable the UFW firewall to start at boot time.</p> <p><code>sudo $EDIT /etc/ufw/ufw.conf</code></p> <p>And set the ENABLED variable near the top:</p> <p><code>ENABLED=yes</code></p> <p>Now you can formally start UFW now:</p> <p><code>sudo ufw enable</code></p> <h3><a id="user-content-install-the-nginx" href="#install-the-nginx" name="install-the-nginx" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Install the Nginx</h3> <p>Next we need to install the Nginx web server and reverse-proxy, as well as the Let's Encrypt SSL certificate generator, both of which are crucial for any secure web services you might want to host. Nginx is a more efficient and flexible alternative to the older Apache web server you might've seen elsewhere (Nginx recently surpassed Apache as the most widely used web server on the Internet).</p> <p><code>sudo apt install nginx-full letsencrypt ssl-cert</code></p> <p>You'll get a couple pop-up windows in your terminal, just hit ENTER to accept the defaults. Having installed it, we need to create firewall rules to allow external services to see it:</p> <p><code>sudo ufw allow 'Nginx Full'</code></p> <p>You can check if the firewall rules you requested have been enabled:</p> <p><code>sudo ufw status</code></p> <h2><a id="user-content-outgoing-vps-email-optional" href="#outgoing-vps-email-optional" name="outgoing-vps-email-optional" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Outgoing VPS Email (optional)</h2> <p>Although it's not absolutely necessary (you can do this section later if you're in a big hurry), it's very useful for your server to be able to send out emails, like status emails to administrators (perhaps you) about things requiring their attention, e.g. the status of backups, pending security updates, expiring SSL certificates, etc. To do this, we'll set up the industrial strength Postfix SMTP server, which is pretty quick and easy. First we install Postfix.</p> <p><code>sudo apt install postfix bsd-mailx</code></p> <p>During the install, you'll be asked to select a bunch of configuration parameters. Select the defaults except:</p> <ul><li>Select "Internet Site with Smarthost",</li> <li>fill in the domain name for your server [domain name],</li> <li>the [smtp server] name and [smtp port] (in the form [smtp server]:[smtp port], e.g. smtp.oeru.org:587 ) of your "smarthost" who'll be doing the authenticating SMTP for you, and</li> <li>the email address to which you want to receive system-related messages, [your email].</li> </ul><p>After that's done, we set a default address for the server to mail to, to [your email] selected above. First</p> <p><code>sudo $EDIT /etc/aliases</code></p> <p>We need to make sure the "root" user points to a real email address. Add a line at the bottom which says (replacing [your email] with your email :) )</p> <p><code>root: [your email]</code></p> <p>After which you'll need to convert the aliases file into a form that postfix can process, simply by running this:</p> <p><code>sudo newaliases</code></p> <p>Then we have to define the authentication credentials required to convince your mail server that you're you!</p> <p><code>sudo $EDIT /etc/postfix/relay_password</code></p> <p>and enter a single line in this format:</p> <p><code>[smtp server] [smtp user]:[smtp password]</code></p> <p>as an example, this is more or less what I've got for my system. Note that the [smtp user] in my case is an email address (this is common with many smtp system - the user is the same as the email address):</p> <p><code>smtp.oerfoundation.org smtp-work@fossdle.org:SomeObscurePassw0rd</code></p> <p>then save the file and, like the aliases file, run the conversion process (which uses a slightly different mechanism):</p> <p><code>sudo postmap /etc/postfix/relay_password</code></p> <p>Finally, we'll edit the main configuration file for Postfix to tell it about all this stuff:</p> <p>sudo $EDIT /etc/postfix/main.cf</p> <p>If your SMTP server uses port 25 (the default for unencrypted SMTP) you don't have to change anything, although most people nowadays prefer to use StartTLS or otherwise encrypted transport to at least ensure that your SMTP authentication details (at least) are transferred encrypted. That means using port 587 or 465. If you're using either of those ports, find the "relayhost = [your server name]" line... and add your port number after a colon, like this</p> <p><code>relayhost = [smtp server]:[smtp port]</code></p> <p>or, for example:</p> <p><code>relayhost = smtp.oerfoundation.org:465</code></p> <p>Then we have to update the configuration for Postfix to ensure that it knows about the details we've just defined (this command will automatically back up the original default configuration so you can start from scratch with the template below):</p> <p><code>sudo mv /etc/postfix/main.cf /etc/postfix/main.cf.orig &amp;&amp; sudo $EDIT /etc/postfix/main.cf</code></p> <p>You can just copy-and-paste the following into it, substituting your specific values for the [tokens].</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span># See /usr/share/postfix/main.cf.dist for a commented, more complete version</span>   <span># Debian specific: Specifying a file name will cause the first</span> <span># line of that file to be used as the name. The Debian default</span> <span># is /etc/mailname.</span> <span>#myorigin = /etc/mailname</span>   smtpd_banner = <span>$myhostname</span> ESMTP <span>$mail_name</span> <span>(</span>Ubuntu<span>)</span> biff = no   <span># appending .domain is the MUA's job.</span> append_dot_mydomain = no   <span># Uncomment the next line to generate "delayed mail" warnings</span> <span>#delay_warning_time = 4h</span> readme_directory = no   <span># See http://www.postfix.org/COMPATIBILITY_README.html -- default to 3.6 on</span> <span># fresh installs.</span> compatibility_level = <span>3.6</span>   <span># TLS parameters</span> <span>smtpd_tls_cert_file</span>=<span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>ssl-cert-snakeoil.pem <span>smtpd_tls_key_file</span>=<span>/</span>etc<span>/</span>ssl<span>/</span>private<span>/</span>ssl-cert-snakeoil.key <span>smtpd_tls_security_level</span>=may   <span>smtp_tls_CApath</span>=<span>/</span>etc<span>/</span>ssl<span>/</span>certs <span>#smtp_tls_security_level=may</span> smtp_tls_session_cache_database = btree:<span>${data_directory}</span><span>/</span>smtp_scache   smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination myhostname = <span>[</span>domain name<span>]</span> alias_maps = hash:<span>/</span>etc<span>/</span>aliases alias_database = hash:<span>/</span>etc<span>/</span>aliases myorigin = <span>/</span>etc<span>/</span>mailname mydestination = <span>$myhostname</span>, localhost relayhost = <span>[</span>smtp server<span>]</span>:<span>[</span>smtp port<span>]</span> mynetworks = 127.0.0.0<span>/</span><span>8</span> <span>[</span>::ffff:127.0.0.0<span>]</span><span>/</span><span>104</span> <span>[</span>::<span>1</span><span>]</span><span>/</span><span>128</span> mailbox_size_limit = <span>0</span> recipient_delimiter = + inet_interfaces = all inet_protocols = all   <span># added to configure accessing the relay host via authenticating SMTP</span> smtp_sasl_auth_enable = <span>yes</span> smtp_sasl_password_maps = hash:<span>/</span>etc<span>/</span>postfix<span>/</span>relay_password smtp_sasl_security_options = noanonymous smtp_tls_security_level = encrypt   <span># if you're using Ubuntu prior to 20.04, uncomment (remove the #) the</span> <span># earlier line smtp_tls_security_level = may to save errors in 'postfix check'</span> <span># and comment this line (by adding a # at the start)</span> smtp_tls_wrappermode = <span>yes</span></pre></div></div> <p>Once you've created that <code>main.cf</code> file, you can double check that your config is valid:</p> <p><code>sudo postfix check</code></p> <p>and if it's all ok, you can get Postfix to re-read its configuration:</p> <p><code>sudo postfix reload</code></p> <p>You can then try sending an email so see if it works!</p> <p>By default, a command line application called "mail" is installed as part of the bsd-mailx package we installed alongside postfix. You can use it to send test email from the command line on your host to verify you've got things working correctly! The stuff in &lt;&gt; are the keys to hit at the end of the line...</p> <p><code>mail you@email.domain&lt;ENTER&gt;</code></p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>Subject: Testing from your.relay.server.domain<span>&lt;</span>ENTER<span>&gt;</span> Testing postfix remote host<span>&lt;</span>ENTER<span>&gt;</span> <span>&lt;</span>CTRL-D<span>&gt;</span> Cc:<span>&lt;</span>ENTER<span>&gt;</span></pre></div></div> <p>Typing (hold down the Control or Ctrl key on your keyboard and press the "d" key) will finish your message, showing you a "CC:" field, in which you can type in other email addresses if you want to test sending to multiple addresses. When you then hit , it will attempt to send this email. It might take a few minutes to work its way through to the receiving email system (having to run the gauntlet of spam and virus filters on the way).</p> <p>You can also always check the postfix system logs to see what postfix thinks about it using the command:</p> <p><code>sudo less +G /var/log/mail.log</code></p> <p>if your system doesn't have a <code>/var/log/mail.log</code>, never fear! Try this instead:</p> <p><code>sudo less +G /var/log/syslog</code></p> <p>In either case, hit to have the log update in real time.</p> <h2><a id="user-content-installing-docker-compose-and-lets-encrypt" href="#installing-docker-compose-and-lets-encrypt" name="installing-docker-compose-and-lets-encrypt" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Installing Docker Compose and Let's Encrypt</h2> <p>The next step is to set up the file structure for holding your Docker configurations and the data your Docker containers will access. This is my convention, so you're welcome to do things different, but this is a 'known good' approach.</p> <p>First let's install Docker Compose (and its dependencies, like the whole Docker subsystem) and the <a href="http://letsencrypt.org/">Let's Encrypt</a> scripts that let you procure no-cost Secure Sockets Layer certificates to secure access to your server.</p> <p><code>sudo apt install docker-compose letsencrypt</code></p> <p>Now we create the set of directories I use for holding Docker Compose configurations (<code>/home/docker</code>) and the persistent data the Docker containers create (<code>/home/data</code>)</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>D</span>=<span>[</span>nextcloud domain<span>]</span> <span>sudo</span> <span>mkdir</span> <span>-p</span> <span>/</span>home<span>/</span>data<span>/</span><span>$D</span> <span>sudo</span> <span>mkdir</span> <span>-p</span> <span>/</span>home<span>/</span>docker<span>/</span><span>$D</span></pre></div></div> <p>followed by</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>D</span>=<span>[</span>onlyoffice domain<span>]</span> <span>sudo</span> <span>mkdir</span> <span>-p</span> <span>/</span>home<span>/</span>data<span>/</span><span>$D</span> <span>sudo</span> <span>mkdir</span> <span>-p</span> <span>/</span>home<span>/</span>docker<span>/</span><span>$D</span></pre></div></div> <p>It's helpful to make sure that your non-root user can also read and write files in these directories:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>U</span>=<span>[</span>vps username<span>]</span> <span>sudo</span> <span>chown</span> <span>-R</span> <span>$U</span> <span>/</span>home<span>/</span>docker <span>sudo</span> <span>chown</span> <span>-R</span> <span>$U</span> <span>/</span>home<span>/</span>data</pre></div></div> <h2><a id="user-content-installing-mariadb" href="#installing-mariadb" name="installing-mariadb" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Installing MariaDB</h2> <p>MariaDB is effectively a drop-in alternative to MySQL and we prefer it because it's not controlled by Oracle and has a more active developer community. On Ubuntu, MariaDB pretends to be MySQL for compatibility purposes, so don't be weirded out by the interchangeable names below. Install the server and the client like this.</p> <p><code>sudo apt install mariadb-server mariadb-client</code></p> <p>You should now be able to type <code>sudo mysql</code> at the command prompt, and it'll log you into the MariaDB console (to get out type <code>\q</code> or <code>exit</code>)</p> <p>Tweak the configuration so that it's listening on</p> <p><code>sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf</code></p> <p>and copy the bind-address line and adjust so it looks like this - we want MariaDB to be listening on all interfaces, not just localhost (127.0.0.1)...</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span># Instead of skip-networking the default is now to listen only on</span> <span># localhost which is more compatible and is not less secure.</span> <span>#bind-address = 127.0.0.1</span> bind-address = 0.0.0.0</pre></div></div> <p>Then restart MariaDB:</p> <p><code>sudo service mysql restart</code></p> <p>It should now be listening on port 3306 on all interfaces, i.e. 0.0.0.0. Your instance will be protected from anyone outside of your VPS connecting to it by the fact that external access to port 3306 isn't allowed by your ufw firewall.</p> <p>To check it's running, you can run</p> <p><code>sudo netstat -punta | grep 3306</code></p> <p>and you should see something like</p> <p><code>tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 8459/mysqld</code></p> <p>which is the 'mysqld' (the MySQL-compatible database daemon provided by MariaDB).</p> <p>Now set up the database which will hold NextCloud's data. Log into the MySQL client on the host:</p> <p><code>sudo mysql</code></p> <p>You'll need to gin up a password for your "nextcloud" database user. I usually use <code>pwgen</code> (<code>sudo apt install pwgen</code>) - for example running this command will give you a single 19 character password without special characters (just numbers and letters):</p> <p><code>pwgen -s 19 1</code></p> <p>Giving you something like this (but if it's truly random, almost certainly not exactly this):</p> <p>bYIOSrvR9aGwL5FRGFU</p> <p>At the prompt (which will look something like MariaDB [(none)]&gt;) enter the following lines (putting your password in place of [passwd]):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER <span>"nextcloud"</span><span>@</span><span>"%"</span> IDENTIFIED BY <span>"[passwd]"</span>; GRANT ALL ON nextcloud.<span>*</span> to <span>"nextcloud"</span><span>@</span><span>"%"</span>; FLUSH PRIVILEGES;</pre></div></div> <p>Then enter <code>\q</code> to exit.</p> <h2><a id="user-content-configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice" href="#configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice" name="configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring Nginx reverse proxy for NextCloud and OnlyOffice</h2> <p>Above, we installed Nginx as well as the Let's Encrypt scripts. Now we'll configure them as it's useful to have them working <em>before</em> you set up your services.</p> <p>In order for you, outside of your server, to see the NextCloud and OnlyOffice services, you will need to set up a secure external 'reverse proxy' on your host VPS which will accept requests for those two services from the Internet and pass those requests securely to the two sets of Docker containers providing the services. These will answer to <code>https://[nextcloud domain]</code> (for NextCloud) and <code>https://[onlyoffice domain]</code> for OnlyOffice.</p> <p>Let's Encrypt will provide the SSL certificates (each is a file with a specially generated, very long string) which we use to limit access to our services to encrypted (secure) connections (protecting both our users and ourselves from external enemies).</p> <p>Nginx will not run unless the SSL certificates you reference in your configurations are valid. Given that we need to request them with a working Nginx <em>prior</em> to them being created puts us in an awkward position. We use a trick to get around it: we <em>temporarily</em> reference the default 'self-signed' SSL certificates (sometimes called 'Snakeoil certs' because that's the placeholder name they're given) that every new Linux system generates when it's installed, that are <em>valid certificates</em> (and thus acceptable to Nginx) but *they won't work with our domains, as they're generic and not 'signed' by an external party, like Let's Encrypt, meaning that your browser won't like them. But that's ok, as you browser will never need to see them, and Let's Encrypt's systems won't look at them either. We'll swap the Snakeoil certs out as soon as we've successfully created the Let's Encrypt ones, and your browser will be happy, and all will be well with the world.</p> <p>Note: many thanks to Stephen Harlow (who crash-tested this tutorial!) for pointing out that you <em>might</em> need to run the following if you're not finding the 'Snakeoil certs' on your system (running them just to be safe shouldn't cause any issues):</p> <p><code>sudo make-ssl-cert generate-default-snakeoil</code></p> <h2><a id="user-content-lets-encrypt-setup" href="#lets-encrypt-setup" name="lets-encrypt-setup" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Let's Encrypt setup</h2> <p>Let's Encrypt and Nginx need to work together. Nginx stores all of its configuration in the directory <code>/etc/nginx</code>. The first thing we'll do is create a place for Let's Encrypt Nginx-specific configuration details:</p> <p><code>sudo mkdir /etc/nginx/includes</code></p> <p>Then we create that configuration file itself:</p> <p><code>sudo $EDIT /etc/nginx/includes/letsencrypt.conf</code></p> <p>into which we copy-and-paste the following (no [tokens] to replace in this one!)</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span># Rule for legitimate ACME Challenge requests</span> location ^~ <span>/</span>.well-known<span>/</span>acme-challenge<span>/</span> <span>{</span> default_type <span>"text/plain"</span>; <span># this can be any directory, but this name keeps it clear</span> root <span>/</span>var<span>/</span>www<span>/</span>letsencrypt; <span>}</span>   <span># Hide /acme-challenge subdirectory and return 404 on all requests.</span> <span># It is somewhat more secure than letting Nginx return 403.</span> <span># Ending slash is important!</span> location = <span>/</span>.well-known<span>/</span>acme-challenge<span>/</span> <span>{</span> <span>return</span> <span>404</span>; <span>}</span></pre></div></div> <p>As described in the file we've just created, Let's Encrypt will look for a secret code we create to verify that we own the domain we're requesting an SSL certificate for, so we have to make sure it exists:</p> <p><code>sudo mkdir /var/www/letsencrypt</code></p> <h3><a id="user-content-nextcloud-proxy-configuration" href="#nextcloud-proxy-configuration" name="nextcloud-proxy-configuration" class="heading-permalink" aria-hidden="true" title="Permalink"></a>NextCloud Proxy Configuration</h3> <p>To configure the NextCloud proxy, you need to create this configuration file in your <code>/etc/nginx/sites-available/</code> directory.</p> <p>Create a file with a meaningful name for your NextCloud Proxy, something like "nextcloud" (I use the domain name I've chosen, e.g. for docs.oeru.org I call the proxy file "docs.oeru.org" - keeps everything clear, and I can have <em>multiple instances on the same server if I want</em>...). Let's go with in this instance (change it if you prefer)</p> <p><code>sudo $EDIT /etc/nginx/sites-available/nextcloud </code></p> <p>with the following contents, replacing [nextcloud domain] with your selected domain name, but leave off the [ ] (those are just there to make sure nginx errors if you've missed replacing any) - and the port number 8080 if you've opted to change to a different one!:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>server <span>{</span> listen <span>80</span>; listen <span>[</span>::<span>]</span>:<span>80</span>;   <span># note, you can add additional domain names, separated by a space, to which this config will answer.</span> server_name <span>[</span>nextcloud domain<span>]</span>;   include includes<span>/</span>letsencrypt.conf;   <span># enforce https</span> location <span>/</span> <span>{</span> <span>return</span> <span>302</span> https:<span>//</span><span>$server_name</span><span>$request_uri</span>; <span>}</span> <span>}</span>   server <span>{</span> listen <span>443</span> ssl; listen <span>[</span>::<span>]</span>:<span>443</span> ssl;   <span># note, you can add additional domain names, separated by a space, to which this config will answer.</span> server_name <span>[</span>nextcloud domain<span>]</span>;   <span>## Access and error logs.</span> access_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>nextcloud domain<span>]</span>_access.log; error_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>nextcloud domain<span>]</span>_error.log;   <span># these are temporary certificates, used only long enough to secure Let's Encrypt certs as below.</span> ssl_certificate <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>ssl-cert-snakeoil.pem; ssl_certificate_key <span>/</span>etc<span>/</span>ssl<span>/</span>private<span>/</span>ssl-cert-snakeoil.key;   <span># these need to be commented out until after the Let's Encrypt</span> <span># certificates have been acquired</span> <span>#ssl_certificate /etc/letsencrypt/live/[nextcloud domain]/fullchain.pem;</span> <span>#ssl_certificate_key /etc/letsencrypt/live/[nextcloud domain]/privkey.pem;</span>   <span># from http://axiacore.com/blog/enable-perfect-forward-secrecy-nginx/</span> ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; <span># limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;</span> <span># forward secrecy settings</span> ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers <span>"EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"</span>; ssl_dhparam <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>dhparam.pem;   <span># The following 2 rules are only needed for the user_webfinger app.</span> <span># Uncomment it if you're planning to use this app.</span> rewrite ^<span>/</span>.well-known<span>/</span>host-meta <span>/</span>public.php?<span>service</span>=host-meta <span>last</span>; rewrite ^<span>/</span>.well-known<span>/</span>host-meta.json <span>/</span>public.php?<span>service</span>=host-meta-json <span>last</span>;   <span># The following rule is only needed for the Social app.</span> <span># Uncomment it if you're planning to use this app.</span> rewrite ^<span>/</span>.well-known<span>/</span>webfinger <span>/</span>public.php?<span>service</span>=webfinger <span>last</span>;   location ^~ <span>/</span> <span>{</span> proxy_pass http:<span>//</span>127.0.0.1:<span>8080</span>; proxy_set_header Upgrade <span>$http_upgrade</span>; proxy_set_header Connection <span>"Upgrade"</span>; proxy_set_header Host <span>$http_host</span>; proxy_read_timeout 36000s; proxy_buffering off; proxy_max_temp_file_size 15000m; <span>}</span> client_max_body_size 1G; fastcgi_buffers <span>64</span> 4K; add_header Strict-Transport-Security <span>"max-age=31536000; includeSubdomains;"</span>; <span># Remove X-Powered-By, which is an information leak</span> fastcgi_hide_header X-Powered-By; <span>}</span></pre></div></div> <p>Note: you'll need to create the file cited in the proxy configuration: <code>/etc/ssl/certs/dhparam.pem</code></p> <p>You can do this as follows (install the necessary software, backup any possible existing version as a matter of prudence, and create a new one):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>sudo</span> apt update <span>&amp;&amp;</span> <span>sudo</span> apt <span>install</span> openssl <span>sudo</span> <span>[</span> <span>-f</span> <span>"/etc/ssl/certs/dhparam.pem"</span> <span>]</span> <span>&amp;&amp;</span> <span>sudo</span> <span>mv</span> <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>dhparam.pem <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>dhparam.pem.bak <span>sudo</span> openssl dhparam <span>-out</span> <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>dhparam.pem <span>2048</span></pre></div></div> <p>Once those are created, you have to make sure that they're "enabled" (replacing with your file names, of course):</p> <p><code>cd /etc/nginx/sites-enabled</code> <code>sudo ln -sf ../sites-available/nextcloud .</code></p> <p>To confirm that there aren't any typos or issues that might make nginx unhappy, run</p> <p><code>sudo nginx -t</code></p> <p>If all's well, get nginx to reread its configuration with the new files (if not, it might be because you missed replacing one of the [tokens]):</p> <p><code>sudo service nginx reload</code></p> <h3><a id="user-content-onlyoffice-proxy-configuration" href="#onlyoffice-proxy-configuration" name="onlyoffice-proxy-configuration" class="heading-permalink" aria-hidden="true" title="Permalink"></a>OnlyOffice Proxy Configuration</h3> <p>The OnlyOffice proxy configuration uses a very similar process to the one above. You just need to create another configuration file:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>upstream docservice <span>{</span> server 127.0.0.1:<span>9880</span>; <span>}</span>   map <span>$http_host</span> <span>$this_host</span> <span>{</span> <span>""</span> <span>$host</span>; default <span>$http_host</span>; <span>}</span>   map <span>$http_x_forwarded_proto</span> <span>$the_scheme</span> <span>{</span> default <span>$http_x_forwarded_proto</span>; <span>""</span> <span>$scheme</span>; <span>}</span>   map <span>$http_x_forwarded_host</span> <span>$the_host</span> <span>{</span> default <span>$http_x_forwarded_host</span>; <span>""</span> <span>$this_host</span>; <span>}</span>   map <span>$http_upgrade</span> <span>$proxy_connection</span> <span>{</span> default upgrade; <span>""</span> close; <span>}</span>   proxy_set_header Upgrade <span>$http_upgrade</span>; proxy_set_header Connection <span>$proxy_connection</span>; proxy_set_header X-Forwarded-Host <span>$the_host</span>; proxy_set_header X-Forwarded-Proto <span>$the_scheme</span>; proxy_set_header X-Forwarded-For <span>$proxy_add_x_forwarded_for</span>;   server <span>{</span> listen <span>80</span>; listen <span>[</span>::<span>]</span>:<span>80</span>;   server_name <span>[</span>onlyoffice domain<span>]</span>;   <span># for let's encrypt renewals!</span> include <span>/</span>etc<span>/</span>nginx<span>/</span>includes<span>/</span>letsencrypt.conf;   <span>## Access and error logs.</span> access_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>onlyoffice domain<span>]</span>_access.log; error_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>onlyoffice domain<span>]</span>_error.log;   <span># redirect all HTTP traffic to HTTPS.</span> location <span>/</span> <span>{</span> <span>return</span> <span>302</span> https:<span>//</span><span>$server_name</span><span>$request_uri</span>; <span>}</span> <span>}</span>   <span># This configuration assumes that there's an nginx container talking to the mautic PHP-fpm container,</span> <span># and this is a reverse proxy for that Mautic instance.</span> server <span>{</span> listen <span>443</span> ssl; listen <span>[</span>::<span>]</span>:<span>443</span> ssl;   server_name <span>[</span>onlyoffice domain<span>]</span>;   ssl_certificate <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>ssl-cert-snakeoil.pem; ssl_certificate_key <span>/</span>etc<span>/</span>ssl<span>/</span>private<span>/</span>ssl-cert-snakeoil.key; <span>#ssl_certificate /etc/letsencrypt/live/[onlyoffice domain]/fullchain.pem;</span> <span>#ssl_certificate_key /etc/letsencrypt/live/[onlyoffice domain]/privkey.pem;</span> ssl_protocols TLSv1 TLSv1.1 TLSv1.2; <span># to create this, see https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html</span> ssl_dhparam <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>dhparam.pem; keepalive_timeout 20s; <span># for let's encrypt renewals!</span> include <span>/</span>etc<span>/</span>nginx<span>/</span>includes<span>/</span>letsencrypt.conf;   proxy_http_version <span>1.1</span>; proxy_buffering off;   <span>## Access and error logs.</span> access_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>onlyoffice domain<span>]</span>_access.log; error_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span><span>[</span>onlyoffice domain<span>]</span>_error.log;   add_header Strict-Transport-Security max-age=<span>31536000</span>; <span># add_header X-Frame-Options SAMEORIGIN;</span> add_header X-Content-Type-Options nosniff;   <span># see https://github.com/ONLYOFFICE/document-server-proxy/blob/master/nginx/proxy-https-to-http.conf</span> location <span>/</span> <span>{</span> proxy_pass http:<span>//</span>docservice; proxy_http_version <span>1.1</span>; <span>}</span> <span>}</span></pre></div></div> <p>After that's done, we'll repeat what we did for the NextCloud config:</p> <p><code>sudo cd /etc/nginx/sites-enabled</code> <code>sudo ln -sf ../sites-available/onlyoffice .</code> <code>sudo nginx -t</code></p> <p>and, if there're no errors, run</p> <p><code>sudo service nginx reload</code></p> <p>Now we're ready to request Let's Encrypt certificates.</p> <h3><a id="user-content-requesting-lets-encrypt-certificates" href="#requesting-lets-encrypt-certificates" name="requesting-lets-encrypt-certificates" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Requesting Let's Encrypt certificates</h3> <p>To request Let's Encrypt SSL certificates for your NextCloud and OnlyOffice services, run the following, replacing the [token], of course (note that 'certbot' is the script provided by the Let's Encrypt package - historically, it could also be called via 'letsencrypt', although apparently the latter is now deprecated):</p> <p><code>sudo certbot --webroot -w /var/www/letsencrypt -d [nextcloud domain]</code></p> <p>Note - if you want to address your instance from multiple domains, use one (or more) <code>-d [another domain]</code> - just make sure that</p> <ul><li>all those domains already point to your VPS, and</li> <li>those domains are included in the Nginx proxy configuration above.</li> </ul><p>otherwise the Let's Encrypt certbot request will fail!</p> <p>Here's what you're likely to see as output from the first run of the letsencrypt script - note that it will ask you for an email address (so it can send you warnings if your certificate is going to expire, e.g. due to a problem with renewal (like if you make a configuration change that breaks the renewal process)).</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>Saving debug log to <span>/</span>var<span>/</span>log<span>/</span>letsencrypt<span>/</span>letsencrypt.log Enter email address <span>(</span>used <span>for</span> urgent renewal and security notices<span>)</span> <span>(</span>Enter <span>'c'</span> to cancel<span>)</span>: webmaster<span>@</span>fossdle.org   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please <span>read</span> the Terms of Service at https:<span>//</span>letsencrypt.org<span>/</span>documents<span>/</span>LE-SA-v1.3-September-<span>21</span>-<span>2022</span>.pdf. You must agree <span>in</span> order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <span>(</span>Y<span>)</span>es<span>/</span><span>(</span>N<span>)</span>o: y   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let<span>'s Encrypt project and the non-profit organization that develops Certbot? We'</span>d like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <span>(</span>Y<span>)</span>es<span>/</span><span>(</span>N<span>)</span>o: y Account registered. Requesting a certificate <span>for</span> <span>[</span>nextcloud domain<span>]</span>   Successfully received certificate. Certificate is saved at: <span>/</span>etc<span>/</span>letsencrypt<span>/</span>live<span>/</span><span>[</span>nextcloud domain<span>]</span><span>/</span>fullchain.pem Key is saved at: <span>/</span>etc<span>/</span>letsencrypt<span>/</span>live<span>/</span><span>[</span>nextcloud domain<span>]</span><span>/</span>privkey.pem This certificate expires on <span>(</span>some future <span>date</span><span>)</span>. These files will be updated when the certificate renews. Certbot has <span>set</span> up a scheduled task to automatically renew this certificate <span>in</span> the background.   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - If you like Certbot, please consider supporting our work by: <span>*</span> Donating to ISRG <span>/</span> Let<span>'s Encrypt: https://letsencrypt.org/donate * Donating to EFF: https://eff.org/donate-le - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span></pre></div></div> <p>Ideally, you'll see a message like the above. If not, and there's an error, the error messages they provide are usually very useful and accurate. Fix the problem and try again. Note, your SSL certificate will have the name of your [nextcloud domain], even if it also provide support for [second domain name] (or third, fourth, etc.).</p> <p>Once you have a Let's Encrypt certificate, you can update our NGINX configuration:</p> <p><code>sudo $EDIT /etc/nginx/sites-available/[nextcloud domain]</code></p> <p>and swap all occurrences of</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre> ssl_certificate <span>/</span>etc<span>/</span>ssl<span>/</span>certs<span>/</span>ssl-cert-snakeoil.pem; ssl_certificate_key <span>/</span>etc<span>/</span>ssl<span>/</span>private<span>/</span>ssl-cert-snakeoil.key; <span># ssl_certificate /etc/letsencrypt/live/[nextcloud domain]/fullchain.pem;</span> <span># ssl_certificate_key /etc/letsencrypt/live/[nextcloud domain]/privkey.pem;</span></pre></div></div> <p>to</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span># ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;</span> <span># ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;</span> ssl_certificate <span>/</span>etc<span>/</span>letsencrypt<span>/</span>live<span>/</span><span>[</span>nextcloud domain<span>]</span><span>/</span>fullchain.pem; ssl_certificate_key <span>/</span>etc<span>/</span>letsencrypt<span>/</span>live<span>/</span><span>[</span>nextcloud domain<span>]</span><span>/</span>privkey.pem;</pre></div></div> <p>which enables your new domain-specific SSL certificate. Check that NGINX is happy with your change:</p> <p><code>sudo nginx -t</code></p> <p>and if so,</p> <p><code>sudo service nginx reload</code></p> <p>You domain should now be enabled for <code>https://</code> access. Note that going to <code>http://[nextcloud domain]</code> should automatically redirect you to <code>https://[nextcloud domain]</code> because you care about your user's security! :grin:</p> <p>Now you'll have to repeat the same process for the [onlyoffice domain]. When that's done... Onward!</p> <h2><a id="user-content-prepare-your-docker-compose-host" href="#prepare-your-docker-compose-host" name="prepare-your-docker-compose-host" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Prepare your Docker Compose host</h2> <p>We make use of the NextCloud community's stable Docker container which they keep (more or less) up-to-date. Similarly, the OnlyOffice developers maintain a Docker container, too. We will run them both on this same server as separate services via Docker Compose. The two sets of Docker containers will look like this:</p> <ol><li>a suite of NextCloud containers:</li> </ol><ul><li>the main PHP-FPM container (which provides most of the functionality for NextCloud using the PHP scripting engine,</li> <li>an identical container to the PHP one which runs the cron service (which does periodic administrative tasks relevant to NextCloud)</li> <li>a Redis container (which provides performance improving caching for NextCloud), and</li> <li>an Nginx webserver container which makes it easier to manage the configuration and paths of the NextCloud instance. It means that on the hosting server, we only need to run a proxying web server, which is easy.</li> </ul><ol start="2"><li>the single OnlyOffice container which, despite the Docker convention of each container running only a single services, runs the whole OnlyOffice stack, which includes PostgreSQL, Nginx, Rabbit-MQ, Python, and NodeJS.</li> </ol><p>The way I prefer to implement this set of containers is to use:</p> <p><code>sudo apt install docker-compose</code></p> <p>to set up the entire Docker and Docker Compose system on your server. If you desire, you can also set up a <a href="https://docs.docker.com/compose/install/">newer version of Docker Compose</a>, namely the 2.x series. The command line interface and feedback on actions is nicer with this newer version, but otherwise, there's little difference (a few other services I run require 2.x, like <a href="https://github.com/mailcow/mailcow-dockerized">Mailcow</a>, so I've had experience with both).</p> <p>Then set up a place for your Docker containers and the associated persistent data (your Docker containers should hold no important data - you should be able to delete and recreate them entirely without losing any important data or configuration):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>docker <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>docker<span>/</span>nextcloud <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>docker<span>/</span>onlyoffice <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>data <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>data<span>/</span>nextcloud <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>nginx <span>sudo</span> <span>mkdir</span> <span>/</span>home<span>/</span>data<span>/</span>onlyofficesudo <span>chown</span> <span>-R</span> <span>${USER}</span>:<span>${USER}</span> <span>/</span>home<span>/</span>docker <span>/</span>home<span>/</span>data</pre></div></div> <p>My personal convention is to name both docker and data directories after the specific domain name of the service to which they apply - makes it easier when, for example, I have multiple instances of NextCloud on a single server. The above is intended to be straight forward for folks only running one of each - but feel free to modify for your requirements. If you do so, remember to ripple that through the rest of these instructions!</p> <h2><a id="user-content-nextcloud-install" href="#nextcloud-install" name="nextcloud-install" class="heading-permalink" aria-hidden="true" title="Permalink"></a>NextCloud Install</h2> <h3><a id="user-content-install-the-nextcloud-docker-recipe" href="#install-the-nextcloud-docker-recipe" name="install-the-nextcloud-docker-recipe" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Install the NextCloud Docker recipe</h3> <p>Now we have a place to put the really key bit - the code for running NextCloud and OnlyOffice via Docker Compose. First, let's set up NextCloud (this also installs the OnlyOffice server):</p> <p><code>cd /home/docker/nextcloud</code></p> <p>You'll have to create a file, e.g via</p> <p><code>$EDIT docker-compose.yml</code></p> <p>and fill it with this (substituting the values in [] to suit your details - and changing the paths in /home/data if you've used something different than the default above!):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>version: <span>'3'</span> services: nginx: container_name: nginx-server image: nginx ports: - 127.0.0.1:<span>8080</span>:<span>80</span> volumes: - <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>nginx<span>/</span>nginx.conf:<span>/</span>etc<span>/</span>nginx<span>/</span>nginx.conf:ro - <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>nextcloud:<span>/</span>var<span>/</span>www<span>/</span>html links: - app environment: - VIRTUAL_HOST restart: unless-stopped app: container_name: app-server image: nextcloud:fpm stdin_open: <span>true</span> tty: <span>true</span> links: - redis expose: - <span>'80'</span> - <span>'9000'</span> volumes: - <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>nextcloud:<span>/</span>var<span>/</span>www<span>/</span>html environment: - <span>REDIS_HOST</span>=redis - <span>REDIS_HOST_PASSWORD</span>=<span>[</span>redis password<span>]</span> extra_hosts: - <span>'[onlyoffice domain]:[ipv4]'</span> restart: unless-stopped cron: image: nextcloud:fpm volumes: - <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>nextcloud:<span>/</span>var<span>/</span>www<span>/</span>html user: www-data entrypoint: <span>|</span> <span>bash</span> <span>-c</span> <span>'bash -s &lt;&lt;EOF trap "break;exit" SIGHUP SIGINT SIGTERM while /bin/true; do /usr/local/bin/php /var/www/html/cron.php sleep 900 done EOF'</span> restart: unless-stopped redis: image: redis:alpine command: redis-server <span>--requirepass</span> <span>[</span>redis password<span>]</span> volumes: - <span>/</span>home<span>/</span>data<span>/</span>nextcloud<span>/</span>redis:<span>/</span>data restart: unless-stopped</pre></div></div> <p>The "port" specified above, 8080, for nginx is arbitrary - I picked it to ensure it doesn't don't conflict with ports being used by other containers on my server - you can use this value if you want, or use <code>sudo netstat -punta</code> (you might need to install the package that provides netstat first, <code>sudo apt install net-tools</code>) to see what ports are currently claimed by other services on your server (if there are any) and pick one that doesn't clash! If it scroll past too fast, you can pipe it into less to allow you to scroll and search like this: <code>sudo netstat -punta | less</code> - hit "q" to exit or "/" to initiate a text search. Or, if you want verify that a specific port is not already being used, you can do this (in this case for port 8080) via <code>sudo netstat -punta | grep 8080</code> - if it returns any results, something is already listening on that port. If not, it's available.</p> <h3><a id="user-content-the-nextcloud-nginx-configuration" href="#the-nextcloud-nginx-configuration" name="the-nextcloud-nginx-configuration" class="heading-permalink" aria-hidden="true" title="Permalink"></a>The NextCloud Nginx configuration</h3> <p>You will also need to provide the "nginx.conf" file referenced in the nginx section of the Docker Compose configuration. Do that via</p> <p><code>$EDIT /home/data/nextcloud/nginx/nginx.conf</code></p> <p>and copy-and-paste the following incantation (you shouldn't need to change anything in this one) - there're notes in it offering some explanations:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>worker_processes auto;   error_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span>error.log warn; pid <span>/</span>var<span>/</span>run<span>/</span>nginx.pid;     events <span>{</span> worker_connections <span>1024</span>; <span>}</span>     http <span>{</span> include <span>/</span>etc<span>/</span>nginx<span>/</span>mime.types; default_type application<span>/</span>octet-stream;   log_format main <span>'$remote_addr - $remote_user [$time_local] "$request" '</span> <span>'$status $body_bytes_sent "$http_referer" '</span> <span>'"$http_user_agent" "$http_x_forwarded_for"'</span>;   access_log <span>/</span>var<span>/</span>log<span>/</span>nginx<span>/</span>access.log main;   sendfile on; <span>#tcp_nopush on;</span>   keepalive_timeout <span>65</span>;   set_real_ip_from 10.0.0.0<span>/</span><span>8</span>; set_real_ip_from 172.16.0.0<span>/</span><span>12</span>; set_real_ip_from 192.168.0.0<span>/</span><span>16</span>; real_ip_header X-Real-IP;   <span>#gzip on;</span>   map <span>$http_host</span> <span>$this_host</span> <span>{</span> <span>""</span> <span>$host</span>; default <span>$http_host</span>; <span>}</span>   map <span>$http_x_forwarded_proto</span> <span>$the_scheme</span> <span>{</span> default <span>$http_x_forwarded_proto</span>; <span>""</span> <span>$scheme</span>; <span>}</span>   map <span>$http_x_forwarded_host</span> <span>$the_host</span> <span>{</span> default <span>$http_x_forwarded_host</span>; <span>""</span> <span>$this_host</span>; <span>}</span>   upstream php-handler <span>{</span> server app-server:<span>9000</span>; <span>}</span>   server <span>{</span> listen <span>80</span>;   <span># Add headers to serve security related headers</span> <span># Before enabling Strict-Transport-Security headers please read into this</span> <span># topic first.</span> <span>#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;</span> <span>#</span> <span># WARNING: Only add the preload option once you read about</span> <span># the consequences in https://hstspreload.org/. This option</span> <span># will add the domain to a hardcoded list that is shipped</span> <span># in all major browsers and getting removed from this list</span> <span># could take several months.</span> add_header Referrer-Policy <span>"no-referrer"</span> always; add_header X-Content-Type-Options <span>"nosniff"</span> always; add_header X-Download-Options <span>"noopen"</span> always; add_header X-Frame-Options <span>"SAMEORIGIN"</span> always; add_header X-Permitted-Cross-Domain-Policies <span>"none"</span> always; add_header X-Robots-Tag <span>"noindex, nofollow"</span> always; add_header X-XSS-Protection <span>"1; mode=block"</span> always;   <span># Remove X-Powered-By, which is an information leak</span> fastcgi_hide_header X-Powered-By;   <span># Path to the root of your installation</span> root <span>/</span>var<span>/</span>www<span>/</span>html;   location = <span>/</span>robots.txt <span>{</span> allow all; log_not_found off; access_log off; <span>}</span>   <span># The following 2 rules are only needed for the user_webfinger app.</span> <span># Uncomment it if you're planning to use this app.</span> <span>#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;</span> <span>#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;</span>   <span># The following rule is only needed for the Social app.</span> <span># Uncomment it if you're planning to use this app.</span> <span>#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;</span>   location = <span>/</span>.well-known<span>/</span>carddav <span>{</span> <span>return</span> <span>301</span> <span>$scheme</span>:<span>//</span><span>$host</span>:<span>$server_port</span><span>/</span>remote.php<span>/</span>dav; <span>}</span>   location = <span>/</span>.well-known<span>/</span>caldav <span>{</span> <span>return</span> <span>301</span> <span>$scheme</span>:<span>//</span><span>$host</span>:<span>$server_port</span><span>/</span>remote.php<span>/</span>dav; <span>}</span>   <span># set max upload size</span> client_max_body_size 10G; fastcgi_buffers <span>64</span> 4K;   <span># Enable gzip but do not remove ETag headers</span> <span>gzip</span> on; gzip_vary on; gzip_comp_level <span>4</span>; gzip_min_length <span>256</span>; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_types application<span>/</span>atom+xml application<span>/</span>javascript application<span>/</span>json application<span>/</span><span>ld</span>+json application<span>/</span>manifest+json application<span>/</span>rss+xml application<span>/</span>vnd.geo+json application<span>/</span>vnd.ms-fontobject application<span>/</span>x-font-ttf application<span>/</span>x-web-app-manifest+json application<span>/</span>xhtml+xml application<span>/</span>xml font<span>/</span>opentype image<span>/</span>bmp image<span>/</span>svg+xml image<span>/</span>x-icon text<span>/</span>cache-manifest text<span>/</span>css text<span>/</span>plain text<span>/</span>vcard text<span>/</span>vnd.rim.location.xloc text<span>/</span>vtt text<span>/</span>x-component text<span>/</span>x-cross-domain-policy;   <span># Uncomment if your server is build with the ngx_pagespeed module</span> <span># This module is currently not supported.</span> <span>#pagespeed off;</span>   location <span>/</span> <span>{</span> rewrite ^ <span>/</span>index.php; <span>}</span>   location ~ ^\<span>/</span><span>(</span>?:build<span>|</span>tests<span>|</span>config<span>|</span>lib<span>|</span>3rdparty<span>|</span>templates<span>|</span>data<span>)</span>\<span>/</span> <span>{</span> deny all; <span>}</span> location ~ ^\<span>/</span><span>(</span>?:\.<span>|</span>autotest<span>|</span>occ<span>|</span>issue<span>|</span>indie<span>|</span>db_<span>|</span>console<span>)</span> <span>{</span> deny all; <span>}</span>   location ~ ^\<span>/</span><span>(</span>?:index<span>|</span>remote<span>|</span>public<span>|</span>cron<span>|</span>core\<span>/</span>ajax\<span>/</span>update<span>|</span>status<span>|</span>ocs\<span>/</span>v<span>[</span><span>12</span><span>]</span><span>|</span>updater\<span>/</span>.+<span>|</span>oc<span>[</span>ms<span>]</span>-provider\<span>/</span>.+<span>)</span>\.php<span>(</span>?:$<span>|</span>\<span>/</span><span>)</span> <span>{</span> fastcgi_split_path_info ^<span>(</span>.+?\.php<span>)</span><span>(</span>\<span>/</span>.<span>*|</span><span>)</span>$; <span>set</span> <span>$path_info</span> <span>$fastcgi_path_info</span>; try_files <span>$fastcgi_script_name</span> =<span>404</span>; include fastcgi_params; fastcgi_param SCRIPT_FILENAME <span>$document_root</span><span>$fastcgi_script_name</span>; fastcgi_param PATH_INFO <span>$path_info</span>; <span># fastcgi_param HTTPS on;</span>   <span># Avoid sending the security headers twice</span> fastcgi_param modHeadersAvailable <span>true</span>;   <span># Enable pretty urls</span> fastcgi_param front_controller_active <span>true</span>; fastcgi_pass php-handler; fastcgi_intercept_errors on; fastcgi_request_buffering off; <span>}</span>   location ~ ^\<span>/</span><span>(</span>?:updater<span>|</span>oc<span>[</span>ms<span>]</span>-provider<span>)</span><span>(</span>?:$<span>|</span>\<span>/</span><span>)</span> <span>{</span> try_files <span>$uri</span><span>/</span> =<span>404</span>; index index.php; <span>}</span>   <span># Adding the cache control header for js, css and map files</span> <span># Make sure it is BELOW the PHP block</span> location ~ \.<span>(</span>?:css<span>|</span>js<span>|</span>woff2?<span>|</span>svg<span>|</span>gif<span>|</span>map<span>)</span>$ <span>{</span> try_files <span>$uri</span> <span>/</span>index.php<span>$request_uri</span>; add_header Cache-Control <span>"public, max-age=15778463"</span>; <span># Add headers to serve security related headers (It is intended to</span> <span># have those duplicated to the ones above)</span> <span># Before enabling Strict-Transport-Security headers please read into</span> <span># this topic first.</span> <span>#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;</span> <span>#</span> <span># WARNING: Only add the preload option once you read about</span> <span># the consequences in https://hstspreload.org/. This option</span> <span># will add the domain to a hardcoded list that is shipped</span> <span># in all major browsers and getting removed from this list</span> <span># could take several months.</span> add_header Referrer-Policy <span>"no-referrer"</span> always; add_header X-Content-Type-Options <span>"nosniff"</span> always; add_header X-Download-Options <span>"noopen"</span> always; add_header X-Frame-Options <span>"SAMEORIGIN"</span> always; add_header X-Permitted-Cross-Domain-Policies <span>"none"</span> always; add_header X-Robots-Tag <span>"noindex, nofollow"</span> always; add_header X-XSS-Protection <span>"1; mode=block"</span> always;   <span># Optional: Don't log access to assets</span> access_log off; <span>}</span>   location ~ \.<span>(</span>?:png<span>|</span>html<span>|</span>ttf<span>|</span>ico<span>|</span>jpg<span>|</span>jpeg<span>|</span>bcmap<span>|</span>mp4<span>|</span>webm<span>)</span>$ <span>{</span> try_files <span>$uri</span> <span>/</span>index.php<span>$request_uri</span>; <span># Optional: Don't log access to other assets</span> access_log off; <span>}</span> add_header Strict-Transport-Security <span>"max-age=31536000; includeSubdomains;"</span>; <span>}</span> <span>}</span></pre></div></div> <p>That should be all the configuration you need to make the NextCloud Docker containers go.</p> <h3><a id="user-content-the-onlyoffice-docker-configuration" href="#the-onlyoffice-docker-configuration" name="the-onlyoffice-docker-configuration" class="heading-permalink" aria-hidden="true" title="Permalink"></a>The OnlyOffice Docker configuration</h3> <p>We also need to something similar (but easier) for OnlyOffice. This is the docker-compose.yml that I use:</p> <p><code>cd /home/docker/onlyoffice</code> <code>$EDIT docker-compose.yml</code></p> <p>and copy-and-paste this into it (replacing the []):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>version: <span>'3'</span> services: onlyoffice: image: onlyoffice<span>/</span>documentserver:latest restart: unless-stopped ports: - 127.0.0.1:<span>9880</span>:<span>80</span> environment: <span># - JWT_SECRET=[onlyoffice secret]</span> volumes: - <span>/</span>home<span>/</span>data<span>/</span>onlyoffice<span>/</span>data:<span>/</span>var<span>/</span>www<span>/</span>onlyoffice<span>/</span>Data - <span>/</span>home<span>/</span>data<span>/</span>onlyoffice<span>/</span>logs:<span>/</span>var<span>/</span>log<span>/</span>onlyoffice - <span>/</span>home<span>/</span>data<span>/</span>onlyoffice<span>/</span>lib:<span>/</span>var<span>/</span>lib<span>/</span>onlyoffice - <span>/</span>home<span>/</span>data<span>/</span>onlyoffice<span>/</span>db:<span>/</span>var<span>/</span>lib<span>/</span>postgresql extra_hosts: - <span>"[nextcloud domain]:[ipv4]"</span></pre></div></div> <p>Now, we can fire it up provisionally:</p> <p><code>docker-compose up -d &amp;&amp; docker-compose logs -f</code></p> <p>We'll find the value of [onlyoffice secret] a bit later, below.</p> <p>To get back to a command prompt without killing the running Docker container execute a <code>CTRL-C</code>.</p> <h2><a id="user-content-firing-up-your-nextcloud" href="#firing-up-your-nextcloud" name="firing-up-your-nextcloud" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Firing up your NextCloud!</h2> <p>Phew - congratulations on getting here! We've reached the moment of truth where we need to see if this whole thing will work!</p> <p>We need to make sure we're back in the NextCloud Docker directory we set up:</p> <p><code>cd /home/docker/nextcloud</code></p> <p>Then you can run:</p> <p><code>docker-compose up -d &amp;&amp; docker-compose logs -f</code></p> <p>This will trigger the initial download of the docker container images you've specified in your <code>docker-compose.yml</code> file. All going well, after a few minutes (longer or shorter depending on the speed of your server's connection) you should have download the Nginx, Redis, and NextCloud Docker images, and then the script will attempt to start them (bringing them "up" in daemon mode with the -d, meaning they'll keep running even if you log out) and then, if successful, the <code>logs -f</code> command will run and show you a stream of log messages from the containers, each preceded by the container name to which it corresponds. This should help you debug any problems that occur during the process (ideally, none).</p> <p>Once you see log messages streaming past, and no obvious "container exited" or other error messages (which will usually contain the word "error" a lot), you should be able to point your browser at your selected domain name and have your fist visit to your NextCloud in your browser! Just point your web browser at https://[nextcloud domain] (replacing with your domain, of course. You should also try going to http://[nextcloud domain] (note the missing 's' from http) which should automatically <em>redirect</em> you to https://[nextcloud domain] as the reverse proxy file instructs.</p> <p>Again, to get back to a command prompt without killing the running Docker containers execute a <code>CTRL-C</code>.</p> <h3><a id="user-content-the-nextcloud-source-code-if-necessary" href="#the-nextcloud-source-code-if-necessary" name="the-nextcloud-source-code-if-necessary" class="heading-permalink" aria-hidden="true" title="Permalink"></a>The NextCloud source code (if necessary)</h3> <p><strong>Normally the source code for NextCloud's current stable version is transparently downloaded and installed by the NextCloud Docker container the first time it's instantiated</strong>. If it is, you'll see a bunch of files and directories in your <code>/home/data/nextcloud/nextcloud</code> folder. If so, you're fine and you can move on to the next step.</p> <p>If not, you can always find the most recent stable release's <a href="https://nextcloud.com/install/#instructions-server">source code here</a>. I tend to prefer the .tar.bz2 archive format, so I get it from this link: <a href="https://download.nextcloud.com/server/releases/latest.tar.bz2">https://download.nextcloud.com/server/releases/latest.tar.bz2</a> (which, fingers crossed, should remain valid indefinitely - if not, check the previous link or look for 'Download' on the <a href="https://nextcloud.com">NextCloud website</a>.).</p> <p>We need to get that file and extract it in <code>/home/data/nextcloud</code>, so do the following (if <code>wget</code> isn't already installed, get it via <code>sudo apt install wget</code>):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>cd</span> <span>/</span>home<span>/</span>data<span>/</span>nextcloud <span>wget</span> https:<span>//</span>download.nextcloud.com<span>/</span>server<span>/</span>releases<span>/</span>latest.tar.bz2 <span>tar</span> xvfj latest.tar.bz2</pre></div></div> <p>which will create a directory 'nextcloud' with the latest (stable) version of the NextCloud source code in that directory.</p> <p>Then reassert the file permissions just to be sure</p> <p><code>sudo chown -R www-data nextcloud</code></p> <p>After that, you should be able to point your browser at your domain (the containers are already running) and see if it starts the install process as it should. [/code]</p> <p>You can figure out what version that is by running:</p> <p><code>cat nextcloud/version.php | grep VersionString</code></p> <p>With my latest install, I get the result:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>$</span>OC_VersionString = <span>'26.0.2'</span>;</pre></div></div> <p>Note, I tend to hold on to install archives for safety's sake, so I generally do the following to tidy up (still in the nextcloud data directory), replacing [version] with the advertised most recent stable version of NextCloud (26.0.2 in my case):</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>mkdir</span> attic <span>mv</span> latest.tar.bz2 attic<span>/</span>nextcloud_<span>[</span>version<span>]</span>.tar.bz2</pre></div></div> <p>Now you've got the source code for NextCloud where you containers are configured to look for it!</p> <h2><a id="user-content-configuring-database-access" href="#configuring-database-access" name="configuring-database-access" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring database access</h2> <p>On doing so, if all is well, you should be directed through the database set up process for your NextCloud instance. You'll be asked for your database details, which should be:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>database IP: 172.17.0.1 - this is the default IP of the Docker host server. database name: <span>[</span>db name<span>]</span> database user: <span>[</span>db user<span>]</span> database password: <span>[</span>db password<span>]</span></pre></div></div> <h2><a id="user-content-configuring-the-admin-user" href="#configuring-the-admin-user" name="configuring-the-admin-user" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring the Admin user</h2> <p>Once that's set and working, NextCloud will install all the relevant database tables and initial data. You'll be asked to set up an admin user account, which can be "admin" and some strong password you create (you can use the <code>pwgen</code> utility you used earlier) - I'd recommend recording it somewhere. <em>I would not recommend making your own account, in your name, the main admin account</em>. Instead, I recommend creating a second account, <em>with administrator privileges</em>, for yourself, but leave the admin account purely for administrative activities.</p> <h2><a id="user-content-configuring-outgoing-email" href="#configuring-outgoing-email" name="configuring-outgoing-email" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring Outgoing Email</h2> <p>To allow your NextCloud instance to send outgoing email, so that your site can alert you to security updates that need to be applied, or so that any of your NextCloud users can request a password reset if they've forgot theirs. For this, you'll need the authenticating SMTP account details from the start of this process. You'll need:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre>SMTP server : an IP address or a domain name SMTP username: a username or an email address SMTP password: a strong password already configured <span>for</span> the username on that server SMTP <span>login</span> security: whether <span>login</span> is via TLS, SSL, or unsecure <span>(</span><span>!!</span><span>)</span>, and SMTP <span>login</span> method: plain, encrypted, <span>"login"</span> or some other value.</pre></div></div> <p>You should be able to test your email settings to make sure the details you've entered are valid. If you need to adjust these settings later, you can go to the admin menu (top right of the web browser interface) and go to Admin-&gt;Basic Settings - should have a path of <code>https://[nextcloud domain]/settings/admin</code>.</p> <h2><a id="user-content-setting-up-onlyoffice" href="#setting-up-onlyoffice" name="setting-up-onlyoffice" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Setting up OnlyOffice</h2> <p>The OnlyOffice server should already be running - if you point your browser at <code>https://[onlyoffice domain]</code> you should see a page like the attached screenshot with the OnlyOffice Logo and a title of "OnlyOffice Docs Community Edition".</p> <h2><a id="user-content-configuring-onlyoffice-integration-with-nextcloud" href="#configuring-onlyoffice-integration-with-nextcloud" name="configuring-onlyoffice-integration-with-nextcloud" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Configuring OnlyOffice Integration with NextCloud</h2> <p>To configure your NextCloud to use your OnlyOffice, the OnlyOffice will require that NextCloud knows its "secret". To generate the secret, run this in <code>/home/docker/onlyoffice</code>:</p> <p><code>docker-compose exec onlyoffice /var/www/onlyoffice/documentserver/npm/json -f /etc/onlyoffice/documentserver/local.json 'services.CoAuthoring.secret.session.string'</code></p> <p>The resulting <em>secret</em> string, which will look something like <code>QC7QmEqUpXmmnwXZcvBQ</code> needs to be added to your OnlyOffice docker-compose.yml file to ensure that the same code is used everytime you start OnlyOffice (if it isn't set, it'll be generated each time you restart OnlyOffice and your NextCloud will need a different 'secret' each time - a major inconvenience).</p> <p><code>$EDIT /home/docker/onlyoffice/docker-compose.yml</code></p> <p>Add it in place of [onlyoffice secret] <em>and also remove the '#' that's commenting out the line</em> - again, thanks to Stephen Harlow for pointing out that this is required! Then restart OnlyOffice via</p> <p><code>docker-compose up -d</code></p> <p>Docker will see that the container's configuration has changed and will restart the container.</p> <p>Next you need to be logged into your NextCloud as an administartive user (your own user is fine if you've given it admin privileges).</p> <p>You should have an "admin" menu (assuming you've created your user with Administrator privileges) at the top right of the web interface. If you go to Apps, you can install the new "Hub bundle" available under the "App bundles" option (see attached image). If you don't want the whole bundle you can just use the search box to search for "OnlyOffice" or go to the "Office &amp; text" App category and enable the OnlyOffice "official" app, at which point it will automatically download the latest version of the connector app and install it (it should appear in your /home/data/nextcloud/apps directory)</p> <p>Once you've done that, go to your top right menu again, selecting Admin, and you should see "OnlyOffice" as an option in the left column (which starts with "Basic settings"). Selecting that, you'll need to enter the following:</p> <div class="geshifilter"><div class="bash geshifilter-bash"><pre><span>"Document Editing Service address"</span>: https:<span>//</span><span>[</span>onlyoffice domain<span>]</span> <span>"Secret key"</span>: <span>[</span>onlyoffice secret<span>]</span></pre></div></div> <p>You don't need the 'advanced settings'.</p> <p>When you're done, click "Save".</p> <p>You can also select formats you'd like OnlyOffice to open and edit files of those types are clicked or created. I've selected the following: doc, docx, odp, ods, odt, ppt, pptx, xls, xlsx, and in the second section: csv and txt.</p> <p>You can also make other editor customisations as you desire. The only Editor customisation setting I haven't selected is "Display Chat menu button" because NextCloud Hub provides an integrated Chat service, making this one within OnlyOffice an unnecessary distraction.</p> <p>Once finished configuring, you should have the ability to go back to the home of your NextCloud install, which should show you your top-level folders. If you click the "+" next to the home icon (top left of the folder pane) you should now have the option to create (in addition to "Upload file", "New folder", "New text file") a "New Document", "New Spreadsheet", and "New Presentation". Clicking those should give you the OnlyOffice interface for the designated content type.</p> <p>Similarly, you can use the "Upload file" to upload a document in a format that is supported by OnlyOffice. Once uploaded, clicking on the filename should open it for editing in the appropriate OnlyOffice interface.</p> <p>It is saved as it is changed, so you shouldn't need to save it explicitly.</p> <h2><a id="user-content-keeping-the-whole-thing-up-to-date" href="#keeping-the-whole-thing-up-to-date" name="keeping-the-whole-thing-up-to-date" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Keeping the whole thing up-to-date</h2> <p>So, as you're no doubt aware, both NextCloud and OnlyOffice are always being improved and updated. I certainly encourage you to keep your installations up-to-date.</p> <p>While you'll periodically be alerted that NextCloud apps have available updates (these can be upgraded through the browser interface) updates to the NextCloud and OnlyOffice systems themselves need to be undertaken by upgrading their containers. Luckily it's easy to do although I strongly urge you to ensure you have a very recent backup of both database and uploaded files - they're the files in <code>/home/data/nextcloud/data</code> and <code>/home/data/onlyoffice/</code> (note, backups of OnlyOffice are complicated somewhat by the fact that you can't reliably back up running PostgreSQL instance simply by backing up its files - see a solution below). Prior to updating my containers, I normally create an archive of my NextCloud code in the event the upgrade goes wrong and I need to recover quickly. I do it like this. In my <code>/home/data/nextcloud</code> directory, I create a new 'attic' directory:</p> <p><code>cd /home/data/nextcloud &amp;&amp; sudo mkdir attic</code></p> <p>then I create an archive of my entire NextCloud source directory in the attic directory:</p> <p><code>DATE=</code>date +%Y%m%d<code> &amp;&amp; sudo tar cvfz attic/nextcloud-${DATE}.tgz --exclude "data" nextcloud</code></p> <p>If you need to recover files from it, you can untar it (assuming you have sufficient disk space! Best to be mindful of that!) via</p> <p><code>sudo mkdir tmp &amp;&amp; cd tmp &amp;&amp; tar xvfz ../attic/nextcloud-${DATE}.tgz</code></p> <p>although if you're doing it in a different SSH session (e.g. after the fact) you might have to manually enter the DATE part of the filename.</p> <p>Once you've got a backup of your NextCloud source code, updating the container should be as easy as either doing another</p> <p><code>docker-compose pull</code></p> <p>and then restarting the service with the new containers via</p> <p><code>docker-compose up -d</code></p> <p>which will remove any old containers (this won't remove any data you want to save if you followed the directions above! But remember to do it in the right directory!) and start up the new versions you've just pulled.</p> <p>Use <code>docker-compose logs -f</code> to watch the logs - you'll likely see useful debugging information in the unlikely event that something goes wrong in the upgrade process.</p> <h2><a id="user-content-backing-up-nextcloud" href="#backing-up-nextcloud" name="backing-up-nextcloud" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Backing up NextCloud</h2> <p>To back up your instance on your server, you need two things: a file system backup of your <code>/home/data/nextcloud</code> directory, and database dumps of your database.</p> <p>There're lots of ways to back up your files (I've recently updated to using a system called Restic to make off-server incremental encrypted backups - I plan to document this in a future howto! - although there're other documented approaches - leave a comment below if you'd like to learn more about my approach!).</p> <p>Backing up your MariaDB databases is as easy installing automysqlbackups:</p> <p><code>sudo apt install automysqlbackups</code></p> <p>You'll find daily versioned dumps of your MariaDB database(s) in /var/lib/automysqlbackups on your VM host's filesystem. To run an ad hoc backup (which will replace the previous backup from that day, if there is one) just run</p> <p><code>sudo automysqlbackups</code></p> <h2><a id="user-content-backup-onlyoffice" href="#backup-onlyoffice" name="backup-onlyoffice" class="heading-permalink" aria-hidden="true" title="Permalink"></a>Backup OnlyOffice</h2> <p>Along with backing up the files in your <code>/home/data/onlyoffice</code> directory, you'll also want a proper "dump" of your PostgreSQL backup (you can write simple bash scripts to do this regularly, automatically), particularly prior to doing an upgrade (to allow for recovery if something goes badly wrong, which is always possible). You can achieve this by going to</p> <p><code>cd /home/docker/onlyoffice</code></p> <p>and running this</p> <p><code>DATE=$(date +%Y%m%d) &amp;&amp; FILE=/home/data/onlyoffice/backup/fullbackup-${DATE}.sql &amp;&amp; docker-compose exec onlyoffice sudo -u postgres pg_dumpall &gt; ${FILE} &amp;&amp; gzip ${FILE}</code></p> <p>which will assign the current date to DATE, the relevant filename to FILE, and then put the backup SQL into a dated file called $FILE and compress the result with gzip :)</p> <p>At some point, I'll modify my normal versioned PostgreSQL-in-a-Docker-Container dated database backup scripts to cater for this solution and make the result available on <a href="https://git.oeru.org">https://git.oeru.org</a> - it'll probably be a small modification to this script: <a href="https://git.oeru.org/oeru/docker-compose-dbbackup">https://git.oeru.org/oeru/docker-compose-dbbackup</a> in case someone wants to beat me to it!</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=56&amp;2=field_blog_comments&amp;3=comment" token="TVFnCS25aCQNEoXgVru9brw8N6CW8SDeKyXkrmV0rJI"></drupal-render-placeholder> </div> </section> Sun, 28 May 2023 23:50:43 +0000 dave 56 at http://tech.oeru.org Installing NextCloud Hub with OnlyOffice on Ubuntu 18.04 http://tech.oeru.org/installing-nextcloud-hub-onlyoffice-ubuntu-1804 <span class="field field--name-title field--type-string field--label-hidden">Installing NextCloud Hub with OnlyOffice on Ubuntu 18.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--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--_804"> <span class="field__item-wrapper"><a href="/taxonomy/term/68" hreflang="en">18.04</a></span> </div> <div class="field__item field__item--nextcloud"> <span class="field__item-wrapper"><a href="/taxonomy/term/51" hreflang="en">nextcloud</a></span> </div> <div class="field__item field__item--onlyoffice"> <span class="field__item-wrapper"><a href="/taxonomy/term/69" hreflang="en">onlyoffice</a></span> </div> <div class="field__item field__item--mariadb"> <span class="field__item-wrapper"><a href="/taxonomy/term/48" hreflang="en">mariadb</a></span> </div> <div class="field__item field__item--docker-compose"> <span class="field__item-wrapper"><a href="/taxonomy/term/25" hreflang="en">docker compose</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--php"> <span class="field__item-wrapper"><a href="/taxonomy/term/40" hreflang="en">php</a></span> </div> <div class="field__item field__item--redis"> <span class="field__item-wrapper"><a href="/taxonomy/term/21" hreflang="en">redis</a></span> </div> <div class="field__item field__item--polls"> <span class="field__item-wrapper"><a href="/taxonomy/term/70" hreflang="en">polls</a></span> </div> <div class="field__item field__item--scheduling"> <span class="field__item-wrapper"><a href="/taxonomy/term/71" hreflang="en">scheduling</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" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Tue 04/02/2020 - 09:41</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/2020-02/Screenshot_2020-02-11-2%20file-sample_1MB%20docx%20-%20Lane%20NextCloud.png?itok=bqhSZGni" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Sample DOCX file being edited in open source OnlyOffice&quot;}" role="button" title="Sample DOCX file being edited in open source OnlyOffice" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sample DOCX file being edited in open source OnlyOffice&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-11-2%20file-sample_1MB%20docx%20-%20Lane%20NextCloud.png?itok=OW_2e1WM" width="220" height="140" alt="Sample DOCX file being edited in open source OnlyOffice" loading="lazy" 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/2020-02/Screenshot_2020-02-11%20Digital%20Storage%20Weight%20and%20Volume%20xlsx%20-%20Lane%20NextCloud.png?itok=luaOg5rt" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Sample XLSX file being edited in open source OnlyOffice&quot;}" role="button" title="Sample XLSX file being edited in open source OnlyOffice" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sample XLSX file being edited in open source OnlyOffice&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-11%20Digital%20Storage%20Weight%20and%20Volume%20xlsx%20-%20Lane%20NextCloud.png?itok=CZcvoi7c" width="220" height="140" alt="Sample XLSX file being edited in open source OnlyOffice" loading="lazy" 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/2020-02/Screenshot_2020-02-11%20file-sample_1MB%20docx%20-%20Lane%20NextCloud.png?itok=GzQZ26uC" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Another example of DOCX file being edited in open source OnlyOffice&quot;}" role="button" title="Another example of DOCX file being edited in open source OnlyOffice" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Another example of DOCX file being edited in open source OnlyOffice&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-11%20file-sample_1MB%20docx%20-%20Lane%20NextCloud.png?itok=9KcMLR4t" width="220" height="140" alt="Another example of DOCX file being edited in open source OnlyOffice" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-4"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-11%20Files%20-%20OERu%20NextCloud.png?itok=Zm3uP_wT" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Sample of web-view of NextCloud files and folders.&quot;}" role="button" title="Sample of web-view of NextCloud files and folders." data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sample of web-view of NextCloud files and folders.&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-11%20Files%20-%20OERu%20NextCloud.png?itok=Bpnx2qg6" width="220" height="155" alt="Sample of web-view of NextCloud files and folders." loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-5"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-11%20Polls%20-%20NZOSS%20Nextcloud.png?itok=Fp17si_J" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;A sample NextCloud Poll (alternative to Doodle Polls) for scheduling. Yes, it&#039;s timezone-aware!&quot;}" role="button" title="A sample NextCloud Poll (alternative to Doodle Polls) for scheduling. Yes, it&#039;s timezone-aware!" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;A sample NextCloud Poll (alternative to Doodle Polls) for scheduling. Yes, it&#039;s timezone-aware!&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-11%20Polls%20-%20NZOSS%20Nextcloud.png?itok=8rpIpQne" width="220" height="154" alt="A sample NextCloud Poll (alternative to Doodle Polls) for scheduling. Yes, it&#039;s timezone-aware!" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-6"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-12%20ONLYOFFICE%E2%84%A2.png?itok=04xrGCN1" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;If your onlyoffice.domain server is working, this is what you should see in your browser!&quot;}" role="button" title="If your onlyoffice.domain server is working, this is what you should see in your browser!" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;If your onlyoffice.domain server is working, this is what you should see in your browser!&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-12%20ONLYOFFICE%E2%84%A2.png?itok=1I3F7Cbi" width="220" height="187" alt="If your onlyoffice.domain server is working, this is what you should see in your browser!" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-7"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-13%20Apps%20-%20NZOSS%20Nextcloud.png?itok=Io3v-pzT" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The NextCloud &quot;app&quot; configuration page&quot;}" role="button" title="The NextCloud &quot;app&quot; configuration page" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The NextCloud &quot;app&quot; configuration page&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-13%20Apps%20-%20NZOSS%20Nextcloud.png?itok=VGORRtXl" width="103" height="220" alt="The NextCloud &quot;app&quot; configuration page" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-8"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-13%20Settings%20-%20NZOSS%20Nextcloud.png?itok=8sZGBrtG" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The NextCloud settings page. &quot;}" role="button" title="The NextCloud settings page. " data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The NextCloud settings page. &quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-13%20Settings%20-%20NZOSS%20Nextcloud.png?itok=98LUc9zv" width="220" height="163" alt="The NextCloud settings page. " loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-9"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-13%20Settings%20-%20OnlyOffice%20-%20NZOSS%20Nextcloud_0.png?itok=KwWWWKUT" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;The &quot;OnlyOffice&quot; app configuration page for NextCloud&quot;}" role="button" title="The &quot;OnlyOffice&quot; app configuration page for NextCloud" data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;The &quot;OnlyOffice&quot; app configuration page for NextCloud&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-13%20Settings%20-%20OnlyOffice%20-%20NZOSS%20Nextcloud_0.png?itok=JdKSA022" width="220" height="189" alt="The &quot;OnlyOffice&quot; app configuration page for NextCloud" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-10"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2020-02/Screenshot_2020-02-21%20App%20Bundles-%20OERu%20NextCloud.png?itok=3N1GtflH" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;NextCloud App Bundle configuration page.&quot;}" role="button" title="NextCloud App Bundle configuration page." data-colorbox-gallery="gallery-field_image-33yzROn9I9M" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;NextCloud App Bundle configuration page.&quot;}"><img src="/sites/default/files/styles/medium/public/2020-02/Screenshot_2020-02-21%20App%20Bundles-%20OERu%20NextCloud.png?itok=c1_0PwiH" width="220" height="141" alt="NextCloud App Bundle configuration page." loading="lazy" 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><strong>Update 2023-06-14</strong>: Here's a <a href="/node/56">new tutorial for Ubuntu 22.04</a>! Consider this older tutorial obsolete (but possibly helpful for people with older systems?)</p> <p>I have previously provided an <a href="/installing-nextcloud-and-collabora-office-online-docker-ubuntu-1604">in-depth explanation about NextCloud with Collabora Office Online and how we've installed it on Ubuntu 16.04</a>. This is an update both of the process, and of the technology. NextCloud is leaping from strength to strength, and seems to be <a href="https://nextcloud.com/blog/eu-governments-choose-independence-from-us-cloud-providers-with-nextcloud/">benefiting from</a> the well-founded concern held by many in the EU about data sovereignty and the market domination (and exploitation) of US-based multinationals like Amazon, Google, Microsoft, Dropbox, and others. As a collaborative, web-based front end to LibreOffice, Collabora shows great potential... but it's not anywhere near the capabilities of Google Docs...</p> <p>The same, however, is not true of a relatively new entry into the web-based collaborative productivity application space: <a href="https://www.onlyoffice.com/">OnlyOffice</a>. The application itself (for the tech focused reader, they've built an entirely <a href="https://github.com/ONLYOFFICE/">new application ecosystem</a> primarily using modern Javascript frameworks)  is impressive in both capabilities and polish. The only real caveat I've come across is that it uses, by default, the <a href="https://openstandards.nz/case-study-microsofts-ooxml-standard">fauxpen standard formats</a> developed by Microsoft rather than the true open standard formats of <a href="https://en.wikipedia.org/wiki/OpenDocument">OpenDocumentFormat</a>. But in a world where, sadly, most people don't even know what a file format is, any software that doesn't read and write the incumbent monopolist's format with great fidelity is dead in the water.  On that count, OnlyOffice is impressive.</p> <h2>NextCloud and OnlyOffice - even better together!</h2> <p>The beauty of the open source software model is that we can connect complementary applications, like NextCloud and OnlyOffice - developed by completely separate communities - to create a tightly integrated, highly functional, diverse computing platform. This combination, along with a bunch of other NextCloud "apps", is the equal of something like Google Apps (which includes Google Docs and Google Drive), but is <em>under your control, not Google's.</em> To me, that's a crucial difference. </p> <p>With the release of NextCloud 18.0.1, NextCloud has bundled OnlyOffice with it, creating something called "<a href="https://nextcloud.com/hub/">NextCloud Hub</a>". It's pretty impressive. That's what we're setting up here!</p> <h2>Setting up your own NextCloud Hub!</h2> <p>Yes, NextCloud and OnlyOffice servers on the same host.</p> <p>If you're game to run your own (and, in my experience, it's a surprisingly well behaved system) here's how you do it.</p> <p>In preparation, you'll want to have the following ready:</p> <ul><li>a Linux virtual machine or "VM" (I recommend running the current Ubuntu LTS version, or current Debian) with an external IP address and a user with sudo privileges - <a href="/setting-your-own-bitwarden-password-keeper-and-sync-server">more info on that</a>...,</li> <li>your domain name for the NextCloud instance, pointing to the IP address of your VM,</li> <li>credentials for an email address capable of sending from a remote server (usually termed an "<a href="/configuring-linux-server-send-email-postfix-smtp-server">authenticating SMTP email account</a>")</li> </ul><p>Please note: the images accompanying this howto have been pulled from several different NextCloud and OnlyOffices I maintain.</p> <h3>Secure access with SSH</h3> <p>First things first, make sure you're logged into your host (probably via SSH) as a user who has "sudo" capabilities! You need to log into the host from your local machine. We recommend setting up <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server">key-based authentication</a>.</p> <h3>Firewall with UFW</h3> <p>No computer system is ever full secure - there're always exploits waiting to be found, so security is a process of maintaining vigilance. Part of that is reducing exposure - minimising your "attack surface". Use a firewall - "<a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-16-04" title="Uncomplicated FireWall">ufw</a>" is installed on Ubuntu by default. Make sure you've got exceptions for SSH (without them, you could lock yourself out of your machine! Doh!).</p> <p>Run the following commands to allow your Docker containers to talk to other services on your host.</p> <p><code>sudo ufw allow in on docker0<br /> sudo ufw allow from 172.0.0.0/8 to any</code></p> <p>Specifically for Docker's benefit, you need to tweak the default Forwarding rule (I use "vim" as my editor. If you don't know how to/want to use it, replace <strong>vim</strong> with <strong>nano</strong> everywhere you see it in the following - nano's easier to use for simple edits like this):</p> <p><code>sudo vim /etc/default/ufw</code></p> <p>and duplicate (copy and paste it) the line <code>DEFAULT_FORWARD_POLICY="DROP"</code> tweak it to look like this (commenting out the default, but leaving it there for future reference, so you know what you've changed!):</p> <p><code>#DEFAULT_FORWARD_POLICY="DROP"<br /> DEFAULT_FORWARD_POLICY="ACCEPT"</code></p> <p>You also have to edit <code>/etc/ufw/sysctl.conf</code> and remove the "#" at the start of the following lines, so they look like this:</p> <p><code>sudo vim /etc/ufw/sysctl.conf</code></p> <p><code># Uncomment this to allow this host to route packets between interfaces<br /> net/ipv4/ip_forward=1<br /> net/ipv6/conf/default/forwarding=1<br /> net/ipv6/conf/all/forwarding=1</code></p> <p>and finally restart the network stack and ufw on your server<code> </code></p> <p><code>sudo service networking restart<br /> sudo service ufw restart</code></p> <h3>Installing the Nginx webserver</h3> <p>In the configuration I'm describing here, you'll need a webserver running on the server - it'll be acting as a "proxy" for the Docker-based Nginx instance described below. I like the efficiency of Nginx and clarity of Nginx configurations over those of Apache and other open source web servers. Here's how you install it.</p> <p><code>sudo apt-get install nginx-full</code></p> <p>To allow nginx to be visible via ports 80 and 443, run</p> <p><code>sudo ufw allow "Nginx Full"</code></p> <p><strong>Note</strong>: make sure your hosting service is not blocking these ports at some outer layer (depending on who's providing that hosting service you may have to set up port forwarding).</p> <h3>Installing MariaDB</h3> <p>MariaDB is effectively a drop-in alternative to MySQL and we prefer it because it's not controlled by Oracle and has a more active developer community. On Ubuntu, MariaDB pretends to be MySQL for compatibility purposes, so don't be weirded out by the interchangeable names below. Install the server and the client like this.</p> <p><code>sudo apt-get install mariadb-server-10.0 mariadb-client-10.0</code></p> <p>You need to set a root (admin) user password - you might want to create a /root/.my.cnf file containing the following (replacing YOURPASSWORD) to let you access MariaDB without a password from the commandline<code>:</code></p> <p><code>[client]<br /> user=root<br /> password=YOURPASSWORD</code></p> <p>You should now be able to type "mysql" at the command prompt</p> <p>Tweak the configuration so that it's listening on</p> <p><code>sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf </code></p> <p>and copy the bind-address line and adjust so it looks like this - we want MariaDB to be listening on all interfaces, not just localhost (127.0.0.1)...</p> <p><code># Instead of skip-networking the default is now to listen only on<br /> # localhost which is more compatible and is not less secure.<br /> #bind-address           = 127.0.0.1<br /> bind-address            = 0.0.0.0</code></p> <p>Then restart MariaDB:</p> <p><code>sudo service mysql restart</code></p> <p>It should now be listening on port 3306 on all interfaces, i.e. 0.0.0.0.</p> <p>Now set up the database which will hold NextCloud's data. Log into the MySQL client on the host (if you've created a .my.cnf file in your home directory as describe above, you won't need to enter your username and password):</p> <p><code>mysql -u root -p</code></p> <p>Enter your root password when prompted. It's also a good idea to gin up a password for your "nextcloud" database user. I usually use pwgen (<code>sudo apt-get install pwgen</code>) - for example running this command will give you a single 19 character password without special characters (just numbers and letters):</p> <p><code>pwgen -s 19 1</code></p> <p>Giving you something like this (but if it's truly random, almost <em>certainly not exactly </em>this):</p> <p>bYIOSrvR9aGwL5FRGFU</p> <p>At the prompt (which will look something like <code>MariaDB [(none)]&gt;</code>) enter the following lines (putting your password in place of [passwd]):</p> <p><code>CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;<br /> CREATE USER "nextcloud"@"%" IDENTIFIED BY "[passwd]";<br /> GRANT ALL ON nextcloud.* to "nextcloud"@"%";<br /> FLUSH PRIVILEGES;</code></p> <p>Then enter \q to exit.</p> <h2>Prepare your Docker Compose host</h2> <p>We make use of the NextCloud community's <a href="https://hub.docker.com/_/nextcloud/" title="Documentation for the reference NextCloud Docker container.">stable Docker container</a> which they keep up to date. Similarly, the OnlyOffice developers maintain a Docker container, too. We will run them both on this same server as separate services via <a href="https://docs.docker.com/compose/">Docker Compose</a>. The two sets of Docker containers will look like this:</p> <ol><li>a suite of NextCloud containers: <ol><li>the main PHP-FPM container (which provides most of the functionality for NextCloud using the PHP scripting engine,</li> <li>an identical container to the PHP one which runs the cron service (which does periodic administrative tasks relevant to NextCloud)</li> <li>a Redis container (which provides performance improving caching for NextCloud), and</li> <li>an Nginx webserver container which makes it easier to manage the configuration and paths of the NextCloud instance. It means that on the hosting server, we only need to run a proxying web server, which is easy.</li> </ol></li> <li>the single OnlyOffice container which, despite the Docker convention of each container running only a single services, runs the whole OnlyOffice stack, which includes PostgreSQL, Nginx, Rabbit-MQ, Python, and NodeJS.</li> </ol><p>The way I prefer to implement this set of containers is to use:</p> <p><code>sudo apt-get install docker-compose </code></p> <p>to set up the entire Docker and Docker Compose system on your server.</p> <p>Then set up a place for your Docker containers (replace "me" with your non-root username on the server) and the associated persistent data (your Docker containers should hold <em>no</em> important data - you should be able to delete and recreate them entirely without losing any important data or configuration):</p> <p><code>sudo mkdir /home/data</code><br /><code>sudo mkdir /home/data/nextcloud<br /> sudo mkdir /home/data/nextcloud-nginx<br /> sudo mkdir /home/data/nextcloud-redis</code><br /><code>sudo mkdir /home/data/onlyoffice</code><br /><code>sudo mkdir /home/docker<br /> sudo mkdir /home/docker/nextcloud</code><br /><code>sudo chown -R me:me /home/docker</code></p> <h2>NextCloud Install</h2> <p>First, let's set up NextCloud (this also installs the OnlyOffice server):</p> <p><code>cd /home/docker/nextcloud</code></p> <p>Here's an example of the required docker-compose.yml file (you can create this via a text editor like "nano" which should be pre-installed on any VM these days (or use my preferred, but less intuitive, editor, vim) <code>nano docker-compose.yml</code> in the /home/docker/nextcloud directory):</p> <p><code>version: '3'<br /> services:<br />   nginx:<br />     container_name: nginx-server<br />     image: nginx<br />     ports:<br />       - 127.0.0.1:8082:80<br />     volumes:<br />       - /home/data/nextcloud-nginx/nginx/nginx.conf:/etc/nginx/nginx.conf:ro<br />       - /home/data/nextcloud:/var/www/html<br />     links:<br />       - app<br />     environment:<br />       - VIRTUAL_HOST<br />     restart: unless-stopped      <br />   app:<br />     container_name: app-server<br />     image: nextcloud:fpm<br />     stdin_open: true<br />     tty: true<br />     links:<br />       - redis<br />     expose:<br />       - '80'<br />       - '9000'<br />     volumes:<br />       - /home/data/nextcloud:/var/www/html<br />     restart: unless-stopped      <br />   cron:<br />     image: nextcloud:fpm<br />     volumes:<br />       - /home/data/nextcloud:/var/www/html<br />     user: www-data<br />     entrypoint: |<br />       bash -c 'bash -s &lt;&lt;EOF<br />       trap "break;exit" SIGHUP SIGINT SIGTERM<br />       while /bin/true; do<br />         /usr/local/bin/php /var/www/html/cron.php<br />         sleep 900<br />       done<br />       EOF'<br />     restart: unless-stopped      <br />   redis:<br />     image: redis:alpine<br />     volumes:<br />       - /home/data/nextcloud-redis:/data<br />     restart: unless-stopped<br />   onlyoffice-document-server:<br />     container_name: onlyoffice-document-server<br />     image: onlyoffice/documentserver:latest<br />     stdin_open: true<br />     tty: true<br />     restart: unless-stopped<br />     expose:<br />       - '80'<br />       - '443'<br />     volumes:<br />       - /home/data/onlyoffice/data:/var/www/onlyoffice/Data<br />       - /home/data/onlyoffice/log:/var/log/onlyoffice</code></p> <p>The "port" specified above, 8082 for <code>nginx</code> is arbitrary - I picked it to ensure it doesn't don't conflict with ports being used by other containers on my server - you can use these if you want, or use <code>sudo netstat -punta</code> to see what ports are currently claimed by other services on your server (if there are any) and pick one that doesn't clash! If it scroll past too fast, you can pipe it into less to allow you to scroll and search like this: <code>sudo netstat -punta | less</code> - hit "q" to exit or "/" to initiate a text search.</p> <p>You will also need to provide the "nginx.conf" file referenced in the nginx section of the file. Do that by using your editor, e.g. <code>nano nginx.conf</code>, and enter this content (you shouldn't need to alter anything):</p> <p><code>user  www-data;</code></p> <p><code>worker_processes  1;</code></p> <p><code>error_log  /var/log/nginx/error.log warn;<br /> pid        /var/run/nginx.pid;</code></p> <p><code>events {<br />     worker_connections  1024;<br /> }</code></p> <p><code>http {<br />     upstream backend {<br />         server app-server:9000;<br />     }</code></p> <p><code>    include       /etc/nginx/mime.types;<br />     default_type  application/octet-stream;</code></p> <p><code>    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '<br />                       '$status $body_bytes_sent "$http_referer" '<br />                       '"$http_user_agent" "$http_x_forwarded_for"';</code></p> <p><code>    access_log  /var/log/nginx/access.log  main;</code></p> <p><code>    sendfile        on;<br />     #tcp_nopush     on;</code></p> <p><code>    keepalive_timeout  65;</code></p> <p><code>    map $http_host $this_host {<br />         "" $host;<br />         default $http_host;<br />     }</code></p> <p><code>    map $http_x_forwarded_proto $the_scheme {<br />         default $http_x_forwarded_proto;<br />         "" $scheme;<br />     }</code></p> <p><code>    map $http_x_forwarded_host $the_host {<br />         default $http_x_forwarded_host;<br />         "" $this_host;<br />     }</code></p> <p><code>    server {<br />         listen 80;</code></p> <p><code>        # Add headers to serve security related headers<br />         add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";<br />         add_header X-Content-Type-Options nosniff;<br />         add_header X-XSS-Protection "1; mode=block";<br />         add_header X-Robots-Tag none;<br />         add_header X-Download-Options noopen;<br />         add_header X-Permitted-Cross-Domain-Policies none;</code></p> <p><code>        root /var/www/html;<br />         client_max_body_size 10G; # 0=unlimited - set max upload size<br />         fastcgi_buffers 64 4K;</code></p> <p><code>        gzip off;</code></p> <p><code>        index index.php;<br />         error_page 403 /core/templates/403.php;<br />         error_page 404 /core/templates/404.php;</code></p> <p><code>        rewrite ^/.well-known/carddav /remote.php/dav/ permanent;<br />         rewrite ^/.well-known/caldav /remote.php/dav/ permanent;</code></p> <p><code>        location = /robots.txt {<br />             allow all;<br />             log_not_found off;<br />             access_log off;<br />         }</code></p> <p><code>        location ~ ^/(build|tests|config|lib|3rdparty|templates|data)/ {<br />             deny all;<br />         }</code></p> <p><code>        location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {<br />             deny all;<br />         }</code></p> <p><code>        location / {<br />             rewrite ^/remote/(.*) /remote.php last;<br />             rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;<br />             try_files $uri $uri/ =404;<br />         }</code></p> <p><code>        location ~* ^/ds-vpath/ {<br />             rewrite /ds-vpath/(.*) /$1  break;<br />             proxy_pass http://onlyoffice-document-server;<br />             proxy_redirect     off;</code></p> <p><code>            client_max_body_size 100m;</code></p> <p><code>            proxy_http_version 1.1;<br />             proxy_set_header Upgrade $http_upgrade;<br />             proxy_set_header Connection "upgrade";</code></p> <p><code>            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-Host $the_host/ds-vpath;<br />             proxy_set_header X-Forwarded-Proto $the_scheme;<br />             #proxy_set_header X-Forwarded-Proto 'https';<br />         }</code></p> <p><code>        location ~ \.php(?:$|/) {<br />             fastcgi_split_path_info ^(.+\.php)(/.+)$;<br />             include fastcgi_params;<br />             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;<br />             fastcgi_param PATH_INFO $fastcgi_path_info;<br />             fastcgi_param HTTPS off;<br />             fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice<br />             fastcgi_pass backend;<br />             fastcgi_intercept_errors on;<br />         }</code></p> <p><code>        # Adding the cache control header for js and css files<br />         # Make sure it is BELOW the location ~ \.php(?:$|/) { block<br />         location ~* \.(?:css|js)$ {<br />             add_header Cache-Control "public, max-age=7200";<br />             # Add headers to serve security related headers<br />             add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";<br />             add_header X-Content-Type-Options nosniff;<br />             add_header X-Frame-Options "SAMEORIGIN";<br />             add_header X-XSS-Protection "1; mode=block";<br />             add_header X-Robots-Tag none;<br />             add_header X-Download-Options noopen;<br />             add_header X-Permitted-Cross-Domain-Policies none;<br />             # Optional: Don't log access to assets<br />             access_log off;<br />         }</code></p> <p><code>        # Optional: Don't log access to other assets<br />         location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|swf)$ {<br />             access_log off;<br />         }</code><br /><code>    }<br /> }</code></p> <p>That should be all the configuration you need to make the Docker containers go.</p> <h2>Configuring Nginx to proxy NextCloud and OnlyOffice</h2> <p>The next step is configuring the local nginx proxy servers for NextCloud and OnlyOffice using the nginx instance you installed earlier. That's what responds to the domain name you choose for this service. In our case, the name is <a href="https://docs.oeru.org">https://docs.oeru.org</a> - you can have a look at it to see what you should be seeing when you first start things up! We use <a href="https://letsencrypt.org" title="This is an incredible free and open source service, that is single-handedly making the web a much safer place.">Let's Encrypt</a> to provide secure hosting - <a href="/protecting-your-users-lets-encrypt-ssl-certs">here're my Let's Encrypt instructions</a> on setting it up. The key thing to realise is that your "certificates" need to exist for Nginx to restart with the new configurations below - use the "commenting out the intervening lines" trick mentioned in my instructions to bootstrap the creation of your secure certificates!</p> <p>To configure the proxy, you need to create this configuration file in your /etc/nginx/sites-available/ directory.</p> <h3>NextCloud Proxy Configuration</h3> <p>Create a file with a meaningful name for your NextCloud Proxy, perhaps based on the domain name you've chosen (our file for docs.oeru.org is called "docs") using the same editing approach as the last few (although this is in a different directory) for example <code>sudo nano /etc/nginx/sites-available/nextcloud</code> with the following contents, replacing <code>[nextcloud.domain]</code> with your selected domain name, but leave off the [ ] (those are just there to make sure nginx errors if you've missed replacing any) - and the port number 8082 if you've opted to change to a different one!:</p> <p><code>server {<br />     listen 80;<br />     listen [::]:80;<br />     server_name <strong>[nextcloud.domain]</strong>;</code></p> <p><code>    include includes/letsencrypt.conf;</code></p> <p><code>    # enforce https<br />     location / {<br />         return 302 https://$server_name$request_uri;<br />     }<br /> }</code></p> <p><code>server {<br />     listen 443 ssl;<br />     listen [::]:443 ssl;<br />     #listen 127.0.0.1:443 ssl;</code></p> <p><code>    server_name <strong>[nextcloud.domain]</strong>;</code></p> <p><code>    ## Access and error logs.<br />     access_log /var/log/nginx/<strong>[nextcloud.domain]</strong>_access.log;<br />     error_log /var/log/nginx/<strong>[nextcloud.domain]</strong>_error.log;</code></p> <p><code>    ssl_certificate /etc/letsencrypt/live/<strong>[nextcloud.domain]</strong>/fullchain.pem;<br />     ssl_certificate_key /etc/letsencrypt/live/<strong>[nextcloud.domain]</strong>/privkey.pem;</code></p> <p><code>    ssl on;<br />     # from http://axiacore.com/blog/enable-perfect-forward-secrecy-nginx/<br />     ssl_session_cache shared:SSL:10m;<br />     ssl_session_timeout  10m;<br />     # limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;<br />     # forward secrecy settings<br />     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br />     ssl_prefer_server_ciphers on;<br />     ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";<br />     ssl_dhparam /etc/ssl/certs/dhparam.pem;</code></p> <p><code>    #location = /robots.txt {<br />     #    allow all;<br />     #    log_not_found off;<br />     #    access_log off;<br />     #}</code></p> <p><code>    # The following 2 rules are only needed for the user_webfinger app.<br />     # Uncomment it if you're planning to use this app.<br />     rewrite ^/.well-known/host-meta /public.php?service=host-meta last;<br />     rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;</code></p> <p><code>    # The following rule is only needed for the Social app.<br />     # Uncomment it if you're planning to use this app.<br />     rewrite ^/.well-known/webfinger /public.php?service=webfinger last;</code></p> <p><code>    location ^~ / {<br />         proxy_pass http://127.0.0.1:<strong>8082</strong>;<br />         proxy_set_header Upgrade $http_upgrade;<br />         proxy_set_header Connection "Upgrade";<br />         proxy_set_header Host $http_host;<br />         proxy_read_timeout 36000s;<br />         proxy_buffering off;<br />         proxy_max_temp_file_size 15000m;<br />     }<br />     client_max_body_size 1G;<br />     fastcgi_buffers 64 4K;<br />     add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";<br />     # Remove X-Powered-By, which is an information leak<br />     fastcgi_hide_header X-Powered-By;<br /> }</code></p> <p>Note: you'll need to create the file cited in the proxy configration: <code>/etc/ssl/certs/dhparam.pem </code></p> <p>You can do this as follows (install the necessary software, backup any possible existing version as a matter of prudence, and create a new one):</p> <p><code>sudo apt update &amp;&amp; sudo apt install openssl<br /><span class="pun">sudo [<span class="pln"> </span>-</span><span class="pln">f </span><span class="str">"</span>/etc/ssl/certs/dhparam.pem<span class="str">"</span><span class="pln"> </span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> sudo mv </span>/etc/ssl/certs/dhparam.pem /etc/ssl/certs/dhparam.pem</code>.bak<br /><span style="font-family:monospace"><span style="color:#000000;background-color:#ffffff;">sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048</span></span><br />  </p> <p>Once those are created, you have to make sure that they're "enabled" (replacing with your file names, of course):</p> <p><code>sudo cd /etc/nginx/sites-enabled<br /> sudo ln -sf ../sites-available/nextcloud .</code></p> <p>To confirm that there aren't any typos or issues that might make nginx unhappy, run</p> <p><code>sudo nginx -t</code></p> <p>If all's well, get nginx to reread its configuration with the new files (if not, it might be because you missed replacing one of the [tokens]):</p> <p><code>sudo service nginx reload</code></p> <h2>Firing up your NextCloud!</h2> <p>Phew - congratulations on getting here! We've reached the moment of truth where we need to see if this whole thing will work!</p> <p>We need to make sure we're back in the NextCloud Docker directory we set up:</p> <p><code>cd /home/docker/nextcloud</code></p> <p>and then we need to try running our docker-compose script to "pull" in the pre-built Docker containers we've specified in our docker-compose.yml file:</p> <p><code>docker-compose pull</code></p> <p>All going well, after a few minutes (longer or shorter depending on the speed of your server's connection) you should have download the Nginx, Redis, and NextCloud Docker images. Then you can run:</p> <p><code>docker-compose up -d &amp;&amp; docker-compose logs -f</code></p> <p>This will attempt to start up the containers (bringing them "up" in daemon mode, thus the -d) and then show you a stream of log messages from the containers, preceded by the container name. This should help you debug any problems that occur during the process (ideally, none).</p> <p>Once you see log messages streaming past, and no obvious "container exited" or other error messages (which will usually contain the word "error" a lot), you should be able to point your browser at your selected domain name and bring it up in your browser! Just point your web browser at <code>https://nextcloud.domain</code> (replacing with your domain, of course - the https assumes you've got your Let's Encrypt certificate set up - I recommend doing that first).</p> <h3>Configuring database access</h3> <p>On doing so, if all is well, you should be directed through the database set up process for your NextCloud instance. Your details should be:</p> <p>database IP: 172.17.0.1 - this is the default IP of the Docker host server.<br /> database name: nextcloud<br /> database user: nextcloud<br /> database password: (the one you came up with above)</p> <h3>Configuring the Admin user</h3> <p>Once that's set and working, NextCloud will install all the relevant database tables and initial data. You'll be asked to set up an <em>admin user</em> account, which can be "admin" (you could make it something different to help stymie nefarious probes that assume you've got a user called "admin" - but don't forget what you've called it!) and some strong password you create (you can use the pwgen utility you used earlier) - I'd recommend recording it somewhere. I would <em>not</em> recommend making your own account, in your name, the main admin account. Instead, I recommend creating a second account, <em>with administrator privileges</em>, for yourself, but leave the admin account purely for administrative activities.</p> <h3>Configuring Outgoing Email</h3> <p>To allow your NextCloud instance to send outgoing email, so that your site can alert you to security updates that need to be applied, or so that users can request a replacement password if they've forgot theirs, you'll need an <em>authenticating SMTP account</em> somewhere. Most of you already have one. You'll probably want to set up a dedicated email address for this server somewhere, perhaps something like "<a href="mailto:nextcloud@your.domain">nextcloud@your.domain</a>" or similar, with a username (often just the email address) and a password. You'll need the following details:</p> <p>SMTP server : an IP address or a domain name<br /> SMTP username: a username or an email address<br /> SMTP password: a strong password already configured for the username on that server<br /> SMTP login security: whether login is via TLS, SSL, or unsecure (!!), and<br /> SMTP login method: plain, encrypted, "login" or some other value.</p> <p>You should be able to test your email settings to make sure the details you've entered are valid. If you need to adjust these settings later, you can go to the admin menu (top right of the web browser interface) and go to Admin-&gt;Additional Settings  - should have a path of <code>https://nextcloud.domain/settings/admin/additional</code></p> <h2>Setting up OnlyOffice</h2> <p>The OnlyOffice server should already be running - if you point your browser at <code>https://nextcloud.domain/ds-vpath/</code> you should see something like the "Document Server is running" (with a big green "tick") page included in the images accompanying this article.</p> <h3>Configuring OnlyOffice Integration with NextCloud</h3> <p>Once you're logged in to NextCloud as your own user, looking at your own default folders, you can start having a look around. You should have an "admin" menu (assuming you've created your user with Administrator privileges) at the top right of the web interface. If you go to Apps, you can install the new "Hub bundle" available under the "App bundles" option (see attached image). If you don't want the whole bundle you can just use the search box to search for "OnlyOffice" or go to the "Office &amp; text" App category and enable the OnlyOffice "official" app, at which point it will automatically download the latest version of the connector app and install it (it should appear in your /home/data/nextcloud/apps directory)</p> <p>Once you've done that, go to your top right menu again, selecting Admin, and you should see "OnlyOffice" as an option in the left column (which starts with "Basic settings"). Selecting that, you'll need to enter the following:</p> <ul><li> "Document Editing Service address":<code> /ds-vpath/</code></li> <li><code>"</code>Secret key": (leave blank)</li> <li> Under "Advanced server settings" <ul><li> <p class="onlyoffice-header">"Document Editing Service address for internal requests from the server": <code>http://onlyoffice-document-server/</code></p> </li> <li> <p class="onlyoffice-header">"Server address for internal requests from the Document Editing Service": <code>http://nginx-server/</code></p> </li> </ul></li> </ul><p>When you're done, click "Save".</p> <p>You can also select formats you'd like OnlyOffice to open and edit files of those types are clicked or created. I've selected the following: doc, docx, odp, ods, odt, ppt, pptx, xls, xlsx, and in the second section: csv and txt.</p> <p>You can also make other editor customisations as you desire. The only Editor customisation setting I <em>haven't</em> selected is "Display Chat menu button" because NextCloud Hub provides an integrated Chat service, making this one within OnlyOffice an unnecessary distraction.</p> <p>Once finished configuring, you should have the ability to go back to the home of your NextCloud install, which should show you your top-level folders. If you click the "+" next to the home icon (top left of the folder pane) you should now have the option to create (in addition to "Upload file", "New folder", "New text file") a "New Document", "New Spreadsheet", and "New Presentation". Clicking those should give you the OnlyOffice interface for the designated content type.</p> <p>Similarly, you can use the "Upload file" to upload a document in a format that is supported by OnlyOffice. Once uploaded, clicking on the filename should open it for editing in the appropriate OnlyOffice interface.</p> <p>It is saved as it is changed, so you shouldn't need to save it explicitly.</p> <h2>Keeping the whole thing up-to-date</h2> <p>So, as you're no doubt aware, both NextCloud and OnlyOffice are always being improved and updated. I certainly encourage you to keep your installations up-to-date.</p> <p>While you'll periodically be alerted that NextCloud <strong>apps</strong> have available updates (these can be upgraded through the browser interface) updates to the NextCloud and OnlyOffice systems themselves need to be undertaken by upgrading their containers. Luckily it's easy to do (although I strongly urge you to ensure you have a very recent backup of both database and uploaded files - they're the files in /home/data/nextcloud/data and /home/data/onlyoffice/ (note, backups of OnlyOffice are complicated somewhat by the fact that you can't reliably back up running PostgreSQL instance simply by backing up its files - see a solution below):</p> <p>Updating the container should be as easy as either doing another</p> <p><code>docker-compose pull </code></p> <p>and then shutting down Docker container via a</p> <p><code>docker-compose up -d</code></p> <p>which will remove any old containers (this won't remove any data you want to save if you followed the directions above! But remember to do it in the right directory!) and start up the new versions you've just pulled.</p> <p>Use <code>docker-compose logs -f</code> to watch the logs - you'll likely see useful debugging information in the unlikely event that something goes wrong in the upgrade process.</p> <h2>Backing up NextCloud</h2> <p>To back up your instance on your server, you need two things: a file system backup of your /home/data/nextcloud directory, and database dumps of your database.</p> <p>There're lots of ways to back up your files (I've recently updated to using a system called Restic to make off-server incremental encrypted backups - I plan to document this in a future howto! - although there're <a href="https://www.howtoforge.com/linux_rdiff_backup">other documented approaches</a> - leave a comment below if you'd like to learn more about my approach!).</p> <p>Backing up your MariaDB databases is as easy installing automysqlbackups:</p> <p><code>sudo apt install automysqlbackups</code></p> <p>You'll find daily versioned dumps of your MariaDB database(s) in /var/lib/automysqlbackups on your VM host's filesystem. To run an ad hoc backup (which will replace the previous backup from that day, if there is one) just run</p> <p><code>sudo automysqlbackups</code></p> <h2>Backup OnlyOffice</h2> <p>Along with backing up the files in your /home/data/onlyoffice directory, you'll also want a proper "dump" of your PostgreSQL backup (you can write simple bash scripts to do this regularly, automatically), particularly prior to doing an upgrade (to allow for recovery if something goes badly wrong, which is always possible). You can achieve this by going to</p> <p><code>cd /home/docker/onlyoffice</code></p> <p>and running this</p> <p><code>DATE=`date +%Y%m%d` &amp;&amp; FILE=/home/data/onlyoffice/backup/fullbackup-${DATE}.sql &amp;&amp; docker-compose exec onlyoffice sudo -u postgres pg_dumpall &gt; ${FILE} &amp;&amp; gzip ${FILE}</code></p> <p>which will assign the current date to DATE, the relevant filename to FILE, and then put the backup SQL into a dated file called $FILE and compress the result with gzip :)</p> <p>At some point, I'll modify my normal versioned dated database backup scripts to cater for this solution and make the result available on <a href="https://git.oeru.org">https://git.oeru.org</a> - in the meantime, you can use the above before you do a backup and manually delete older backups if they start taking up too much space (or, better still, write your own clever script that does it automatically and let me know about it!).</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=29&amp;2=field_blog_comments&amp;3=comment" token="9kYJqJN_nL4QNtjWT8YsPb_jXY2Bv9NrASHDdb5feiU"></drupal-render-placeholder> </div> </section> Mon, 03 Feb 2020 20:41:16 +0000 dave 29 at http://tech.oeru.org