{"id":285,"date":"2025-09-09T14:50:32","date_gmt":"2025-09-09T07:50:32","guid":{"rendered":"https:\/\/altai22.ru\/?p=285"},"modified":"2026-03-17T22:28:38","modified_gmt":"2026-03-17T15:28:38","slug":"install-nextcloud-hub-and-onlyoffice-on-ubuntu-24-04-with-docker-compose","status":"publish","type":"post","link":"https:\/\/altai22.ru\/?p=285","title":{"rendered":"\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 NextCloud Hub and OnlyOffice \u043d\u0430 Ubuntu 24.04 \u0432 Docker Compose"},"content":{"rendered":"\n<p>This is yet another update of my previous posts (installing&nbsp;<a href=\"https:\/\/tech.oeru.org\/node\/17\">NextCloud with Collabora Office Online on Ubuntu 16.04<\/a>&nbsp;and then&nbsp;<a href=\"https:\/\/tech.oeru.org\/node\/29\">NextCloud with OnlyOffice on Ubuntu 18.04<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/tech.oeru.org\/node\/56\">Install NextCloud Hub and OnlyOffice on Ubuntu 22.04 with Docker Compose<\/a>).&nbsp;<a href=\"https:\/\/nextcloud.com\/\">NextCloud<\/a>&nbsp;continues to develop at a blistering rate, and as of this writing, it&#8217;s at version 30.0.5. This is fortunate, as countries in the EU are finally getting savvy about serious about addressing their sovereignty-threating dependence on US-based multinationals like Amazon, Google, Microsoft, Dropbox, and others really is. The Danish government&nbsp;<a href=\"https:\/\/www.english.digmin.dk\/Media\/638736628110392217\/The%20role%20of%20big%20tech%20as%20digital%20infrastructure.pdf\">just published a superb example of the solid thinking<\/a>&nbsp;now starting to emerge. NextCloud will be a key part of that transition away from US BigTech&#8217;s proprietary model, and it can&#8217;t come too soon.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>There&#8217;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&#8217;ve used in the past). But the best companion productivity suite for NextCloud, in my opinion, is&nbsp;<a href=\"https:\/\/onlyoffice.com\/\">OnlyOffice<\/a>. The application itself (for the tech focused reader, they&#8217;ve built an entirely&nbsp;<a href=\"https:\/\/github.com\/ONLYOFFICE\/\">new application ecosystem<\/a>&nbsp;primarily using modern Javascript frameworks) is impressive in both capabilities and polish. The only real caveat I&#8217;ve come across is that it uses, by default, the&nbsp;<a href=\"https:\/\/openstandards.nz\/case-study-microsofts-ooxml-standard\">&#8216;fauxpen&#8217; standard formats<\/a>&nbsp;developed by Microsoft rather than the true open standard formats of&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/OpenDocument\">OpenDocumentFormat<\/a>. But in a world where, sadly, most people don&#8217;t even know what a file format is, any software that doesn&#8217;t read and write the incumbent monopolist&#8217;s format with great fidelity is dead in the water. On that count, OnlyOffice is impressive. NextCloud + OnlyOffice &#8212; even better together (<em>without<\/em>&nbsp;a single US multinational tech giant involved. NextCloud development is led from Germany, OnlyOffice&#8217;s development is led by a team in&nbsp;<a href=\"https:\/\/www.onlyoffice.com\/about.aspx\">Latvia<\/a>)!<\/p>\n\n\n\n<p>The beauty of the open source software model is that we can connect complementary applications, like NextCloud and OnlyOffice &#8212; developed by completely separate communities &#8212; to create a tightly integrated, highly functional, diverse computing platform. This combination, along with a bunch of other NextCloud &#171;apps&#187;, is the equal of something like Google Apps (which includes Google Docs and Google Drive), but is under your control, not Google&#8217;s. To me, that&#8217;s a crucial difference.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#tips-for-this-tutorial\">Tips for this tutorial<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#create-a-virtual-private-server\">Create a Virtual Private Server<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#vps-properties\">VPS Properties:<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#key-variables-for-you-nextcloud-and-onlyoffice-instances\">Key variables for you NextCloud and OnlyOffice instances<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#get-your-domain-lined-up\">Get your Domain lined up<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#editing-files\">Editing files<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#set-up-an-unprivileged-user-for-yourself\">Set up an unprivileged user for yourself<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configure-the-vps\">Configure the VPS<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-your-firewall\">Configuring your firewall<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#install-the-nginx\">Install the Nginx<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#outgoing-vps-email-optional\">Outgoing VPS Email (optional)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#installing-the-docker-engine-docker-compose-and-lets-encrypt\">Installing the Docker Engine, Docker Compose, and Let&#8217;s Encrypt<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backwards-compatibility-for-docker-compose\">Backwards compatibility for Docker Compose<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#docker-use-by-non-root-user\">Docker use by non-root user<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#docker-conventions\">Docker conventions<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#installing-mariadb\">Installing MariaDB<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice\">Configuring Nginx reverse proxy for NextCloud and OnlyOffice<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#lets-encrypt-setup\">Let&#8217;s Encrypt setup<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#nextcloud-proxy-configuration\">NextCloud Proxy Configuration<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#onlyoffice-proxy-configuration\">OnlyOffice Proxy Configuration<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#requesting-lets-encrypt-certificates\">Requesting Let&#8217;s Encrypt certificates<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#prepare-your-docker-compose-host\">Prepare your Docker Compose host<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#nextcloud-install\">NextCloud Install<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#install-the-nextcloud-docker-recipe\">Install the NextCloud Docker recipe<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-nextcloud-nginx-configuration\">The NextCloud Nginx configuration<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-onlyoffice-docker-configuration\">The OnlyOffice Docker configuration<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#firing-up-your-nextcloud\">Firing up your NextCloud!<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-nextcloud-source-code-if-necessary\">The NextCloud source code (if necessary)<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-database-access\">Configuring database access<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-the-admin-user\">Configuring the Admin user<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-outgoing-email\">Configuring Outgoing Email<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#setting-up-onlyoffice\">Setting up OnlyOffice<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-onlyoffice-integration-with-nextcloud\">Configuring OnlyOffice Integration with NextCloud<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#keeping-the-whole-thing-up-to-date\">Keeping the whole thing up-to-date<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backing-up-nextcloud\">Backing up NextCloud<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backup-onlyoffice\">Backup OnlyOffice<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#tips-for-this-tutorial\"><\/a>Tips for this tutorial<\/h2>\n\n\n\n<p>This (perhaps) somewhat daunting looking 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&#8217;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&nbsp;<em>delete your VPS<\/em>, you should not be out-of-pocket by more than a few cents.<\/p>\n\n\n\n<p>If this is your first attempt at &#8216;self-hosting&#8217;, and you&nbsp;<em>do<\/em>&nbsp;follow through, this could be the start of a new era in your technical status &#8212; you could realised that self-hosting &#8216;agency&#8217; you always wanted. People with that skill set are in hot demand among most organisations, especially in the NGO\/charitable spaces. Plus, I&#8217;ll be very impressed by your&nbsp;<a href=\"https:\/\/www.merriam-webster.com\/dictionary\/moxie\">moxie<\/a>!<\/p>\n\n\n\n<p>With this tutorial, I&#8217;m assuming you&#8217;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&#8217;re SSH&#8217;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>\n\n\n\n<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 &#8212; [] &#8212; with your own values. I assume you&#8217;ll be able to do that in a text editor on your desktop.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#create-a-virtual-private-server\"><\/a>Create a Virtual Private Server<\/h2>\n\n\n\n<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&#8217;ve got a&nbsp;<em>fast<\/em>&nbsp;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&#8217;t undertake this unless you have a flat-rate data connection.<\/p>\n\n\n\n<p>The more cost-effective approach in our experience, is to secure a low cost commodity Linux Virtual Private Server running Ubuntu Linux 24.04 (the latest &#171;Long Term Support&#187; version). That&#8217;s what we&#8217;ll assume you&#8217;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&#8217;t necessarily the same as the &#8216;geographic&#8217; epicentre) of your audience. For the record, we&#8217;ve just shifted our hosting to Hetzner as they&#8217;ve got the benefit of not being US-owned (They&#8217;re German, and therefore don&#8217;t expose us to the egregiously over-reaching US&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/CLOUD_Act\">Cloud<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/proprivacy.com\/guides\/what-is-the-partiot-act\">Patriot<\/a>&nbsp;Acts) and their pricing is pretty unbeatable.<\/p>\n\n\n\n<p>If you have trouble getting a VPS, you might find&nbsp;<a href=\"https:\/\/vimeo.com\/684028258\">this video<\/a>&nbsp;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&#8217;ll find this process&nbsp;<em>much<\/em>&nbsp;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>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#vps-properties\"><\/a>VPS Properties:<\/h3>\n\n\n\n<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&#8217;ll make your life far far easier in the medium-long term.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>4-8 GB RAM<\/li>\n\n\n\n<li>2-4 Virtual CPUs<\/li>\n\n\n\n<li>80-160 GB Disk space (NVME disk is faster than SSD which is faster than spinning disk space)<\/li>\n\n\n\n<li>running Ubuntu Linux 24.04 (the current Long Term Support version)<\/li>\n\n\n\n<li>extra storage &#8212; 20-40GB extra space (can be expanded on fairly short notice)<\/li>\n<\/ul>\n\n\n\n<p>You&#8217;ll need to create an account for yourself on your chosen hosting provider (it&#8217;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 &#8212; you&#8217;ll find instructions on how to set up 2FA on your hosting provider&#8217;s site) and create an Ubuntu 24.04 (or the most recent &#8216;Long Term Support&#8217; (LTS) version) &#8212; 26.04 is likely to come out in April 2026) in the &#8216;zone&#8217; nearest to you (or your primary audience, if that&#8217;s different).<\/p>\n\n\n\n<p>If you don&#8217;t already have an SSH key on your computer, I encourage you to&nbsp;<a href=\"https:\/\/helpdeskgeek.com\/how-to\/how-to-generate-ssh-keys-on-windows-mac-and-linux\/\">create one<\/a>&nbsp;and specify the&nbsp;<strong>public key<\/strong>&nbsp;in the process of creating your server &#8212; specifying the &#8216;public key&#8217; of your SSH identity during the server creation process that should allow you to log in without needing a password!<\/p>\n\n\n\n<p>You&#8217;ll need to note the server&#8217;s&nbsp;<strong>IPv4<\/strong>&nbsp;address (it&#8217;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&nbsp;<strong>IPv6<\/strong>&nbsp;address, which will be a set of 8 four&nbsp;<em>hex character<\/em>&nbsp;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&nbsp;<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&#8217;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&#8217;s instructions.<\/p>\n\n\n\n<p><code>ssh [your server IPv4 or IPv6]<\/code><\/p>\n\n\n\n<p>followed by the ENTER key (that&#8217;ll be true for any line of commands I provide).<\/p>\n\n\n\n<p>In some cases, depending on your hosting provider, you&#8217;ll have a password to enter, or if you&#8217;ve specified your pre-existing public SSH key, you shouldn&#8217;t need to enter a password at all, you should be logged in. To check what user you care, you can type<\/p>\n\n\n\n<p><code>whoami<\/code><\/p>\n\n\n\n<p>If it returns&nbsp;<code>root<\/code>&nbsp;(there&#8217;s also a convention of using a &#8216;#&#8217; as the command prompt), you&#8217;re the root or super-admin of the server. If not, you&#8217;re a normal user (some hosting providers have a convention of giving you a default user called &#171;ubuntu&#187; or perhaps &#171;debian&#187;) with a prompt that is, by convention, a &#8216;$&#8217;.<\/p>\n\n\n\n<p>Now that you&#8217;re logged in, it&#8217;s worth doing an upgrade of your server&#8217;s Ubuntu system! Do that as follows (this works regardless of whether your a root user or an unprivileged user with &#8216;sudo&#8217; ability):<\/p>\n\n\n\n<p><code>sudo apt update &amp;&amp; sudo apt dist-upgrade<\/code><\/p>\n\n\n\n<p>Usually the user, even if it&#8217;s not the root user, will have the ability to use the&nbsp;<code>sudo<\/code>&nbsp;command modifier &#8212; that means &#171;<em>do<\/em>&nbsp;this action as the root (aka the &#8216;Super User&#8217;, thus &#8216;<em>su<\/em>&#8216; in &#8216;sudo&#8217; for short) user&#187; &#8212; if you&#8217;re a non-root user, you&#8217;ll likely be asked to enter your password as a security precaution the first time you run a command prefaced by&nbsp;<code>sudo<\/code>. Enter it, and it should run the command. Plus, the system shouldn&#8217;t bother you for it again unless you leave your terminal unused for a while (usually 5 minutes) and come back to it.<\/p>\n\n\n\n<p>At this point, I also like to install a cool software package called &#8216;etckeeper&#8217; 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>\n\n\n\n<p><code>sudo apt install etckeeper<\/code><\/p>\n\n\n\n<p>which will also install some dependencies, including the very important (and relevant later on) &#8216;git&#8217; version control system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#key-variables-for-you-nextcloud-and-onlyoffice-instances\"><\/a>Key variables for you NextCloud and OnlyOffice instances<\/h2>\n\n\n\n<p>To set up your services, you&#8217;ll need a few crucial bits of information related to your system&#8217;s identity and external systems you&#8217;ll need it to interact with. For example, as mentioned before, you&#8217;ll need a domain name. For the rest of this tutorial, we&#8217;ll use the convention of representing those variables as a name inside [], or, for the domain name you&#8217;ve picked, [domain name].<\/p>\n\n\n\n<p>Here&#8217;s a list of variables you&#8217;ll need to know to complete the rest of this tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>[ipv4]<\/strong>&nbsp;and&nbsp;<strong>[ipv6]<\/strong>&nbsp;&#8212; your VPS&#8217; IPv4 and IPv6 addresses (the latter can be ignored if your cloud provider doesn&#8217;t support IPv6 addresses) as described above.<\/li>\n\n\n\n<li><strong>[nextcloud domain]<\/strong>&nbsp;and&nbsp;<strong>[onlyoffice domain]<\/strong>&nbsp;&#8212; the fully qualified domain names or subdomains of a base&nbsp;<strong>[domain name]<\/strong>&nbsp;by which you want your services to be accessed. You must have full domain management ability on this domain. Example: nextcloud.oeru.org &#8212; that&#8217;s the nextcloud subdomain of the oeru.org domain.<\/li>\n\n\n\n<li>Authenticating SMTP details &#8212; if you want your services to be able to send emails to users &#8212; crucial things like email address validation and password recovery emails, it&#8217;s highly recommended! You can also use it to configure your server to send you (as system adminstrator) messages about its status (optional).\n<ul class=\"wp-block-list\">\n<li><strong>[smtp server]<\/strong>&nbsp;&#8212; the domain name or IPv4 or IPv6 address of an SMTP server<\/li>\n\n\n\n<li><strong>[smtp port]<\/strong>&nbsp;&#8212; the port number on the server that is listening for your connection. By convention it&#8217;s likely to be 465 or 587, or possibly 25.<\/li>\n\n\n\n<li><strong>[smtp reply-to-email]<\/strong>&nbsp;&#8212; a monitored email to which people can send email related to this WordPress site, e.g. notifications@<strong>[domain name]<\/strong><\/li>\n\n\n\n<li><strong>[smtp user]<\/strong>&nbsp;&#8212; the username (often an email address) used to authenticate against your SMTP server, provided by your email provider.<\/li>\n\n\n\n<li><strong>[smtp password]<\/strong>&nbsp;&#8212; the accompanying password, provided by your email provider.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>[your email]<\/strong>&nbsp;&#8212; an email address to which system-related emails can be sent to you, perhaps something like webmaster@[domain name].<\/li>\n\n\n\n<li><strong>[vps username]<\/strong>&nbsp;&#8212; the username you use on your server (by convention, these are one word, and all lower case).<\/li>\n\n\n\n<li><strong>[redis password]<\/strong>&nbsp;&#8212; this is a random secret that secure access to your webserver&#8217;s cached data &#8212; I use a&nbsp;<a href=\"https:\/\/tech.oeru.org\/node\/43\">randomly generated alphanumeric password<\/a>.<\/li>\n\n\n\n<li><strong>[onlyoffice secret]<\/strong>&nbsp;&#8212; this comes from your actual install, and you can get it when the time comes.<\/li>\n\n\n\n<li>The MariaDB credentials for your NextCloud system (which stores a lot of stuff in MariaDB or MySQL by default)\n<ul class=\"wp-block-list\">\n<li><strong>[db name]<\/strong>&nbsp;&#8212; the name of your MariaDB database for NextCloud &#8212; usually &#8216;nextcloud&#8217;.<\/li>\n\n\n\n<li><strong>[db user]<\/strong>&nbsp;&#8212; the user who can manage your database.<\/li>\n\n\n\n<li><strong>[db password]<\/strong>&nbsp;&#8212; the user&#8217;s password.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#get-your-domain-lined-up\"><\/a>Get your Domain lined up<\/h3>\n\n\n\n<p>You will want to have a domain to point at your server, so you don&#8217;t have to remember the IP number. There&#8217;re are thousands of domain &#171;registrars&#187; in the world who&#8217;ll help you do that&#8230; You just need to &#171;register&#187; a name, and you pay yearly fee (usually between USD10-30 depending on the country and the &#171;TLD&#187; (Top Level Domain. There&#8217;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>\n\n\n\n<p>Here in NZ, I use the services of Metaname (they&#8217;re local to me in Christchurch, and I know them personally and trust their technical capabilities). If you&#8217;re not sure who to use, ask your friends. Someone&#8217;s bound to have recommendations (either positive or negative, in which case you&#8217;ll know who to avoid).<\/p>\n\n\n\n<p>Once you have selected and registered your domain, you can &#8216;manage your Zone&#8217; to set up (usually through a web interface provided by the registrar) an&nbsp;<strong>A Record<\/strong>&nbsp;which associates your website&#8217;s name to the&nbsp;<strong>IPv4<\/strong>&nbsp;address of your server. So you should just be able to enter your server&#8217;s IPv4 address, the domain name (or sub-domain) you want to use for the web service you want to set up.<\/p>\n\n\n\n<p>Nowadays,&nbsp;<em>if your Domain Name host offers it (some don&#8217;t, meaning you might be better off with a different one),<\/em>&nbsp;it&#8217;s also important to define an&nbsp;<strong>IPv6<\/strong>&nbsp;record, which is called an&nbsp;<strong>AAAA Record<\/strong>&#8230; you put in your IPv6 address instead of your IPv4 one.<\/p>\n\n\n\n<p>You might be asked to set a &#171;Time-to-live&#187; (which has to do with the length of time Domain Name Servers are asked to &#171;cache&#187; 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&#8217;s interface requests&#8230; but in most cases that&#8217;ll be set to a default of an hour automatically.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#editing-files\"><\/a>Editing files<\/h2>\n\n\n\n<p>In the rest of this tutorial, we&#8217;re going to be editing quite a few files via the command line. If you&#8217;re new to this, I recommend using the &#8216;nano&#8217; text editor which is installed by default on Ubuntu Linux systems. It&#8217;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 &#8216;vim&#8217;. There&#8217;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>\n\n\n\n<pre class=\"wp-block-preformatted\">EDIT=$(which nano)<\/pre>\n\n\n\n<p>or, if you&#8217;re like me<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EDIT=$(which vim)<\/pre>\n\n\n\n<p>so that subsequent references to $EDIT will invoke your preferred editor. Note the command&nbsp;<code>$(which nano)<\/code>&nbsp;is a script which finds the full path to the named command, in this case &#8216;nano&#8217;. Putting a command inside the $() means &#8216;replace with the value the script returns&#8217;, so it sets the value of EDIT to the path of the nano command in this case.<\/p>\n\n\n\n<p>To test (at any time) whether you session still knows your $EDIT command, run<\/p>\n\n\n\n<p><code>echo $EDIT<\/code><\/p>\n\n\n\n<p>if it returns the path to your preferred editor, you&#8217;re good to go. If not, just reassert the EDIT= line from above!<\/p>\n\n\n\n<p><em>Note: if you log out and back in again, change users, or create a new terminal tab\/session, you&#8217;ll need to reassert the EDIT value.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#set-up-an-unprivileged-user-for-yourself\"><\/a>Set up an unprivileged user for yourself<\/h3>\n\n\n\n<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&#8217;s name has a new name) work the same way your original SSH login did.<\/p>\n\n\n\n<p>This will log you into your server as it did the first time, either as &#8216;root&#8217; or the default unprivileged user. It&#8217;s not considered good practice to access your server as root (it&#8217;s too easy to completely screw it up by accident). It&#8217;s a good idea to create your own separate &#8216;non-root&#8217; user who has &#8216;sudo&#8217; privileges and the ability to log in via SSH. If you are&nbsp;<em>currently logged in as &#8216;root&#8217;<\/em>, you can create a normal user for yourself via (replace [vps username] with your chosen username &#8212; in my case, I&#8217;d use&nbsp;<code>U=dave<\/code>):<\/p>\n\n\n\n<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>\n\n\n\n<p>You&#8217;ll also want to a set a password for user [vps username] (we have a tutorial on&nbsp;<a href=\"https:\/\/tech.oeru.org\/node\/43\">creating good passwords<\/a>):<\/p>\n\n\n\n<p><code>passwd $U<\/code><\/p>\n\n\n\n<p>then become that user temporarily (note, the root user can &#8216;become&#8217; another user without needing to enter a password) and create an SSH key and, in the process, the&nbsp;<code>.ssh<\/code>&nbsp;directory (directories starting with a &#8216;.&#8217; are normally &#8216;hidden&#8217; &#8212; you can show them in a directory listing via&nbsp;<code>ls -a<\/code>) for the file into which to put your public SSH key:<\/p>\n\n\n\n<p><code>su $U<\/code><\/p>\n\n\n\n<p>after which you need to re-run your EDIT command:&nbsp;<code>EDIT=$(which nano)<\/code><\/p>\n\n\n\n<p>and then run&nbsp;<code>ssh-keygen -t rsa -b 2048<\/code><br><code>$EDIT ~\/.ssh\/authorized_keys<\/code><\/p>\n\n\n\n<p>and in that file, copy and paste (without spaces on either end) your&nbsp;<em>current computer&#8217;s<\/em>&nbsp;<strong>public<\/strong>&nbsp;ssh key (<em>never publish<\/em>&nbsp;your private key anywhere!), save and close the file.<\/p>\n\n\n\n<p>and then leave the &#8216;su&#8217; state, back to the superuser:<\/p>\n\n\n\n<p><code>CTRL+D<\/code>&nbsp;or type&nbsp;<code>exit<\/code><\/p>\n\n\n\n<p>From that point, you should be able to SSH to your server via&nbsp;<code>ssh [vps username]@[domain name]<\/code>&nbsp;without needing to enter a password.<\/p>\n\n\n\n<p>These instructions use &#8216;sudo&#8217; in front of commands because I assume you&#8217;re using a non-root user. The instructions will still work fine even if you&#8217;re logged in as &#8216;root&#8217; (the &#8216;sudo&#8217; will be ignored as it&#8217;s unnecessary).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configure-the-vps\"><\/a>Configure the VPS<\/h2>\n\n\n\n<p>First things first. Let&#8217;s make sure you&#8217;ve got the time zone set appropriately for your instance. It&#8217;ll probably default to &#8216;UTC&#8217; (Greenwich Mean Time). For our servers, I tend to pick &#8216;Pacific\/Auckland&#8217; which is our time zone. Run this<\/p>\n\n\n\n<p><code>sudo dpkg-reconfigure tzdata<\/code><\/p>\n\n\n\n<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&#8217;re looking at logs and having to constantly convert the times into your timezone.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-your-firewall\"><\/a>Configuring your firewall<\/h3>\n\n\n\n<p>In the name of safety from the get-go, let&#8217;s configure our firewall. We work on the basis of explicitly allowing in&nbsp;<em>only<\/em>&nbsp;what we want to let in (i.e. a &#8216;default deny&#8217; policy).<\/p>\n\n\n\n<p>First we&#8217;ll enable the use of SSH through the firewall (<em>not doing this could lock us out of your machine!<\/em>)<\/p>\n\n\n\n<p><code>sudo ufw allow ssh<\/code><\/p>\n\n\n\n<p>while we&#8217;re here, we&#8217;ll also enable data transfer from the internal (to the VPS) Docker virtual network and the IP range it uses for Docker containers:<\/p>\n\n\n\n<p><code>sudo ufw allow in on docker0<\/code><br><code>sudo ufw allow from 172.0.0.0\/8 to any<\/code><\/p>\n\n\n\n<p>Then we&#8217;ll enable forwarding from internal network interfaces as required for Docker containers to be able to talk to the outside world:<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/default\/ufw<\/code><\/p>\n\n\n\n<p>and copy the line&nbsp;<code>DEFAULT_FORWARD_POLICY=\"DROP\"<\/code>&nbsp;tweak it to look like this (commenting out the default, but leaving it there for future reference!):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#DEFAULT_FORWARD_POLICY=\"DROP\"\nDEFAULT_FORWARD_POLICY=\"ACCEPT\"<\/pre>\n\n\n\n<p>and then save and exit the file (CTRL-X and then &#8216;Y&#8217; if your editor is nano).<\/p>\n\n\n\n<p>You also have to edit&nbsp;<code>\/etc\/ufw\/sysctl.conf<\/code>&nbsp;and remove the &#171;#&#187; at the start of the following lines, so they look like this:<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/ufw\/sysctl.conf<\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Uncomment this to allow this host to route packets between interfaces\nnet\/ipv4\/ip_forward=1\nnet\/ipv6\/conf\/default\/forwarding=1\nnet\/ipv6\/conf\/all\/forwarding=1<\/pre>\n\n\n\n<p>Then we need to restart the network stack to apply that configuration change<\/p>\n\n\n\n<p><code>sudo systemctl restart systemd-networkd<\/code><\/p>\n\n\n\n<p>(on older Ubuntu systems this would have been done via&nbsp;<code>sudo service networking restart<\/code>&#8230;)<\/p>\n\n\n\n<p>Next we have to enable the UFW firewall to start at boot time.<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/ufw\/ufw.conf<\/code><\/p>\n\n\n\n<p>And set the ENABLED variable near the top:<\/p>\n\n\n\n<p><code>ENABLED=yes<\/code><\/p>\n\n\n\n<p>Now you can formally start UFW now:<\/p>\n\n\n\n<p><code>sudo ufw enable<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#install-the-nginx\"><\/a>Install the Nginx<\/h3>\n\n\n\n<p>Next we need to install the Nginx web server and reverse-proxy, as well as the Let&#8217;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&#8217;ve seen elsewhere (Nginx recently surpassed Apache as the most widely used web server on the Internet).<\/p>\n\n\n\n<p><code>sudo apt install nginx-full letsencrypt ssl-cert<\/code><\/p>\n\n\n\n<p>You&#8217;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>\n\n\n\n<p><code>sudo ufw allow 'Nginx Full'<\/code><\/p>\n\n\n\n<p>You can check if the firewall rules you requested have been enabled:<\/p>\n\n\n\n<p><code>sudo ufw status<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#outgoing-vps-email-optional\"><\/a>Outgoing VPS Email (optional)<\/h2>\n\n\n\n<p>Although it&#8217;s not absolutely necessary (you can do this section later if you&#8217;re in a big hurry), it&#8217;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&#8217;ll set up the industrial strength Postfix SMTP server, which is pretty quick and easy. First we install Postfix.<\/p>\n\n\n\n<p><code>sudo apt install postfix bsd-mailx<\/code><\/p>\n\n\n\n<p>During the install, you&#8217;ll be asked to select a bunch of configuration parameters. Select the defaults except:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select &#171;Internet Site with Smarthost&#187;,<\/li>\n\n\n\n<li>fill in the domain name for your server [domain name],<\/li>\n\n\n\n<li>the [smtp server] name and [smtp port] (in the form [smtp server]:[smtp port], e.g. smtp.oeru.org:587 ) of your &#171;smarthost&#187; who&#8217;ll be doing the authenticating SMTP for you, and<\/li>\n\n\n\n<li>the email address to which you want to receive system-related messages, [your email].<\/li>\n<\/ul>\n\n\n\n<p>After that&#8217;s done, we set a default address for the server to mail to, to [your email] selected above. First<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/aliases<\/code><\/p>\n\n\n\n<p>We need to make sure the &#171;root&#187; user points to a real email address. Add a line at the bottom which says (replacing [your email] with your email \ud83d\ude42 )<\/p>\n\n\n\n<p><code>root: [your email]<\/code><\/p>\n\n\n\n<p>After which you&#8217;ll need to convert the aliases file into a form that postfix can process, simply by running this:<\/p>\n\n\n\n<p><code>sudo newaliases<\/code><\/p>\n\n\n\n<p>Then we have to define the authentication credentials required to convince your mail server that you&#8217;re you!<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/postfix\/relay_password<\/code><\/p>\n\n\n\n<p>and enter a single line in this format:<\/p>\n\n\n\n<p><code>[smtp server] [smtp user]:[smtp password]<\/code><\/p>\n\n\n\n<p>as an example, this is more or less what I&#8217;ve got for my system. Note that the [smtp user] in my case is an email address (this is common with many smtp system &#8212; the user is the same as the email address):<\/p>\n\n\n\n<p><code>smtp.oerfoundation.org smtp-work@fossdle.org:SomeObscurePassw0rd<\/code><\/p>\n\n\n\n<p>then save the file and, like the aliases file, run the conversion process (which uses a slightly different mechanism):<\/p>\n\n\n\n<p><code>sudo postmap \/etc\/postfix\/relay_password<\/code><\/p>\n\n\n\n<p>Finally, we&#8217;ll edit the main configuration file for Postfix to tell it about all this stuff:<\/p>\n\n\n\n<p>sudo $EDIT \/etc\/postfix\/main.cf<\/p>\n\n\n\n<p>If your SMTP server uses port 25 (the default for unencrypted SMTP) you don&#8217;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&#8217;re using either of those ports, find the &#171;relayhost = [your server name]&#187; line&#8230; and add your port number after a colon, like this<\/p>\n\n\n\n<p><code>relayhost = [smtp server]:[smtp port]<\/code><\/p>\n\n\n\n<p>or, for example:<\/p>\n\n\n\n<p><code>relayhost = smtp.oerfoundation.org:465<\/code><\/p>\n\n\n\n<p>Then we have to update the configuration for Postfix to ensure that it knows about the details we&#8217;ve just defined (this command will automatically back up the original default configuration so you can start from scratch with the template below):<\/p>\n\n\n\n<p><code>sudo mv \/etc\/postfix\/main.cf \/etc\/postfix\/main.cf.orig &amp;&amp; sudo $EDIT \/etc\/postfix\/main.cf<\/code><\/p>\n\n\n\n<p>You can just copy-and-paste the following into it, substituting your specific values for the [tokens].<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># See \/usr\/share\/postfix\/main.cf.dist for a commented, more complete version\n&nbsp;\n# Debian specific:  Specifying a file name will cause the first\n# line of that file to be used as the name.  The Debian default\n# is \/etc\/mailname.\n#myorigin = \/etc\/mailname\n&nbsp;\nsmtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)\nbiff = no\n&nbsp;\n# appending .domain is the MUA's job.\nappend_dot_mydomain = no\n&nbsp;\n# Uncomment the next line to generate \"delayed mail\" warnings\n#delay_warning_time = 4h\nreadme_directory = no\n&nbsp;\n# See http:\/\/www.postfix.org\/COMPATIBILITY_README.html -- default to 3.6 on\n# fresh installs.\ncompatibility_level = 3.6\n&nbsp;\n# TLS parameters\nsmtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem\nsmtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key\n# if using port 587, this is ok\nsmtpd_tls_security_level=may\n# if using port 465, use this\n#smtpd_tls_security_level=encrypt\n&nbsp;\nsmtp_tls_CApath=\/etc\/ssl\/certs\n#smtp_tls_security_level=may\nsmtp_tls_session_cache_database = btree:${data_directory}\/smtp_scache\n&nbsp;\nsmtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination\nmyhostname = [domain name]\nalias_maps = hash:\/etc\/aliases\nalias_database = hash:\/etc\/aliases\nmyorigin = \/etc\/mailname\nmydestination = $myhostname, localhost\n# you can use either port 587, default, or 465 for greater encryption\/security\nrelayhost = [smtp server]:587\nmynetworks = 127.0.0.0\/8 [::ffff:127.0.0.0]\/104 [::1]\/128\nmailbox_size_limit = 0\nrecipient_delimiter = +\ninet_interfaces = all\ninet_protocols = all\n&nbsp;\n# added to configure accessing the relay host via authenticating SMTP\nsmtp_sasl_auth_enable = yes\nsmtp_sasl_password_maps = hash:\/etc\/postfix\/relay_password\nsmtp_sasl_security_options = noanonymous\nsmtp_tls_security_level = encrypt\n&nbsp;\n# \n# uncomment if using port 465\n#smtp_tls_wrappermode = yes<\/pre>\n\n\n\n<p>Once you&#8217;ve created that&nbsp;<code>main.cf<\/code>&nbsp;file, you can double check that your config is valid:<\/p>\n\n\n\n<p><code>sudo postfix check<\/code><\/p>\n\n\n\n<p>and if it&#8217;s all ok, you can get Postfix to re-read its configuration:<\/p>\n\n\n\n<p><code>sudo postfix reload<\/code><\/p>\n\n\n\n<p>You can then try sending an email so see if it works!<\/p>\n\n\n\n<p>By default, a command line application called &#171;mail&#187; 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&#8217;ve got things working correctly! The stuff in &lt;&gt; are the keys to hit at the end of the line&#8230;<\/p>\n\n\n\n<p><code>mail you@email.domain&lt;ENTER&gt;<\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Subject: Testing from your.relay.server.domain&lt;ENTER&gt;\nTesting postfix remote host&lt;ENTER&gt;\n&lt;CTRL-D&gt;\nCc:&lt;ENTER&gt;<\/pre>\n\n\n\n<p>Typing (hold down the Control or Ctrl key on your keyboard and press the &#171;d&#187; key) will finish your message, showing you a &#171;CC:&#187; 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>\n\n\n\n<p>You can also always check the postfix system logs to see what postfix thinks about it using the command:<\/p>\n\n\n\n<p><code>sudo less +G \/var\/log\/mail.log<\/code><\/p>\n\n\n\n<p>if your system doesn&#8217;t have a&nbsp;<code>\/var\/log\/mail.log<\/code>, never fear! Try this instead:<\/p>\n\n\n\n<p><code>sudo less +G \/var\/log\/syslog<\/code><\/p>\n\n\n\n<p>In either case, hit to have the log update in real time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#installing-the-docker-engine-docker-compose-and-lets-encrypt\"><\/a>Installing the Docker Engine, Docker Compose, and Let&#8217;s Encrypt<\/h2>\n\n\n\n<p>First let&#8217;s install the Docker Engine, which (these days) comes with Docker Compose and the&nbsp;<a href=\"http:\/\/letsencrypt.org\/\">Let&#8217;s Encrypt<\/a>&nbsp;scripts that let you procure no-cost Secure Sockets Layer certificates to secure access to your server. You can follow the&nbsp;<a href=\"https:\/\/docs.docker.com\/engine\/install\/ubuntu\/\">official Docker Engine install instructions<\/a>, but I&#8217;ve summarised them here (If the following doesn&#8217;t work for you, go back to the official instructions, because something might&#8217;ve changed since I wrote this).<\/p>\n\n\n\n<p>First we want to make sure no old Docker engines are installed on this server (this probably won&#8217;t do anything, but no harm in running it):<\/p>\n\n\n\n<p><code>for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done<\/code><\/p>\n\n\n\n<p>Second, we want to set up Docker&#8217;s &#8216;APT&#8217; repository, so you can keep Docker up-to-date with their latest versions (usually more up-to-date than those shipped with Ubuntu):<\/p>\n\n\n\n<p>First we Add Docker&#8217;s official GPG key (copy and paste all of this at your command line):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt-get update\nsudo apt-get install ca-certificates curl gnupg\nsudo install -m 0755 -d \/etc\/apt\/keyrings\ncurl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo gpg --dearmor -o \/etc\/apt\/keyrings\/docker.gpg\nsudo chmod a+r \/etc\/apt\/keyrings\/docker.gpg<\/pre>\n\n\n\n<p>Then we have to add the repository to Apt our system&#8217;s sources and install the Docker Engine:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">echo \\\n  \"deb [arch=\"$(dpkg --print-architecture)\" signed-by=\/etc\/apt\/keyrings\/docker.gpg] https:\/\/download.docker.com\/linux\/ubuntu \\\n  \"$(. \/etc\/os-release &amp;&amp; echo \"$VERSION_CODENAME\")\" stable\" | \\\n  sudo tee \/etc\/apt\/sources.list.d\/docker.list &gt; \/dev\/null\nsudo apt-get update\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin<\/pre>\n\n\n\n<p>With this approach, any updates made by the Docker community will be installed as part of your regular server upgrades.<\/p>\n\n\n\n<p>Having installed the most recent release of the Docker engine, you should find that you&#8217;ve now got Docker Compose built in. Test that by running<\/p>\n\n\n\n<p><code>docker compose version<\/code><\/p>\n\n\n\n<p>which should return something like (this is what I&#8217;m seeing as of this writing):<\/p>\n\n\n\n<p><code>Docker Compose version v2.32.4<\/code><\/p>\n\n\n\n<p>If that&#8217;s the case, you&#8217;re lookin&#8217; good!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backwards-compatibility-for-docker-compose\"><\/a>Backwards compatibility for Docker Compose<\/h3>\n\n\n\n<p>Since version 2 of the Docker Engine, the &#8216;Docker Compose&#8217; capability has been incorporated into the base system. Prior to version 2, using Docker Compose required installing a separate app, and it was run by typing&nbsp;<code>docker-compose<\/code>&nbsp;rather than&nbsp;<code>docker compose<\/code>&#8230; so something I do now, to accommodate my muscle memory of typing&nbsp;<code>docker-compose<\/code>&nbsp;is to create a tiny script that lets me keep using that command, but have it call, instead, the new&nbsp;<code>docker compose<\/code>&nbsp;functionality. I do this via<\/p>\n\n\n\n<p><code>sudo $EDIT \/usr\/local\/bin\/docker-compose<\/code><\/p>\n\n\n\n<p>into which I put the following:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#!\/bin\/bash\nD=`which docker`\n$D compose \"$@\"<\/pre>\n\n\n\n<p>After saving that, we have to make the script &#8216;executable&#8217; via<\/p>\n\n\n\n<p><code>sudo chmod a+x \/usr\/local\/bin\/docker-compose<\/code><\/p>\n\n\n\n<p>So you should now be able to run<\/p>\n\n\n\n<p><code>docker-compose version<\/code><\/p>\n\n\n\n<p>and get the same result that you did above for&nbsp;<code>docker compose version<\/code>&#8230;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#docker-use-by-non-root-user\"><\/a>Docker use by non-root user<\/h3>\n\n\n\n<p>If the above docker commands didn&#8217;t work for you&#8230; and if you want to run Docker commands without being the root user or using&nbsp;<code>sudo<\/code>, as we usually do, you need to do a few more steps&#8230;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>create a &#8216;docker&#8217; group on your system (this might already exist, but doing this again won&#8217;t hurt):&nbsp;<code>sudo groupadd docker<\/code><\/li>\n\n\n\n<li>add your user to it:&nbsp;<code>sudo usermod -aG docker $USER<\/code><\/li>\n\n\n\n<li>refresh your shell so that it recognises your user&#8217;s membership in the docker group:&nbsp;<code>newgrp docker<\/code><\/li>\n<\/ol>\n\n\n\n<p>You should now be to run a test as a non-root user&nbsp;<code>docker run hello-world<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#docker-conventions\"><\/a>Docker conventions<\/h3>\n\n\n\n<p>Now we create the set of directories I typically use for holding Docker Compose configurations (<code>\/home\/docker<\/code>) and the persistent data the Docker containers create (<code>\/home\/data<\/code>)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">D=[nextcloud domain]\nsudo mkdir -p \/home\/data\/$D\nsudo mkdir -p \/home\/docker\/$D<\/pre>\n\n\n\n<p>followed by<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">D=[onlyoffice domain]\nsudo mkdir -p \/home\/data\/$D\nsudo mkdir -p \/home\/docker\/$D<\/pre>\n\n\n\n<p>It&#8217;s helpful to make sure that your non-root user can also read and write files in these directories:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">U=[vps username]\nsudo chown -R $U \/home\/docker\nsudo chown -R $U \/home\/data<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#installing-mariadb\"><\/a>Installing MariaDB<\/h2>\n\n\n\n<p>MariaDB is effectively a drop-in alternative to MySQL and we prefer it because it&#8217;s not controlled by Oracle and has a more active developer community. On Ubuntu, MariaDB pretends to be MySQL for compatibility purposes, so don&#8217;t be weirded out by the interchangeable names below. Install the server and the client like this.<\/p>\n\n\n\n<p><code>sudo apt install mariadb-server mariadb-client<\/code><\/p>\n\n\n\n<p>You should now be able to type&nbsp;<code>sudo mysql<\/code>&nbsp;at the command prompt, and it&#8217;ll log you into the MariaDB console (to get out type&nbsp;<code>\\q<\/code>&nbsp;or&nbsp;<code>exit<\/code>)<\/p>\n\n\n\n<p>Tweak the configuration so that it&#8217;s listening on<\/p>\n\n\n\n<p><code>sudo vim \/etc\/mysql\/mariadb.conf.d\/50-server.cnf<\/code><\/p>\n\n\n\n<p>and copy the bind-address line and adjust so it looks like this &#8212; we want MariaDB to be listening on all interfaces, not just localhost (127.0.0.1)&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Instead of skip-networking the default is now to listen only on\n# localhost which is more compatible and is not less secure.\n#bind-address           = 127.0.0.1\nbind-address            = 0.0.0.0<\/pre>\n\n\n\n<p>Then restart MariaDB:<\/p>\n\n\n\n<p><code>sudo service mysql restart<\/code><\/p>\n\n\n\n<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&#8217;t allowed by your ufw firewall.<\/p>\n\n\n\n<p>To check it&#8217;s running, you can run<\/p>\n\n\n\n<p><code>sudo netstat -punta | grep 3306<\/code><\/p>\n\n\n\n<p>and you should see something like<\/p>\n\n\n\n<p><code>tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 8459\/mysqld<\/code><\/p>\n\n\n\n<p>which is the &#8216;mysqld&#8217; (the MySQL-compatible database daemon provided by MariaDB).<\/p>\n\n\n\n<p>Now set up the database which will hold NextCloud&#8217;s data. Log into the MySQL client on the host:<\/p>\n\n\n\n<p><code>sudo mysql<\/code><\/p>\n\n\n\n<p>You&#8217;ll need to gin up a password for your &#171;nextcloud&#187; database user. I usually use&nbsp;<code>pwgen<\/code>&nbsp;(<code>sudo apt install pwgen<\/code>) &#8212; for example running this command will give you a single 19 character password without special characters (just numbers and letters):<\/p>\n\n\n\n<p><code>pwgen -s 19 1<\/code><\/p>\n\n\n\n<p>Giving you something like this (but if it&#8217;s truly random, almost certainly not exactly this):<\/p>\n\n\n\n<p>bYIOSrvR9aGwL5FRGFU<\/p>\n\n\n\n<p>At the prompt (which will look something like MariaDB [(none)]&gt;) enter the following lines (putting your password in place of [passwd]):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER \"nextcloud\"@\"%\" IDENTIFIED BY \"[passwd]\";\nGRANT ALL ON nextcloud.* to \"nextcloud\"@\"%\";\nFLUSH PRIVILEGES;<\/pre>\n\n\n\n<p>Then enter&nbsp;<code>\\q<\/code>&nbsp;to exit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-nginx-reverse-proxy-for-nextcloud-and-onlyoffice\"><\/a>Configuring Nginx reverse proxy for NextCloud and OnlyOffice<\/h2>\n\n\n\n<p>Above, we installed Nginx as well as the Let&#8217;s Encrypt scripts. Now we&#8217;ll configure them as it&#8217;s useful to have them working&nbsp;<em>before<\/em>&nbsp;you set up your services.<\/p>\n\n\n\n<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 &#8216;reverse proxy&#8217; 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&nbsp;<code>https:\/\/[nextcloud domain]<\/code>&nbsp;(for NextCloud) and&nbsp;<code>https:\/\/[onlyoffice domain]<\/code>&nbsp;for OnlyOffice.<\/p>\n\n\n\n<p>Let&#8217;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>\n\n\n\n<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&nbsp;<em>prior<\/em>&nbsp;to them being created puts us in an awkward position. We use a trick to get around it: we&nbsp;<em>temporarily<\/em>&nbsp;reference the default &#8216;self-signed&#8217; SSL certificates (sometimes called &#8216;Snakeoil certs&#8217; because that&#8217;s the placeholder name they&#8217;re given) that every new Linux system generates when it&#8217;s installed, that are&nbsp;<em>valid certificates<\/em>&nbsp;(and thus acceptable to Nginx) but *they won&#8217;t work with our domains, as they&#8217;re generic and not &#8216;signed&#8217; by an external party, like Let&#8217;s Encrypt, meaning that your browser won&#8217;t like them. But that&#8217;s ok, as you browser will never need to see them, and Let&#8217;s Encrypt&#8217;s systems won&#8217;t look at them either. We&#8217;ll swap the Snakeoil certs out as soon as we&#8217;ve successfully created the Let&#8217;s Encrypt ones, and your browser will be happy, and all will be well with the world.<\/p>\n\n\n\n<p>Note: many thanks to Stephen Harlow (who crash-tested this tutorial!) for pointing out that you&nbsp;<em>might<\/em>&nbsp;need to run the following if you&#8217;re not finding the &#8216;Snakeoil certs&#8217; on your system (running them just to be safe shouldn&#8217;t cause any issues):<\/p>\n\n\n\n<p><code>sudo make-ssl-cert generate-default-snakeoil<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#lets-encrypt-setup\"><\/a>Let&#8217;s Encrypt setup<\/h2>\n\n\n\n<p>Let&#8217;s Encrypt and Nginx need to work together. Nginx stores all of its configuration in the directory&nbsp;<code>\/etc\/nginx<\/code>. The first thing we&#8217;ll do is create a place for Let&#8217;s Encrypt Nginx-specific configuration details:<\/p>\n\n\n\n<p><code>sudo mkdir \/etc\/nginx\/includes<\/code><\/p>\n\n\n\n<p>Then we create that configuration file itself:<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/nginx\/includes\/letsencrypt.conf<\/code><\/p>\n\n\n\n<p>into which we copy-and-paste the following (no [tokens] to replace in this one!)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Rule for legitimate ACME Challenge requests\nlocation ^~ \/.well-known\/acme-challenge\/ {\n    default_type \"text\/plain\";\n    # this can be any directory, but this name keeps it clear\n    root \/var\/www\/letsencrypt;\n}\n&nbsp;\n# Hide \/acme-challenge subdirectory and return 404 on all requests.\n# It is somewhat more secure than letting Nginx return 403.\n# Ending slash is important!\nlocation = \/.well-known\/acme-challenge\/ {\n    return 404;\n}<\/pre>\n\n\n\n<p>As described in the file we&#8217;ve just created, Let&#8217;s Encrypt will look for a secret code we create to verify that we own the domain we&#8217;re requesting an SSL certificate for, so we have to make sure it exists:<\/p>\n\n\n\n<p><code>sudo mkdir \/var\/www\/letsencrypt<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#nextcloud-proxy-configuration\"><\/a>NextCloud Proxy Configuration<\/h3>\n\n\n\n<p>To configure the NextCloud proxy, you need to create this configuration file in your&nbsp;<code>\/etc\/nginx\/sites-available\/<\/code>&nbsp;directory.<\/p>\n\n\n\n<p>Create a file with a meaningful name for your NextCloud Proxy, something like &#171;nextcloud&#187; (I use the domain name I&#8217;ve chosen, e.g. for docs.oeru.org I call the proxy file &#171;docs.oeru.org&#187; &#8212; keeps everything clear, and I can have&nbsp;<em>multiple instances on the same server if I want<\/em>&#8230;). Let&#8217;s go with in this instance (change it if you prefer)<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/nginx\/sites-available\/nextcloud<\/code><\/p>\n\n\n\n<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&#8217;ve missed replacing any) &#8212; and the port number 8080 if you&#8217;ve opted to change to a different one!:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">server {\n    listen 80;\n    listen [::]:80;\n&nbsp;\n    # note, you can add additional domain names, separated by a space, to which this config will answer.\n    server_name [nextcloud domain];\n&nbsp;\n    include includes\/letsencrypt.conf;\n&nbsp;\n    # enforce https\n    location \/ {\n        return 302 https:\/\/$server_name$request_uri;\n    }\n}\n&nbsp;\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n&nbsp;\n    # note, you can add additional domain names, separated by a space, to which this config will answer.\n    server_name [nextcloud domain];\n&nbsp;\n    ## Access and error logs.\n    access_log \/var\/log\/nginx\/[nextcloud domain]_access.log;\n    error_log \/var\/log\/nginx\/[nextcloud domain]_error.log;\n&nbsp;\n    # these are temporary certificates, used only long enough to secure Let's Encrypt certs as below.\n    ssl_certificate \/etc\/ssl\/certs\/ssl-cert-snakeoil.pem;\n    ssl_certificate_key \/etc\/ssl\/private\/ssl-cert-snakeoil.key;\n&nbsp;\n    # these need to be commented out until after the Let's Encrypt\n    # certificates have been acquired\n    #ssl_certificate \/etc\/letsencrypt\/live\/[nextcloud domain]\/fullchain.pem;\n    #ssl_certificate_key \/etc\/letsencrypt\/live\/[nextcloud domain]\/privkey.pem;\n&nbsp;\n    # from http:\/\/axiacore.com\/blog\/enable-perfect-forward-secrecy-nginx\/\n    ssl_session_cache shared:SSL:10m;\n    ssl_session_timeout  10m;\n    # limit_req_zone $binary_remote_addr zone=one:10m rate=1r\/s;\n    # forward secrecy settings\n    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n    ssl_prefer_server_ciphers on;\n    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\";\n    ssl_dhparam \/etc\/ssl\/certs\/dhparam.pem;\n&nbsp;\n    # Make a regex exception for `\/.well-known` so that clients can still\n    # access it despite the existence of the regex rule\n    # `location ~ \/(\\.|autotest|...)` which would otherwise handle requests\n    # for `\/.well-known`.\n    location ^~ \/.well-known {\n        # The rules in this block are an adaptation of the rules\n        # in `.htaccess` that concern `\/.well-known`.\n&nbsp;\n        location = \/.well-known\/carddav { return 301 \/remote.php\/dav\/; }\n        location = \/.well-known\/caldav  { return 301 \/remote.php\/dav\/; }\n&nbsp;\n        location \/.well-known\/acme-challenge    { try_files $uri $uri\/ =404; }\n        location \/.well-known\/pki-validation    { try_files $uri $uri\/ =404; }\n&nbsp;\n        # Let Nextcloud's API for `\/.well-known` URIs handle all other\n        # requests by passing them to the front-end controller.\n        return 301 \/index.php$request_uri;\n    }\n&nbsp;\n    location ^~ \/ {\n        proxy_pass http:\/\/127.0.0.1:8080;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"Upgrade\";\n        proxy_set_header Host $http_host;\n        proxy_read_timeout 36000s;\n        proxy_buffering off;\n        proxy_max_temp_file_size 15000m;\n    }\n    client_max_body_size 1G;\n    fastcgi_buffers 64 4K;\n    add_header Strict-Transport-Security \"max-age=31536000; includeSubdomains;\";\n    # Remove X-Powered-By, which is an information leak\n    fastcgi_hide_header X-Powered-By;\n}<\/pre>\n\n\n\n<p>Note: you&#8217;ll need to create the file cited in the proxy configuration:&nbsp;<code>\/etc\/ssl\/certs\/dhparam.pem<\/code><\/p>\n\n\n\n<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>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt update &amp;&amp; sudo apt install openssl\nsudo [ -f \"\/etc\/ssl\/certs\/dhparam.pem\" ] &amp;&amp; sudo mv \/etc\/ssl\/certs\/dhparam.pem \/etc\/ssl\/certs\/dhparam.pem.bak\nsudo openssl dhparam -out \/etc\/ssl\/certs\/dhparam.pem 2048<\/pre>\n\n\n\n<p>Once those are created, you have to make sure that they&#8217;re &#171;enabled&#187; (replacing with your file names, of course):<\/p>\n\n\n\n<p><code>cd \/etc\/nginx\/sites-enabled<\/code>&nbsp;<code>sudo ln -sf ..\/sites-available\/nextcloud .<\/code><\/p>\n\n\n\n<p>To confirm that there aren&#8217;t any typos or issues that might make nginx unhappy, run<\/p>\n\n\n\n<p><code>sudo nginx -t<\/code><\/p>\n\n\n\n<p>If all&#8217;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>\n\n\n\n<p><code>sudo service nginx reload<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#onlyoffice-proxy-configuration\"><\/a>OnlyOffice Proxy Configuration<\/h3>\n\n\n\n<p>The OnlyOffice proxy configuration uses a very similar process to the one above. You just need to create another configuration file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">upstream docservice {\n   server 127.0.0.1:9880;\n}\n&nbsp;\nmap $http_host $this_host {\n   \"\" $host;\n   default $http_host;\n}\n&nbsp;\nmap $http_x_forwarded_proto $the_scheme {\n   default $http_x_forwarded_proto;\n   \"\" $scheme;\n}\n&nbsp;\nmap $http_x_forwarded_host $the_host {\n    default $http_x_forwarded_host;\n    \"\" $this_host;\n}\n&nbsp;\nmap $http_upgrade $proxy_connection {\n  default upgrade;\n  \"\" close;\n}\n&nbsp;\nproxy_set_header Upgrade $http_upgrade;\nproxy_set_header Connection $proxy_connection;\nproxy_set_header X-Forwarded-Host $the_host;\nproxy_set_header X-Forwarded-Proto $the_scheme;\nproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n&nbsp;\nserver {\n    listen 80;\n    listen [::]:80;\n&nbsp;\n    server_name [onlyoffice domain];\n&nbsp;\n    # for let's encrypt renewals!\n    include \/etc\/nginx\/includes\/letsencrypt.conf;\n&nbsp;\n    ## Access and error logs.\n    access_log \/var\/log\/nginx\/[onlyoffice domain]_access.log;\n    error_log \/var\/log\/nginx\/[onlyoffice domain]_error.log;\n&nbsp;\n    # redirect all HTTP traffic to HTTPS.\n    location \/ {\n        return  302 https:\/\/$server_name$request_uri;\n    }\n}\n&nbsp;\n# This configuration assumes that there's an nginx container talking to the mautic PHP-fpm container,\n# and this is a reverse proxy for that Mautic instance.\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n&nbsp;\n    server_name [onlyoffice domain];\n&nbsp;\n    ssl_certificate \/etc\/ssl\/certs\/ssl-cert-snakeoil.pem;\n    ssl_certificate_key \/etc\/ssl\/private\/ssl-cert-snakeoil.key;\n    #ssl_certificate \/etc\/letsencrypt\/live\/[onlyoffice domain]\/fullchain.pem;\n    #ssl_certificate_key \/etc\/letsencrypt\/live\/[onlyoffice domain]\/privkey.pem;\n    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n    # to create this, see https:\/\/raymii.org\/s\/tutorials\/Strong_SSL_Security_On_nginx.html\n    ssl_dhparam \/etc\/ssl\/certs\/dhparam.pem;\n    keepalive_timeout 20s;\n    # for let's encrypt renewals!\n    include \/etc\/nginx\/includes\/letsencrypt.conf;\n&nbsp;\n    proxy_http_version 1.1;\n    proxy_buffering off;\n&nbsp;\n    ## Access and error logs.\n    access_log \/var\/log\/nginx\/[onlyoffice domain]_access.log;\n    error_log \/var\/log\/nginx\/[onlyoffice domain]_error.log;\n&nbsp;\n    add_header Strict-Transport-Security max-age=31536000;\n    # add_header X-Frame-Options SAMEORIGIN;\n    add_header X-Content-Type-Options nosniff;\n&nbsp;\n    # see https:\/\/github.com\/ONLYOFFICE\/document-server-proxy\/blob\/master\/nginx\/proxy-https-to-http.conf\n    location \/ {\n        proxy_pass http:\/\/docservice;\n        proxy_http_version 1.1;\n    }\n}<\/pre>\n\n\n\n<p>After that&#8217;s done, we&#8217;ll repeat what we did for the NextCloud config:<\/p>\n\n\n\n<p><code>sudo cd \/etc\/nginx\/sites-enabled<\/code>&nbsp;<code>sudo ln -sf ..\/sites-available\/onlyoffice .<\/code>&nbsp;<code>sudo nginx -t<\/code><\/p>\n\n\n\n<p>and, if there&#8217;re no errors, run<\/p>\n\n\n\n<p><code>sudo service nginx reload<\/code><\/p>\n\n\n\n<p>Now we&#8217;re ready to request Let&#8217;s Encrypt certificates.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#requesting-lets-encrypt-certificates\"><\/a>Requesting Let&#8217;s Encrypt certificates<\/h3>\n\n\n\n<p>To request Let&#8217;s Encrypt SSL certificates for your NextCloud and OnlyOffice services, run the following, replacing the [token], of course (note that &#8216;certbot&#8217; is the script provided by the Let&#8217;s Encrypt package &#8212; historically, it could also be called via &#8216;letsencrypt&#8217;, although apparently the latter is now deprecated):<\/p>\n\n\n\n<p><code>sudo certbot certonly --webroot -w \/var\/www\/letsencrypt -d [nextcloud domain]<\/code><\/p>\n\n\n\n<p>Note &#8212; if you want to address your instance from multiple domains, use one (or more)&nbsp;<code>-d [another domain]<\/code>&nbsp;&#8212; just make sure that<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>all those domains already point to your VPS, and<\/li>\n\n\n\n<li>those domains are included in the Nginx proxy configuration above.<\/li>\n<\/ul>\n\n\n\n<p>otherwise the Let&#8217;s Encrypt certbot request will fail!<\/p>\n\n\n\n<p>Here&#8217;s what you&#8217;re likely to see as output from the first run of the letsencrypt script &#8212; 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>\n\n\n\n<pre class=\"wp-block-preformatted\">Saving debug log to \/var\/log\/letsencrypt\/letsencrypt.log\nEnter email address (used for urgent renewal and security notices)\n (Enter 'c' to cancel): webmaster@fossdle.org\n&nbsp;\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\nPlease read the Terms of Service at\nhttps:\/\/letsencrypt.org\/documents\/LE-SA-v1.3-September-21-2022.pdf. You must\nagree in order to register with the ACME server. Do you agree?\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n(Y)es\/(N)o: y\n&nbsp;\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\nWould you be willing, once your first certificate is successfully issued, to\nshare your email address with the Electronic Frontier Foundation, a founding\npartner of the Let's Encrypt project and the non-profit organization that\ndevelops Certbot? We'd like to send you email about our work encrypting the web,\nEFF news, campaigns, and ways to support digital freedom.\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n(Y)es\/(N)o: y\nAccount registered.\nRequesting a certificate for [nextcloud domain]\n&nbsp;\nSuccessfully received certificate.\nCertificate is saved at: \/etc\/letsencrypt\/live\/[nextcloud domain]\/fullchain.pem\nKey is saved at:         \/etc\/letsencrypt\/live\/[nextcloud domain]\/privkey.pem\nThis certificate expires on (some future date).\nThese files will be updated when the certificate renews.\nCertbot has set up a scheduled task to automatically renew this certificate in the background.\n&nbsp;\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\nIf you like Certbot, please consider supporting our work by:\n * Donating to ISRG \/ Let's Encrypt:   https:\/\/letsencrypt.org\/donate\n * Donating to EFF:                    https:\/\/eff.org\/donate-le\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<\/pre>\n\n\n\n<p>Ideally, you&#8217;ll see a message like the above. If not, and there&#8217;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>\n\n\n\n<p>Once you have a Let&#8217;s Encrypt certificate, you can update our NGINX configuration:<\/p>\n\n\n\n<p><code>sudo $EDIT \/etc\/nginx\/sites-available\/[nextcloud domain]<\/code><\/p>\n\n\n\n<p>and swap all occurrences of<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    ssl_certificate \/etc\/ssl\/certs\/ssl-cert-snakeoil.pem;\n    ssl_certificate_key \/etc\/ssl\/private\/ssl-cert-snakeoil.key;\n#    ssl_certificate \/etc\/letsencrypt\/live\/[nextcloud domain]\/fullchain.pem;\n#    ssl_certificate_key \/etc\/letsencrypt\/live\/[nextcloud domain]\/privkey.pem;<\/pre>\n\n\n\n<p>to<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#    ssl_certificate \/etc\/ssl\/certs\/ssl-cert-snakeoil.pem;\n#    ssl_certificate_key \/etc\/ssl\/private\/ssl-cert-snakeoil.key;\n    ssl_certificate \/etc\/letsencrypt\/live\/[nextcloud domain]\/fullchain.pem;\n    ssl_certificate_key \/etc\/letsencrypt\/live\/[nextcloud domain]\/privkey.pem;<\/pre>\n\n\n\n<p>which enables your new domain-specific SSL certificate. Check that NGINX is happy with your change:<\/p>\n\n\n\n<p><code>sudo nginx -t<\/code><\/p>\n\n\n\n<p>and if so,<\/p>\n\n\n\n<p><code>sudo service nginx reload<\/code><\/p>\n\n\n\n<p>You domain should now be enabled for&nbsp;<code>https:\/\/<\/code>&nbsp;access. Note that going to&nbsp;<code>http:\/\/[nextcloud domain]<\/code>&nbsp;should automatically redirect you to&nbsp;<code>https:\/\/[nextcloud domain]<\/code>&nbsp;because you care about your user&#8217;s security! \ud83d\ude00<\/p>\n\n\n\n<p>Now you&#8217;ll have to repeat the same process for the [onlyoffice domain]. When that&#8217;s done&#8230; Onward!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#prepare-your-docker-compose-host\"><\/a>Prepare your Docker Compose host<\/h2>\n\n\n\n<p>We make use of the NextCloud community&#8217;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>\n\n\n\n<ol class=\"wp-block-list\">\n<li>a suite of NextCloud containers:<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the main PHP-FPM container (which provides most of the functionality for NextCloud using the PHP scripting engine,<\/li>\n\n\n\n<li>an identical container to the PHP one which runs the cron service (which does periodic administrative tasks relevant to NextCloud)<\/li>\n\n\n\n<li>a Redis container (which provides performance improving caching for NextCloud), and<\/li>\n\n\n\n<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>\n<\/ul>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<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>\n<\/ol>\n\n\n\n<p>Then set up a place for your Docker containers and the associated persistent data (your Docker containers should hold no important data &#8212; you should be able to delete and recreate them entirely without losing any important data or configuration):<\/p>\n\n\n\n<p>My personal convention is to name both docker and data directories after the specific domain name of the service to which they apply &#8212; 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 &#8212; but feel free to modify for your requirements. If you do so, remember to ripple that through the rest of these instructions!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#nextcloud-install\"><\/a>NextCloud Install<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#install-the-nextcloud-docker-recipe\"><\/a>Install the NextCloud Docker recipe<\/h3>\n\n\n\n<p>Now we have a place to put the really key bit &#8212; the code for running NextCloud and OnlyOffice via Docker Compose. First, let&#8217;s set up NextCloud (this also installs the OnlyOffice server):<\/p>\n\n\n\n<p><code>cd \/home\/docker\/nextcloud<\/code><\/p>\n\n\n\n<p>You&#8217;ll have to create a file, e.g via<\/p>\n\n\n\n<p><code>$EDIT docker-compose.yml<\/code><\/p>\n\n\n\n<p>and fill it with this (substituting the values in [] to suit your details &#8212; and changing the paths in \/home\/data if you&#8217;ve used something different than the default above!):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">services:\n  nginx:\n    container_name: nginx-server\n    image: nginx\n    ports:\n      - 127.0.0.1:8080:80\n    volumes:\n      - \/home\/data\/nextcloud\/nginx\/nginx.conf:\/etc\/nginx\/nginx.conf:ro\n      - \/home\/data\/nextcloud\/nextcloud:\/var\/www\/html\n    links:\n      - app\n    environment:\n      - VIRTUAL_HOST\n    restart: unless-stopped\n  app:\n    container_name: app-server\n    image: nextcloud:fpm\n    stdin_open: true\n    tty: true\n    links:\n      - redis\n    expose:\n      - '80'\n      - '9000'\n    volumes:\n      - \/home\/data\/nextcloud\/nextcloud:\/var\/www\/html\n    environment:\n      - REDIS_HOST=redis\n      - REDIS_HOST_PASSWORD=[redis password]\n    extra_hosts:\n      - \"[nextcloud domain]:[ipv4]\"\n      - \"[onlyoffice domain]:[ipv4]\"\n    restart: unless-stopped\n  cron:\n    image: nextcloud:fpm\n    volumes:\n      - \/home\/data\/nextcloud\/nextcloud:\/var\/www\/html\n    user: www-data\n    entrypoint: |\n      bash -c 'bash -s &lt;&lt;EOF\n      trap \"break;exit\" SIGHUP SIGINT SIGTERM\n      while \/bin\/true; do\n        \/usr\/local\/bin\/php \/var\/www\/html\/cron.php\n        sleep 900\n      done\n      EOF'\n    restart: unless-stopped\n  redis:\n    image: redis:alpine\n    command: redis-server --requirepass [redis password]\n    volumes:\n      - \/home\/data\/nextcloud\/redis:\/data\n    restart: unless-stopped<\/pre>\n\n\n\n<p>The &#171;port&#187; specified above, 8080, for nginx is arbitrary &#8212; I picked it to ensure it doesn&#8217;t don&#8217;t conflict with ports being used by other containers on my server &#8212; you can use this value if you want, or use&nbsp;<code>sudo netstat -punta<\/code>&nbsp;(you might need to install the package that provides netstat first,&nbsp;<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&#8217;t clash! If it scroll past too fast, you can pipe it into less to allow you to scroll and search like this:&nbsp;<code>sudo netstat -punta | less<\/code>&nbsp;&#8212; hit &#171;q&#187; to exit or &#171;\/&#187; 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&nbsp;<code>sudo netstat -punta | grep 8080<\/code>&nbsp;&#8212; if it returns any results, something is already listening on that port. If not, it&#8217;s available.<\/p>\n\n\n\n<p>The &#8216;extra_hosts&#8217; section is there to ensure that your NextCloud container can find both itself (to use its own API) and your OnlyOffice container without needing to rely on DNS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-nextcloud-nginx-configuration\"><\/a>The NextCloud Nginx configuration<\/h3>\n\n\n\n<p>You will also need to provide the &#171;nginx.conf&#187; file referenced in the nginx section of the Docker Compose configuration. Do that via<\/p>\n\n\n\n<p><code>$EDIT \/home\/data\/nextcloud\/nginx\/nginx.conf<\/code><\/p>\n\n\n\n<p>and copy-and-paste the following incantation (you shouldn&#8217;t need to change anything in this one) &#8212; there&#8217;re notes in it offering some explanations:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">worker_processes auto;\n&nbsp;\nerror_log  \/var\/log\/nginx\/error.log warn;\npid        \/var\/run\/nginx.pid;\n&nbsp;\n&nbsp;\nevents {\n    worker_connections  1024;\n}\n&nbsp;\n&nbsp;\nhttp {\n    include       \/etc\/nginx\/mime.types;\n    default_type  application\/octet-stream;\n    types {\n        text\/javascript mjs;\n        application\/wasm wasm;\n    }\n&nbsp;\n    log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                      '$status $body_bytes_sent \"$http_referer\" '\n                      '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n&nbsp;\n    access_log  \/var\/log\/nginx\/access.log  main;\n&nbsp;\n    keepalive_timeout  65;\n&nbsp;\n    set_real_ip_from  10.0.0.0\/8;\n    set_real_ip_from  172.16.0.0\/12;\n    set_real_ip_from  192.168.0.0\/16;\n    real_ip_header    X-Real-IP;\n&nbsp;\n    #gzip  on;\n&nbsp;\n    map $http_host $this_host {\n        \"\" $host;\n        default $http_host;\n    }\n&nbsp;\n    map $http_x_forwarded_proto $the_scheme {\n        default $http_x_forwarded_proto;\n        \"\" $scheme;\n    }\n&nbsp;\n    map $http_x_forwarded_host $the_host {\n        default $http_x_forwarded_host;\n        \"\" $this_host;\n    }\n&nbsp;\n    # Set the `immutable` cache control options only for assets with a cache busting `v` argument\n    map $arg_v $asset_immutable {\n        \"\" \"\";\n        default \", immutable\";\n    }\n&nbsp;\n    upstream php-handler {\n        server app-server:9000;\n    }\n&nbsp;\n    server {\n        listen 80;\n&nbsp;\n        # Add headers to serve security related headers\n        # Before enabling Strict-Transport-Security headers please read into this\n        # topic first.\n        #add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains; preload;\" always;\n        #\n        # WARNING: Only add the preload option once you read about\n        # the consequences in https:\/\/hstspreload.org\/. This option\n        # will add the domain to a hardcoded list that is shipped\n        # in all major browsers and getting removed from this list\n        # could take several months.\n        add_header Referrer-Policy \"no-referrer\" always;\n        add_header X-Content-Type-Options \"nosniff\" always;\n        add_header X-Download-Options \"noopen\" always;\n        add_header X-Frame-Options \"SAMEORIGIN\" always;\n        add_header X-Permitted-Cross-Domain-Policies \"none\" always;\n        add_header X-Robots-Tag \"noindex, nofollow\" always;\n        add_header X-XSS-Protection \"1; mode=block\" always;\n        add_header Strict-Transport-Security \"max-age=15552000; includeSubdomains;\";\n&nbsp;\n        # Remove X-Powered-By, which is an information leak\n        fastcgi_hide_header X-Powered-By;\n&nbsp;\n        # Path to the root of your installation\n        root \/var\/www\/html;\n&nbsp;\n        # Specify how to handle directories -- specifying `\/index.php$request_uri`\n        # here as the fallback means that Nginx always exhibits the desired behaviour\n        # when a client requests a path that corresponds to a directory that exists\n        # on the server. In particular, if that directory contains an index.php file,\n        # that file is correctly served; if it doesn't, then the request is passed to\n        # the front-end controller. This consistent behaviour means that we don't need\n        # to specify custom rules for certain paths (e.g. images and other assets,\n        # `\/updater`, `\/ocs-provider`), and thus\n        # `try_files $uri $uri\/ \/index.php$request_uri`\n        # always provides the desired behaviour.\n        index index.php index.html \/index.php$request_uri;\n&nbsp;\n        location = \/robots.txt {\n            allow all;\n            log_not_found off;\n            access_log off;\n        }\n&nbsp;\n        # from https:\/\/docs.nextcloud.com\/server\/28\/admin_manual\/installation\/nginx.html#nginx-config\/\n        # Make a regex exception for `\/.well-known` so that clients can still\n        # access it despite the existence of the regex rule\n        # `location ~ \/(\\.|autotest|...)` which would otherwise handle requests\n        location ^~ \/.well-known {\n            # The rules in this block are an adaptation of the rules\n            # in `.htaccess` that concern `\/.well-known`.\n&nbsp;\n            location = \/.well-known\/carddav { return 301 \/remote.php\/dav\/; }\n            location = \/.well-known\/caldav  { return 301 \/remote.php\/dav\/; }\n&nbsp;\n            location \/.well-known\/acme-challenge    { try_files $uri $uri\/ =404; }\n            location \/.well-known\/pki-validation    { try_files $uri $uri\/ =404; }\n&nbsp;\n            # Let Nextcloud's API for `\/.well-known` URIs handle all other\n            # requests by passing them to the front-end controller.\n            return 301 \/index.php$request_uri;\n        }\n&nbsp;\n        # set max upload size\n        client_max_body_size 10G;\n        fastcgi_buffers 64 4K;\n&nbsp;\n        # Enable gzip but do not remove ETag headers\n        gzip on;\n        gzip_vary on;\n        gzip_comp_level 4;\n        gzip_min_length 256;\n        gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;\n        gzip_types application\/atom+xml application\/javascript application\/json application\/ld+json application\/manifest+json application\/rss+xml application\/vnd.geo+json application\/vnd.ms-fontobject application\/x-font-ttf application\/x-web-app-manifest+json application\/xhtml+xml application\/xml font\/opentype image\/bmp image\/svg+xml image\/x-icon text\/cache-manifest text\/css text\/plain text\/vcard text\/vnd.rim.location.xloc text\/vtt text\/x-component text\/x-cross-domain-policy;\n&nbsp;\n        # Uncomment if your server is build with the ngx_pagespeed module\n        # This module is currently not supported.\n        #pagespeed off;\n&nbsp;\n        client_body_buffer_size 512k;\n&nbsp;\n        location ~ ^\\\/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|\/) { return 404; }\n        location ~ ^\\\/(?:\\.|autotest|occ|issue|indie|db_|console) { return 404;  }\n&nbsp;\n        location ~ \\.php(?:$|\/) {\n            # Required for legacy support\n            rewrite ^\/(?!index|remote|public|cron|core\\\/ajax\\\/update|status|ocs\\\/v[12]|updater\\\/.+|ocs-provider\\\/.+|.+\\\/richdocumentscode(_arm64)?\\\/proxy) \/index.php$request_uri;\n&nbsp;\n             fastcgi_split_path_info ^(.+?\\.php)(\/.*)$;\n            set $path_info $fastcgi_path_info;\n&nbsp;\n            try_files $fastcgi_script_name =404;\n&nbsp;\n            include fastcgi_params;\n            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n            fastcgi_param PATH_INFO $path_info;\n            fastcgi_param HTTPS on;\n&nbsp;\n            fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice\n            fastcgi_param front_controller_active true;     # Enable pretty urls\n            fastcgi_pass php-handler;\n&nbsp;\n            fastcgi_intercept_errors on;\n            fastcgi_request_buffering off;\n&nbsp;\n            fastcgi_max_temp_file_size 0;\n        }\n&nbsp;\n        location ~ ^\\\/nextcloud\\\/(?:updater|ocm-provider)(?:$|\\\/) {\n            try_files $uri\/ =404;\n            index index.php;\n        }\n&nbsp;\n        # Serve static files\n        location ~ \\.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ {\n            try_files $uri \/index.php$request_uri;\n            # HTTP response headers borrowed from Nextcloud `.htaccess`\n            add_header Cache-Control                     \"public, max-age=15778463$asset_immutable\";\n            add_header Referrer-Policy                   \"no-referrer\"       always;\n            add_header X-Content-Type-Options            \"nosniff\"           always;\n            add_header X-Frame-Options                   \"SAMEORIGIN\"        always;\n            add_header X-Permitted-Cross-Domain-Policies \"none\"              always;\n            add_header X-Robots-Tag                      \"noindex, nofollow\" always;\n            add_header X-XSS-Protection                  \"1; mode=block\"     always;\n            access_log off;     # Optional: Don't log access to assets\n        }\n&nbsp;\n        location ~ \\.(otf|woff2?)$ {\n            try_files $uri \/index.php$request_uri;\n            expires 7d;         # Cache-Control policy borrowed from `.htaccess`\n            access_log off;     # Optional: Don't log access to assets\n        }\n        # Rule borrowed from `.htaccess`\n        location \/remote {\n            return 301 \/remote.php$request_uri;\n        }\n&nbsp;\n        location \/ {\n            try_files $uri $uri\/ \/index.php$request_uri;\n        }\n    }\n}<\/pre>\n\n\n\n<p>That should be all the configuration you need to make the NextCloud Docker containers go.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-onlyoffice-docker-configuration\"><\/a>The OnlyOffice Docker configuration<\/h3>\n\n\n\n<p>We also need to something similar (but easier) for OnlyOffice. This is the docker-compose.yml that I use:<\/p>\n\n\n\n<p><code>cd \/home\/docker\/onlyoffice<\/code>&nbsp;<code>$EDIT docker-compose.yml<\/code><\/p>\n\n\n\n<p>and copy-and-paste this into it (replacing the []):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">version: '3'\nservices:\n  onlyoffice:\n    image: onlyoffice\/documentserver:latest\n    restart: unless-stopped\n    ports:\n      - 127.0.0.1:9880:80\n# remove the comment # from the following two lines once you've got your JWT_SECRET entered.\n#    environment:\n#      - JWT_SECRET=[onlyoffice secret]\n    volumes:\n      - \/home\/data\/onlyoffice\/data:\/var\/www\/onlyoffice\/Data\n      - \/home\/data\/onlyoffice\/logs:\/var\/log\/onlyoffice\n      - \/home\/data\/onlyoffice\/lib:\/var\/lib\/onlyoffice\n      - \/home\/data\/onlyoffice\/db:\/var\/lib\/postgresql\n    extra_hosts:\n      - \"[nextcloud domain]:[ipv4]\"<\/pre>\n\n\n\n<p>Now, we can fire it up provisionally:<\/p>\n\n\n\n<p><code>docker-compose up -d &amp;&amp; docker-compose logs -f<\/code><\/p>\n\n\n\n<p>We&#8217;ll find the value of [onlyoffice secret] a bit later, below.<\/p>\n\n\n\n<p>To get back to a command prompt without killing the running Docker container execute a&nbsp;<code>CTRL-C<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#firing-up-your-nextcloud\"><\/a>Firing up your NextCloud!<\/h2>\n\n\n\n<p>Phew &#8212; congratulations on getting here! We&#8217;ve reached the moment of truth where we need to see if this whole thing will work!<\/p>\n\n\n\n<p>We need to make sure we&#8217;re back in the NextCloud Docker directory we set up:<\/p>\n\n\n\n<p><code>cd \/home\/docker\/nextcloud<\/code><\/p>\n\n\n\n<p>Then you can run:<\/p>\n\n\n\n<p><code>docker-compose up -d &amp;&amp; docker-compose logs -f<\/code><\/p>\n\n\n\n<p>This will trigger the initial download of the docker container images you&#8217;ve specified in your&nbsp;<code>docker-compose.yml<\/code>&nbsp;file. All going well, after a few minutes (longer or shorter depending on the speed of your server&#8217;s connection) you should have download the Nginx, Redis, and NextCloud Docker images, and then the script will attempt to start them (bringing them &#171;up&#187; in daemon mode with the -d, meaning they&#8217;ll keep running even if you log out) and then, if successful, the&nbsp;<code>logs -f<\/code>&nbsp;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>\n\n\n\n<p>Once you see log messages streaming past, and no obvious &#171;container exited&#187; or other error messages (which will usually contain the word &#171;error&#187; 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 &#8216;s&#8217; from http) which should automatically&nbsp;<em>redirect<\/em>&nbsp;you to https:\/\/[nextcloud domain] as the reverse proxy file instructs.<\/p>\n\n\n\n<p>Again, to get back to a command prompt without killing the running Docker containers execute a&nbsp;<code>CTRL-C<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#the-nextcloud-source-code-if-necessary\"><\/a>The NextCloud source code (if necessary)<\/h3>\n\n\n\n<p><strong>Normally the source code for NextCloud&#8217;s current stable version is transparently downloaded and installed by the NextCloud Docker container the first time it&#8217;s instantiated<\/strong>. If it is, you&#8217;ll see a bunch of files and directories in your&nbsp;<code>\/home\/data\/nextcloud\/nextcloud<\/code>&nbsp;folder. If so, you&#8217;re fine and you can move on to the next step.<\/p>\n\n\n\n<p>If not, you can always find the most recent stable release&#8217;s&nbsp;<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:&nbsp;<a href=\"https:\/\/download.nextcloud.com\/server\/releases\/latest.tar.bz2\">https:\/\/download.nextcloud.com\/server\/releases\/latest.tar.bz2<\/a>&nbsp;(which, fingers crossed, should remain valid indefinitely &#8212; if not, check the previous link or look for &#8216;Download&#8217; on the&nbsp;<a href=\"https:\/\/nextcloud.com\/\">NextCloud website<\/a>.).<\/p>\n\n\n\n<p>We need to get that file and extract it in&nbsp;<code>\/home\/data\/nextcloud<\/code>, so do the following (if&nbsp;<code>wget<\/code>&nbsp;isn&#8217;t already installed, get it via&nbsp;<code>sudo apt install wget<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/home\/data\/nextcloud\nwget https:\/\/download.nextcloud.com\/server\/releases\/latest.tar.bz2\ntar xvfj latest.tar.bz2<\/pre>\n\n\n\n<p>which will create a directory &#8216;nextcloud&#8217; with the latest (stable) version of the NextCloud source code in that directory.<\/p>\n\n\n\n<p>Then reassert the file permissions just to be sure<\/p>\n\n\n\n<p><code>sudo chown -R www-data nextcloud<\/code><\/p>\n\n\n\n<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>\n\n\n\n<p>You can figure out what version that is by running:<\/p>\n\n\n\n<p><code>cat nextcloud\/version.php | grep VersionString<\/code><\/p>\n\n\n\n<p>With my latest install, I get the result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$OC_VersionString = '30.0.5';<\/pre>\n\n\n\n<p>Note, I tend to hold on to install archives for safety&#8217;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 (30.0.5 in my case):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mkdir attic\nmv latest.tar.bz2 attic\/nextcloud_[version].tar.bz2<\/pre>\n\n\n\n<p>Now you&#8217;ve got the source code for NextCloud where you containers are configured to look for it!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-database-access\"><\/a>Configuring database access<\/h2>\n\n\n\n<p>On doing so, if all is well, you should be directed through the database set up process for your NextCloud instance. You&#8217;ll be asked for your database details, which should be:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">database IP: 172.17.0.1 - this is the default IP of the Docker host server.\ndatabase name: [db name]\ndatabase user: [db user]\ndatabase password: [db password]<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-the-admin-user\"><\/a>Configuring the Admin user<\/h2>\n\n\n\n<p>Once that&#8217;s set and working, NextCloud will install all the relevant database tables and initial data. You&#8217;ll be asked to set up an admin user account, which can be &#171;admin&#187; and some strong password you create (you can use the&nbsp;<code>pwgen<\/code>&nbsp;utility you used earlier) &#8212; I&#8217;d recommend recording it somewhere.&nbsp;<em>I would not recommend making your own account, in your name, the main admin account<\/em>. Instead, I recommend creating a second account,&nbsp;<em>with administrator privileges<\/em>, for yourself, but leave the admin account purely for administrative activities.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-outgoing-email\"><\/a>Configuring Outgoing Email<\/h2>\n\n\n\n<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&#8217;ve forgot theirs. For this, you&#8217;ll need the authenticating SMTP account details from the start of this process. You&#8217;ll need:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">SMTP server : an IP address or a domain name\nSMTP username: a username or an email address\nSMTP password: a strong password already configured for the username on that server\nSMTP login security: whether login is via TLS, SSL, or unsecure (!!), and\nSMTP login method: plain, encrypted, \"login\" or some other value.<\/pre>\n\n\n\n<p>You should be able to test your email settings to make sure the details you&#8217;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 &#8212; should have a path of&nbsp;<code>https:\/\/[nextcloud domain]\/settings\/admin<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#setting-up-onlyoffice\"><\/a>Setting up OnlyOffice<\/h2>\n\n\n\n<p>The OnlyOffice server should already be running &#8212; if you point your browser at&nbsp;<code>https:\/\/[onlyoffice domain]<\/code>&nbsp;you should see a page like the attached screenshot with the OnlyOffice Logo and a title of &#171;OnlyOffice Docs Community Edition&#187;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#configuring-onlyoffice-integration-with-nextcloud\"><\/a>Configuring OnlyOffice Integration with NextCloud<\/h2>\n\n\n\n<p>To configure your NextCloud to use your OnlyOffice, the OnlyOffice will require that NextCloud knows its &#171;secret&#187;. To generate the secret, run this in&nbsp;<code>\/home\/docker\/onlyoffice<\/code>:<\/p>\n\n\n\n<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>\n\n\n\n<p>The resulting&nbsp;<em>secret<\/em>&nbsp;string, which will look something like&nbsp;<code>QC7QmEqUpXmmnwXZcvBQ<\/code>&nbsp;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&#8217;t set, it&#8217;ll be generated each time you restart OnlyOffice and your NextCloud will need a different &#8216;secret&#8217; each time &#8212; a major inconvenience).<\/p>\n\n\n\n<p><code>$EDIT \/home\/docker\/onlyoffice\/docker-compose.yml<\/code><\/p>\n\n\n\n<p>Add it in place of&nbsp;<code>#- JWT_SECRET=[onlyoffice secret]<\/code>&nbsp;<em>and also remove the &#8216;#&#8217; that&#8217;s commenting out the line<\/em>&nbsp;&#8212; again, thanks to Stephen Harlow for pointing out that this is required! Then restart OnlyOffice via<\/p>\n\n\n\n<p><code>docker-compose up -d<\/code><\/p>\n\n\n\n<p>Docker will see that the container&#8217;s configuration has changed and will restart the container.<\/p>\n\n\n\n<p>Next you need to be logged into your NextCloud as an administartive user (your own user is fine if you&#8217;ve given it admin privileges).<\/p>\n\n\n\n<p>You should have an &#171;admin&#187; menu (assuming you&#8217;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 &#171;Hub bundle&#187; available under the &#171;App bundles&#187; option (see attached image). If you don&#8217;t want the whole bundle you can just use the search box to search for &#171;OnlyOffice&#187; or go to the &#171;Office &amp; text&#187; App category and enable the OnlyOffice &#171;official&#187; 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>\n\n\n\n<p>Once you&#8217;ve done that, go to your top right menu again, selecting Admin, and you should see &#171;OnlyOffice&#187; as an option in the left column (which starts with &#171;Basic settings&#187;). Selecting that, you&#8217;ll need to enter the following:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\"Document Editing Service address\": https:\/\/[onlyoffice domain]\n\"Secret key\": [onlyoffice secret]<\/pre>\n\n\n\n<p>You don&#8217;t need to set any &#8216;advanced settings&#8217;, although have a look at them so you know what else is available.<\/p>\n\n\n\n<p>When you&#8217;re done, click &#171;Save&#187;.<\/p>\n\n\n\n<p>You can also select formats you&#8217;d like OnlyOffice to open and edit files of those types are clicked or created. I&#8217;ve selected the following: doc, docx, odp, ods, odt, ppt, pptx, xls, xlsx, and in the second section: csv and txt.<\/p>\n\n\n\n<p>You can also make other editor customisations as you desire. The only Editor customisation setting I haven&#8217;t selected is &#171;Display Chat menu button&#187; because NextCloud Hub provides an integrated Chat service, making this one within OnlyOffice an unnecessary distraction.<\/p>\n\n\n\n<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 &#171;+&#187; next to the home icon (top left of the folder pane) you should now have the option to create (in addition to &#171;Upload file&#187;, &#171;New folder&#187;, &#171;New text file&#187;) a &#171;New Document&#187;, &#171;New Spreadsheet&#187;, and &#171;New Presentation&#187;. Clicking those should give you the OnlyOffice interface for the designated content type.<\/p>\n\n\n\n<p>Similarly, you can use the &#171;Upload file&#187; 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>\n\n\n\n<p>It is saved as it is changed, so you shouldn&#8217;t need to save it explicitly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>\u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0430\u043a\u0443\u043f )<\/p>\n\n\n\n<p>\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b.<\/p>\n\n\n\n<p><code>docker-compose pull<\/code><\/p>\n\n\n\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b.<\/p>\n\n\n\n<p><code>docker-compose up -d<\/code><\/p>\n\n\n\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u0442 \u0432 \u0440\u0435\u0436\u0438\u043c \u0422\u041e&#8230; \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0435\u0440\u0435\u0437 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f (\u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0445\u043e\u0441\u0442).<\/p>\n\n\n\n<p>sudo docker exec -ti &#8212;user www-data app-server \/var\/www\/html\/occ maintenance:mode &#8212;on<\/p>\n\n\n\n<p>sudo docker exec -ti &#8212;user www-data app-server \/var\/www\/html\/occ upgrade<\/p>\n\n\n\n<p>sudo docker exec -ti &#8212;user www-data app-server \/var\/www\/html\/occ maintenance:mode &#8212;off<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backing-up-nextcloud\"><\/a>Backing up NextCloud<\/h2>\n\n\n\n<p>To back up your instance on your server, you need two things: a file system backup of your&nbsp;<code>\/home\/data\/nextcloud<\/code>&nbsp;directory, and database dumps of your database.<\/p>\n\n\n\n<p>There&#8217;re lots of ways to back up your files (I&#8217;ve recently updated to using a system called Restic to make off-server incremental encrypted backups &#8212; I plan to document this in a future howto! &#8212; although there&#8217;re other documented approaches &#8212; leave a comment below if you&#8217;d like to learn more about my approach!).<\/p>\n\n\n\n<p>Backing up your MariaDB databases is as easy installing automysqlbackups:<\/p>\n\n\n\n<p><code>sudo apt install automysqlbackups<\/code><\/p>\n\n\n\n<p>You&#8217;ll find daily versioned dumps of your MariaDB database(s) in \/var\/lib\/automysqlbackups on your VM host&#8217;s filesystem. To run an ad hoc backup (which will replace the previous backup from that day, if there is one) just run<\/p>\n\n\n\n<p><code>sudo automysqlbackups<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/tech.oeru.org\/install-nextcloud-hub-and-onlyoffice-ubuntu-2404-docker-compose#backup-onlyoffice\"><\/a>Backup OnlyOffice<\/h2>\n\n\n\n<p>Note: I&#8217;m not entirely sure there&#8217;s anything important to your personal data being stored in the database at accompanies the OnlyOffice default Docker container. I haven&#8217;t bothered backing it up, and haven&#8217;t missed it so far&#8230; (fingers crossed).<\/p>\n\n\n\n<p>But if you&#8217;re wanting to be extra sure, here&#8217;s how you can do it:<\/p>\n\n\n\n<p>Along with backing up the files in your&nbsp;<code>\/home\/data\/onlyoffice<\/code>&nbsp;directory, you&#8217;ll also want a proper &#171;dump&#187; 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>\n\n\n\n<p><code>cd \/home\/docker\/onlyoffice<\/code><\/p>\n\n\n\n<p>and running this<\/p>\n\n\n\n<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>\n\n\n\n<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 \ud83d\ude42<\/p>\n\n\n\n<p>At some point, I&#8217;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&nbsp;<a href=\"https:\/\/git.oeru.org\/\">https:\/\/git.oeru.org<\/a>&nbsp;&#8212; it&#8217;ll probably be a small modification to this script:&nbsp;<a href=\"https:\/\/git.oeru.org\/oeru\/docker-compose-dbbackup\">https:\/\/git.oeru.org\/oeru\/docker-compose-dbbackup<\/a>&nbsp;in case someone wants to beat me to it!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is yet another update of my previous posts (installing&nbsp;NextCloud with Collabora Office Online on Ubuntu 16.04&nbsp;and then&nbsp;NextCloud with OnlyOffice on Ubuntu 18.04&nbsp;and&nbsp;Install NextCloud Hub and OnlyOffice on Ubuntu 22.04 with Docker Compose).&nbsp;NextCloud&nbsp;continues to develop at a blistering rate, and as of this writing, it&#8217;s at version 30.0.5. This is fortunate, as countries in the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[5],"tags":[],"class_list":["post-285","post","type-post","status-publish","format-standard","hentry","category-linuxfreebsd"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p7ekzS-4B","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/posts\/285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/altai22.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=285"}],"version-history":[{"count":3,"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/posts\/285\/revisions"}],"predecessor-version":[{"id":331,"href":"https:\/\/altai22.ru\/index.php?rest_route=\/wp\/v2\/posts\/285\/revisions\/331"}],"wp:attachment":[{"href":"https:\/\/altai22.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/altai22.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/altai22.ru\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}