Nextcloud is recognized as the leading open-source self-hosted file sync and sharing software. It is an alternative to various file-sharing applications such as Google Drive, Dropbox, OwnCloud, and more. Nextcloud offers extensive functionalities like file synchronization and sharing, online document editing, calendar organization, contact management, and numerous others. This tutorial will illustrate how to install Nextcloud on AlmaLinux 9.
Table of Contents
Prerequisites
- An AlmaLinux 9 VPS.
- SSH access with sudo privileges, or root access.
Conventions
# – given commands should be executed with root privileges either directly as a root user or by use of sudo command
$ – given commands should be executed as a regular user
Step 1: Log in to your server via SSH
This tutorial will use root to install everything and execute commands. If you use another system user with sudo privileges, you must add ‘sudo’. First, let’s log in to our Almalinux 9 machine.
ssh root@IP_Address -p Port_number
You will need to replace ‘IP_Address’ and ‘Port_number’ with your server’s respective IP address and SSH port number. Additionally, replace ‘root’ with the username of the system user with sudo privileges.
You can check whether you have the proper AlmaLinux version installed on your server with the following command:
# cat /etc/redhat-release
You will see this as the output:
AlmaLinux release 9.4 (Seafoam Ocelot)
Step 2: Update the System
Before starting, ensure that all AlmaLinux OS package information about applications installed on the server is up to date. You can do this by running the following commands:
# dnf update
Step 3: Install PHP 8
At the time of this writing, the default version of PHP on AlmaLinux 9 is PHP 8.0. According to the Nexcloud system requirements at https://docs.nextcloud.com/server/latest/admin_manual/installation/system_requirements.html we are going to install PHP 8.3 and use it for Nextcloud installation.
# dnf -y install https://rpms.remirepo.net/enterprise/remi-release-9.2.rpm
# dnf update
Once updated, we can check all available PHP versions to install on our AlmaLinux server after installing the Remi repo.
# dnf module list php
You will see an output like this:
[root@rh ~]$# dnf module list php
Last metadata expiration check: 0:00:17 ago on Wed 19 Jun 2024 03:51:07 AM CDT.
AlmaLinux 9 - AppStream
Name Stream Profiles Summary
php 8.1 common [d], devel, minimal PHP scripting language
php 8.2 common [d], devel, minimal PHP scripting language
Remi's Modular repository for Enterprise Linux 9 - x86_64
Name Stream Profiles Summary
php remi-7.4 common [d], devel, minimal PHP scripting language
php remi-8.0 common [d], devel, minimal PHP scripting language
php remi-8.1 common [d], devel, minimal PHP scripting language
php remi-8.2 common [d], devel, minimal PHP scripting language
php remi-8.3 common [d], devel, minimal PHP scripting language
As seen above, we should be able to install PHP 8.3 now.
To enable the default source to get this scripting package installed on our AlmaLinux machine, we need to reset it first, then mention the desired version to enable.
# dnf module reset php
# dnf module enable php:remi-8.3
That’s it, we have swiched to PHP 8.3. Now, to install PHP 8.3 with its required extensions, we can execute this command below:
# dnf install php php-{bz2,ctype,curl,fpm,gd,imagick,intl,json,fileinfo,libxml,mbstring,mysqlnd,openssl,posix,session,simplexml,xmlreader,xmlwriter,zip,zlib}
Once the installation is completed, the PHP-FPM service will run but will not be enabled upon server reboot. You can check and verify the installed PHP version with this command.
# php -v
It will return an output like this:
[root@almalinux8 ~]# php -v
PHP 8.3.8 (cli) (built: Jun 4 2024 14:53:17) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.8, Copyright (c) Zend Technologies
with Zend OPcache v8.3.8, Copyright (c), by Zend Technologies
Step 4: Configure PHP-FPM
In an Almalinux machine, the ‘user’ and ‘group’ in /etc/php-fpm.d/www.conf are defaulted to ‘apache.’ Since we will use nginx as the webserver, we need to edit the configuration file.
# vim /etc/php-fpm.d/www.conf
Change the ‘user’ and ‘group’ to ‘nginx’.
user = nginx
group = nginx
Save the file, then exit. Afterward, we will edit some PHP values required for Nextcloud installation.
# vim /etc/php.ini
Uncomment and change the configuration values as below.
memory_limit = 768M
date.timezone = America/Chicago
cgi.fixpathinfo = 0
We also need to change the permission of the PHP session and OpCache directories.
# chown -R root.nginx /var/lib/php/opcache/
# chown -R root.nginx /var/lib/php/session/
Then, let’s restart PHP-FPM and enable it upon reboot.
# systemctl restart php-fpm
# systemctl enable php-fpm
Step 5: Install and Configure Nginx
After configuring the PHP-FPM, we will install and configure nginx as the webserver, not Apache. Run this command to install it.
# dnf install nginx -y
Start nginx and enable it on boot.
# systemctl enable --now nginx
Let’s create an nginx server block.
# vim /etc/nginx/conf.d/cloud.example.com.conf
Paste the following and make sure you replace cloud.example.com with your actual domain or subdomain name:
upstream php-handler {
server unix:/run/php-fpm/www.sock;
}
# Set the `immutable` cache control options only for assets with a cache busting `v` argument
map $arg_v $asset_immutable {
"" "";
default "immutable";
}
server {
listen 80;
server_name cloud.example.com;
# Path to the root of your installation
root /var/www/nextcloud;
# Prevent nginx HTTP Server Detection
server_tokens off;
# set max upload size and increase upload timeout:
client_max_body_size 512M;
client_body_timeout 300s;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
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/wasm 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;
# HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
index index.php index.html /index.php$request_uri;
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
location = / {
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Make a regex exception for `/.well-known` so that clients can still
# access it despite the existence of the regex rule
# `location ~ /(\.|autotest|...)` which would otherwise handle requests
# for `/.well-known`.
location ^~ /.well-known {
# The rules in this block are an adaptation of the rules
# in `.htaccess` that concern `/.well-known`.
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
# Let Nextcloud's API for `/.well-known` URIs handle all other
# requests by passing them to the front-end controller.
return 301 /index.php$request_uri;
}
# Rules borrowed from `.htaccess` to hide certain paths from clients
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
# Ensure this block, which passes PHP files to the PHP process, is above the blocks
# which handle static assets (as seen below). If this block is not declared first,
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
# to the URI, resulting in a HTTP 500 error response.
location ~ \.php(?:$|/) {
# Required for legacy support
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; $# Avoid sending the security headers twice
fastcgi_param front_controller_active true; $# Enable pretty urls
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_max_temp_file_size 0;
}
location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463, $asset_immutable";
access_log off; $# Optional: Don't log access to assets
location ~ \.wasm$ {
default_type application/wasm;
}
}
location ~ \.woff2?$ {
try_files $uri /index.php$request_uri;
expires 7d; $# Cache-Control policy borrowed from `.htaccess`
access_log off; $# Optional: Don't log access to assets
}
# Rule borrowed from `.htaccess`
location /remote {
return 301 /remote.php$request_uri;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
Save the file, then exit and restart nginx
# systemctl restart nginx
Step 6: Install MySQL server
Nextcloud supports multiple database engines, such as PostgreSQL, Oracle, SQLite, and MySQL/MariaDB. In this tutorial, we are going to use MySQL 8.0. Let’s install it first by invoking the command below.
# dnf install mysql mysql-server
# systemctl enable --now mysqld
The MySQL server is now up and running and will automatically run upon a reboot. You can check the status by running this command:
# systemctl status mysqld
The command will return an output like this:
[root@almalinux9 ~]$# systemctl status mysqld
● mysqld.service - MySQL 8.0 database server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; preset: disabled)
Active: active (running) since Wed 2024-06-19 03:26:55 CDT; 1min 41s ago
Process: 4912 ExecStartPre=/usr/libexec/mysql-check-socket (code=exited, status=0/SUCCESS)
Process: 4934 ExecStartPre=/usr/libexec/mysql-prepare-db-dir mysqld.service (code=exited, status=0/SUCCESS)
Main PID: 5009 (mysqld)
Status: "Server is operational"
Tasks: 37 (limit: 23191)
Memory: 459.9M
CPU: 9.713s
CGroup: /system.slice/mysqld.service
└─5009 /usr/libexec/mysqld --basedir=/usr
Jun 19 03:26:41 almalinux9.rosehosting.com systemd[1]: Starting MySQL 8.0 database server...
Jun 19 03:26:41 almalinux9.rosehosting.com mysql-prepare-db-dir[4934]: Initializing MySQL database
Jun 19 03:26:55 almalinux9.rosehosting.com systemd[1]: Started MySQL 8.0 database server.
Step 7: Create a Database
After installing the MySQL server in the previous step, we can now proceed with creating a new database and a user for our Nextcloud website.
# mysql
Once in the MySQL shell, run these commands.
mysql> CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
mysql> CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY "mod1fyth15";
mysql> GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> \q
Remember to replace ‘m0d1fyth15‘ with a stronger password.
Step 8: Install SSL Certificate
We will install an SSL certificate for our Nextcloud website using the free SSL certificate from Lets Encrypt.
# dnf install certbot python3-certbot-nginx -y
Once installed, you can run this command to issue an SSL certificate. Again, make sure to replace the subdomain with your actual domain or subdomain name; it should match the one in the nginx server block configuration file we created earlier. Also, make sure the domain or subdomain already points to your server’s IP address.
# certbot --nginx -d cloud.example.com
Make sure to answer the prompts, and you will see an output like this:
[root@rh ~]$# certbot --nginx -d cloud.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel): you@cloud.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: n
Account registered.
Requesting a certificate for cloud.example.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/cloud.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/cloud.example.com/privkey.pem
This certificate expires on 2024-09-17.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for cloud.example.com to /etc/nginx/conf.d/nexcloud.conf
Congratulations! You have successfully enabled HTTPS on https://cloud.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Now, let’s restart nginx
# systemctl restart nginx
Step 9: Install Nextcloud
Finally, we can proceed with installing Nextcloud. First, we need to download the installation archive file. Go to the Nextcloud download page and choose the specific version you require.
For this example, we will download the latest version available. Let’s run this command:
# wget https://download.nextcloud.com/server/releases/latest.zip -O latest.zip
Then, extract the downloaded zip archive to the document root directory on your server
# unzip latest.zip -d /var/www/
# mkdir /var/www/nextcloud/data
# chown -R nginx: /var/www/nextcloud
Once extracted, you can now proceed with Nextcloud installation via web installer at http://cloud.yourdomain.com, click on MySQL/MariaDB tab then fill the blank as required, then click on the “Install” button to finish it.
Once finished, you will be brought to the website backend’s login form.
In this tutorial, SELinux is considered disabled. If you encounter an issue most likely related to SELinux, you can check the Nextcloud documentation to fix it.
Congratulations! You have successfully learned how to install Nextcloud on AlmaLinux 9.
If you are a web hosting customer using our managed Nextcloud Hosting, you don’t have to follow this tutorial and install Nextcloud on AlmaLinux 9 yourself. Our Linux admins will set up and configure a Nextcloud VPS for you. They are available 24×7 and will take care of your request immediately, and all you need to do is submit a ticket. Installing Nextcloud is not just about the installation. We can help you optimize your Nextcloud installation if you have an active service with us.
If you liked this post, please share it with your friends or leave a comment below.