Build Guide: Nextcloud Server

Interested in the convenience of the cloud, but want meaningful ownership of your data? Looking for a starter project to get into Linux systems administration or work with the popular LAMP stack? Follow along to learn how to setup your own Nextcloud server - manually - from soup to nuts.

Based on an excellent video tutorial by Jacob from


You'll need a few things to get started:

  • Your own domain
  • A Linux server
  • A password manager (seriously, you'll be creating a gazillion different username/password combinations very soon)
  • A desire to learn
  • Recommended: An SFTP client like Transmit (allows you to use nice GUI text editors like Atom or VS Code)


  • All commands listed here are to be run as root unless instructed otherwise
  • This guide assumes you are using a Debian-based Linux distribution on your server, but that isn't required. Just make sure you know the equivalent commands for actions like package management on your preferred distro; for example, replace apt with yum on CentOS or RHEL.

Step 0: Housekeeping

Find your server's IP address

If you're using a VPS, your server's IP address should be listed in your hosting provider's admin console. If not, such as if you're using a physical server on-prem, run the following:

sudo -u www-data curl

This pings, a cool website that tells you your public IP address, along with a bunch of other stuff.

Why the sudo -u... prepending the curl command? Why not just run curl?

Great question!

As a general rule, I don't like to download code, even that which is likely harmless, while elevated. This command runs curl as the www-data user, normally used only by apps like web servers (including apache, the server we'll be using today). Not only is this user unprivileged, its' shell access is disabled (directs to /sbin/nologin/). This means: the only way to run commands as this user is to actually run them using sudo -u www-data <command-to-run> while logged in as a privileged user (in this case, root).

Update your server:

The packages on your server probably aren't all up to date. Let's fix that.

Login as root...

ssh root@<your-server-ip>

...and update all installed packages:

apt update && apt upgrade -y

Great, your packages are all up to date.

Go ahead and reboot your server now, in case any of them are kernelspace updates:

reboot now

Point your domain at your server

We need to make sure traffic meant for your Nextcloud server actually reaches your it!

Open your domain admin panel and create a new A record. Point it at your server's IP address.

In the hostname section, type a subdomain you want to use (if any). Otherwise, if you want to use the entire domain for your Nextcloud instance (not recommended), type an @.

Note: Depending on your DNS provider, your domain settings may take a while to propagate. Don't be surprised if attempting to connect to your server via its domain doesn't work for a few minutes to a few hours.

Step 1: Install required packages

Our installation of Nextcloud will require the following components:

  • Web server
    • Apache Web server
    • Certbot (for TLS)
  • Database server
    • MariaDB, a MySQL-compatible database software
  • PHP
    • Runtime & support libraries for the PHP language, which Nextcloud is written in
  • Utilities
    • wget (for easily downloading files from command line)
    • unzip (self explanatory)

Login to your server as root:


Now, run the following commands to install the necessary packages:


apt install apache2
apt install python-certbot-apache


apt install mariadb-server


apt install php libapache2-mod-php php-mysql php-gd php-json php-curl
apt install php-mbstring php-intl php-imagick php-xml php-zip php-apcu

apt install wget unzip

Step 2: Setup Apache web server

Start Apache 2:
systemctl start apache2

Enable the Apache daemon (so Apache starts whenever your machine does):
systemctl enable apache2

Add your domain name to Apache's configuration files

On your server, edit the file /etc/apache2/sites-available/000-default.conf in your preferred text editor.

Find the line:

And change it to:, replacing subdomain and yourdomain with your subdomain/domain. Delete the # to uncomment the line.

Now restart Apache to apply the changes:
systemctl restart apache2

Step 3: Setup TLS (HTTPS)

We'll use cerbot to obtain a free TLS certificate from LetsEncrypt. You installed it earlier as part of the python-certbot-apache package. Time to set that up.

Run Certbot:
certbot --apache

Certbot will ask you to enter an email address for your site's administration:

Enter email address (used for urgent renewal and security notices) (Enter 'c' to

You can safely do this; don't worry, it isn't public. It'll also ask you to agree to the terms:

Please read the Terms of Service at You must
agree in order to register with the ACME server at

Choose A to agree to the terms.

It'll then ask:

Which names would you like to activate HTTPS for?
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):



You should now see the following:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
1: No redirect - Make no further changes to the webserver
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

Choose 2: Redirect. This will ensure that all connections to your server are done securely over https.

Now restart Apache to apply your settings:

systemctl restart apache2

Great! Basic TLS is setup on your server!

Harden TLS

Before we go any further, we'll harden the TLS configuration. This is your own personal cloud, storing your sensitive data, after all.

We'll enable HSTS (HTTP Strict Transport Security) by using a feature of Apache called mod headers. This forces clients connecting to use an encrypted HTTPS connection, whether or not they requested it, reducing the possibility for attackers to conduct tls stripping attacks.

Edit the file: /etc/apache2/sites-enabled/000-default-le-ssl.conf

Below ServerName, add the following IfModule:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security “max-age=15552000; includeSubDomains; preload”

Sweet, HSTS is enabled! Your config file should look something like this:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload"

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

Now that HSTS is enabled, run the following command to apply the changes:

a2enmod headers

This makes your Nextcloud server tell all web browsers/clients connecting to it:

"Hey, I'm an https only server! If you see me accepting plaintext http requests in the future, don't connect! You're proably talking to a different server run by someone nefarious!"

Step 4: Install the database server

This is where the password manager comes in. Remembering long passwords that you're probably never going to type in again would be absurdity, so we'll ask our password manager to help us with that.

Generate and store a nice, long password, with no special characters. This will be the root password for our mariadb database server.

Got it? Great!

Now, run the following command to install MariaDB:


You'll be asked to set the root password for MariaDB. Generate one in your password manager, then type it in.

You'll be asked a few more questions:

Remove anonymous users? [Y/n]

Answer y, you don't need them

Disallow root login remotely? [Y/n]

Answer y. Don't worry, this is just for the database and won't mess with your ssh configuration.

Remove test database and access to it? [Y/n]

Answer y, you don't need the test database.

Reload privilege tables now? [Y/n]

Answer y to apply the changes immediately.

You should now see the following:

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Great! Your database server is now installed!

Step 5: Setup the database

Now that you've installed and secured MariaDB, the next step is to use it to setup a database for your Nextcloud server.

Start a MariaDB session by typing: mariadb

You'll see a new screen with a different prompt like this:

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 30
Server version: 10.1.38-MariaDB-0ubuntu0.18.04.1 Ubuntu 18.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

You're about to actually appreciate your caps lock key, for once in your life.

Using the following command, create a database called nextcloud_db.

CREATE DATABASE nextcloud_db;

Now you'll need to create a MariaDB user to access this database. We'll call this user nextcloud.

Your password manager is, once again, your best friend here. Have it generate and store another long password with no special characters.

Got one? Great, proceed.

To create the new user, use the following command:

CREATE USER nextcloud IDENTIFIED BY 'your-password-here';

Now you have to give this nextcloud user access to the nextcloud_db database.

Do this with the following commands:

GRANT USAGE ON nextcloud_db.* TO nextcloud@localhost IDENTIFIED BY 'password-from-last-command';
GRANT ALL privileges ON nextcloud_db.* TO nextcloud@localhost;

Kawabunga, you've given the database user the permissions it needs!

Now let's make sure the changes you made are applied with this command:


Now, exit mariadb. I promise it's easier than exiting vim!

Just type:quit;

That wasn't so tough now, was it?

Step 6: Install Nextcloud

All the necessary packages are installed. The web and database servers are setup. You've secured the installation and configured TLS. Yes, it's finally time. Let's install Nextcloud on your server!

Install files (source code)

Head over to the Nextcloud download page. Copy that big shiny "Download Nextcloud" link.


Now, head back to your ssh session. Download the latest release of Nextcloud on your server from that link you just copied:

sudo -u www-data wget

Extract the download...


...and copy all the files recursively in the resulting nextcloud folder into /var/www/html.

cp -rf ./nextcloud/. /var/www/html

Note the . after nextcloud/.. Don't omit this! Adding the period after the / tells the OS to copy all the files in this directory including the hidden ones - which we need! Specifically, the .htaccess and .user.ini files, which are used for Apache and PHP configuration. We'll get into this later.

Change Permissions

Great, you've gotten the goods Nextcloud needs to run, and put them in the right bin. Now we need to give your web server access to them.

Apache runs as a special Linux user, www-data. To let it access the application files you just downloaded, you need to give this user recursive ownership of the directory we just put them in, /var/www/html.

We can do this with the following command:

chown -R www-data:www-data /var/www/html/.

Once again - take care not to omit the . at the end! We want to change ownership of all the files here, not just the visible ones!

Ha-zah! You've installed the Nextcloud package!

Choose where to store your files

We're almost ready to visit our web GUI to setup our server - but we need one more thing - a place to store our data!

You really can put this anywhere you like; though I advise against putting it in /var/www/html for security reasons. For this example, we'll make a dedicated directory in the root of our drive, called nextcloud-data.

This one's easy. Just make the directory, wherever you want...

mkdir /nextcloud-data

...and give ownership of it to the www-data user so Apache (Nextcloud) can access it:

chown www-data:www-data /nextcloud-data

Now, restart Apache to make sure all our settings are applied:

systemctl restart apache2

7. GUI Setup

Now comes the fun part - seeing your Nextcloud instance actually work for the first time!

Open your preferred web browser and go to your newly-created Nextcloud server's domain:


Create an admin account. Note: This is just the admin account; you won't be using it for day-to-day activities. You can call it whatever you want. In the spirit of Linux, let's call this one: root.

In the "Data Folder" box, type the path of the directory you chose to hold your data; in this case, /nextcloud-data.

Scroll down. You'll see boxes for database user, database password, and database name.


Recall from earlier how we setup a database user nextcloud, and a database, nextcloud_db. Input these accordingly, along with the password you created. Leave the database location as localhost, and ignore the instructions to specify a port.

Now click Finish. If all goes well, the page will lag for a second, like this...


...and in a few moments, will show you a nice splash screen, like this:


Congratulations! You have a basic, running Nextcloud server!

Step 8: Cleaning up

Your server is now technically operational - but don't stop here!

There's still a few steps to go to make sure your Nextcloud server operates at peak performance.


Hand over control of Apache to Nextcloud

Remember those two hidden files we paid such meticulous attention to earlier - .htaccess and .user.ini? This is where they come in.

.htaccess, for example, is supposed to control how our Apache web server operates. Right now, our server is ignoring both of these files. Let's fix that.

Edit the file /etc/apache2/sites-enabled/000-default-le-ssl.conf (the same one where enabled HSTS and mod headers).

Underneath the IfModule we created earlier, add the following Directory statement:

<Directory /var/www/html/>
    Options +FollowSymlinks
    AllowOverride All

Your settings should now look like this:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload"
<Directory /var/www/html/>
    Options +FollowSymlinks
    AllowOverride All

We've now told Apache to use the settings from the .htaccess file located in /var/www/html/, essentially handing off control of it to the Nextcloud application.

Set reasonable file operation limits

Right now, php has very little memory to work with. So little, in fact, that it's practically useless. Let's give it a little more.

PHP's settings are controlled by the file /etc/php/7.2/apache2/php.ini.

Edit it, and find the following lines:

PHP memory limit: (memory_limit)

Set to: memory_limit = 512M

Largest size of a POST request (post_max_size):

Set to:
post_max_size = 512M

Maximum file upload size: (upload_max_filesize):

Set to: upload_max_filesize = 512M

Apply the configuration by restarting apache:

systemctl restart apache2

Great - PHP now has a reasonable amount of memory to work with!

Can I set these limits higher?

Great question!

While you can absolutely set higher limits than those shown in this tutorial, please note that the maximum memory_limit you can set here is (predictably) dependent on your system's available RAM.

Setup Memory Caching

Memory caching increases the performance and responsiveness of your Nextcloud server by minimizing the amount of similar operations that have to be performed.

For this installation, we'll use the PHP extension php-apcu that we installed earlier for our memcache.

Edit /var/www/html/config/config.php

Add the following line at the bottom of the configuration lines:

'memcache.local’ => ‘\OC\Memcache\APCu’,

Save the file end exit the text editor. Now edit the file:


Find the lines:








Uncomment all of them (delete the semicolons[;] in front of them).

Now, set them to the following values:








Save the file and exit the editor.

Now, restart Apache to apply the changes:

systemctl restart apache2

Your memcache is setup!

Your Nextcloud server should now be nice and zippy!

Fix improperly displayed unicode characters

By default, MySQL/mariadb does not support 4-byte character strings. This means emojis and some other unicode characters won't display properly. That could be anything from mildly annoying to totally debilitating, depending on the language your Nextcloud server is set to. Note: I highly advise against skipping this step. All my Nextcloud servers are set to US English, and I still experienced this issue prior to making this change.

First, let's put Nextcloud into maintenance mode to avoid borking the database as we work on it. We do this using the occ command, run as the user www-data, because occ is located in /var/www/html, which we gave www-data ownership of earlier.

We can do this with the following command:

sudo -u www-data php /var/www/html/occ maintenance:mode --on

You can verify that your server is indeed in maintenance mode by attempting to access it from your web browser. You should see this:


Now that our server is in maintenance mode, we can get to work.

Open a MariaDB session with the mariadb command:

root@testcloud:~# mariadb
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 192
Server version: 10.1.38-MariaDB-0ubuntu0.18.04.1 Ubuntu 18.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

We now need to make a change to MariaDB's InnoDB settings to support these 4-byte characters.

Run the following command to alter the character set in our nextcloud_db database to utf8mb4:

ALTER DATABASE nextcloud_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

Now change MariaDB's InnoDB settings to Nextcloud's recommended values with the following commands:

SET GLOBAL innodb_file_format=barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

Now quit MariaDB:


We've changed our MariaDB settings to be compatible with the changes we need to make to our Nextcloud database. Now we need to let Nextcloud know about these changes so it can apply them.

Run the following command to do so:

sudo -u www-data php /var/www/html/occ config:system:set mysql.utf8mb4 --type boolean --value="true"

Now that we've told Nextcloud about the changes to our database, we'll need to tell it to run the data conversions to apply them. We'll use the maintenance:repair occ command to do this.

sudo -u www-data php /var/www/html/occ maintenance:repair

It'll run a conversion and spit out lots of text (hopefully with no errors :)

Now that that's done, take your Nextcloud server out of maintenance mode with the following command:

sudo -u www-data php /var/www/html/occ maintenance:mode --off

Yahoo! Bing! Google! Your Nextcloud instance now supports unicode characters and will render them properly!

Step 9: Finishing touches

You actually could stop here if you wanted. Your server is fully setup and ready to roll. In fact, if you visit your server's Security & setup warnings section (, you'll see a nice, friendly, green checkmark, letting you know everything's in good working order:


All the work we did in the that last 8 steps paid off - as you can see, no warnings or errors here!

But best practices are...the best let's follow some best practices! Say that 5 times fast!

Create a standard user account

As I alluded to earlier - running in a permanently elevated context is, generally speaking, a bad idea. If you were to run this way, and your credentials were ever stolen, the thieves would have unfettered, administrative access to your server in its' entirety. We don't want that!

Instead, let's make an unprivileged account for day-to-day use. Log into your Nextcloud instance in a web browser, click the profile icon in the top-right corner, and click the Users button.


You can figure the rest of this step out from here. I have faith in you.


Connect your email server

This is an optional step that may or may not apply to you. If you're using your server in a small, personal, single-user setting, you can ignore it. Otherwise, you should set this up. This allows users to self-reset their forgotten passwords, receive sharing notifications via email, and more.

From the Admin account, to Settings > Basic Settings > Email server.

Note that Nextcloud doesn't include its' own mail server; you'll need an external mail account that supports SMTP.

Probably goes without saying, but don't use your personal email for this! Make a service account on your domain like


The rest of this step is self-explanatory.

Step 10: Poke around!

This is the fun part! Add some apps to extend your Nextcloud experience!

If you've ever used Wordpress plugins, you'll find yourself right at home. The Nextcloud apps are generally of higher quality than most Wordpress plugins, however, and are almost all free & open source software.

The easiest way to add these is through the Apps interface in the admin account, right next to the Settings button in the corner menu you clicked earlier.

Want a web calendar interface for the CalDAV server built into your Nextcloud? Here you go!


Care to customize your colors, add a privacy policy, switch up your favicon or change the logo on your interface to match your company's? Go for it in the theming settings!


How about a nice web GUI for managing your contacts on the included CardDAV server? Nextcloud has you covered!


You get the idea. Running this server for your organization with an existing LDAP/AD server that you'd like to use for user management? There's an app for that!


That's it for today, folks. Where you go from here is up to you.

I hope you learned something :)

Engineer of The Clouds | They/Them
The Friendly Skies ✈️