Nextcloud is a Dropbox-like open source software that you can self host it on your server and use it to store, backup and synchronize your files and data across multiple devices. If you are looking to move away from Dropbox/Google Drive, and want to have complete control over your data, Nextcloud is the best choice.
The standard way of setting up Nextcloud is complicated, requires a lot of (server and software) configuration and it is prone to errors. Upgrading it is also an hassle. However, with the release of the official Nextcloud docker image, it is now very easy to install and use Nextcloud.
In this tutorial, I will show how to set up a Nextcloud Docker with Nginx reverse proxy. The server used in this tutorial is running Ubuntu 18.04.
Install Docker and docker-compose
If you have not install docker on your server, this is the first step to do so.
1. update the system:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> apt update
2. Install the package and dependencies for docker:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> apt-transport-https ca-certificates curl gnupg-agent software-properties-common
3. Add the docker’s gpg key
curl <span style="color: #660033;">-fsSL</span> https:<span style="color: #000000; font-weight: bold;">//</span>download.docker.com<span style="color: #000000; font-weight: bold;">/</span>linux<span style="color: #000000; font-weight: bold;">/</span>ubuntu<span style="color: #000000; font-weight: bold;">/</span>gpg <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-key add</span> -
4. Add the docker’s repository.
<span style="color: #c20cb9; font-weight: bold;">sudo</span> add-apt-repository <span style="color: #ff0000;">"deb [arch=amd64] https://download.docker.com/linux/ubuntu <span style="color: #007800;">$(lsb_release -cs)</span> stable"</span>
5. Lastly, update the system and install docker:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> apt update<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> docker-ce docker-ce-cli containerd.io
6. If you want to run docker as user (instead of root), add your username to the docker
group:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> groupadd <span style="color: #c20cb9; font-weight: bold;">docker</span><br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> usermod <span style="color: #660033;">-aG</span> <span style="color: #c20cb9; font-weight: bold;">docker</span> username
7. Next, we are going to install docker-compose (the latest version is 1.24.0 as of this post).
<span style="color: #c20cb9; font-weight: bold;">sudo</span> curl <span style="color: #660033;">-L</span> <span style="color: #ff0000;">"https://github.com/docker/compose/releases/download/1.24.0/docker-compose-<span style="color: #007800;">$(uname -s)</span>-<span style="color: #007800;">$(uname -m)</span>"</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>docker-compose<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chmod</span> +x <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>docker-compose
8. Restart the server.
Set up Nextcloud
We are going to make use of docker-compose to run Nextcloud docker image. To get started, first create a “nextcloud” folder, and cd
to it.
<span style="color: #c20cb9; font-weight: bold;">mkdir</span> nextcloud<br /><span style="color: #7a0874; font-weight: bold;">cd</span> nextcloud
1. Create a docker-compose file:
<span style="color: #c20cb9; font-weight: bold;">nano</span> docker-compose.yml
2. Paste the following code to the file:
<span style="color: green;">version</span><span style="font-weight: bold; color: brown;">: </span>'3'<br /><span style="color: #007F45;"><br />services</span>:<span style="color: #007F45;"><br /> db</span>:<span style="color: green;"><br /> image</span><span style="font-weight: bold; color: brown;">: </span>mariadb<span style="color: green;"><br /> command</span><span style="font-weight: bold; color: brown;">: </span>--transaction-isolation=READ-COMMITTED --binlog-format=ROW<span style="color: green;"><br /> restart</span><span style="font-weight: bold; color: brown;">: </span>always<span style="color: #007F45;"><br /> volumes</span><span style="font-weight: bold; color: brown;">:<br /></span> - db:/var/lib/mysql<span style="color: #007F45;"><br /> env_file</span><span style="font-weight: bold; color: brown;">:<br /></span> - db.env<br /><span style="color: #007F45;"><br /> redis</span>:<span style="color: green;"><br /> image</span><span style="font-weight: bold; color: brown;">: </span>redis<span style="color: green;"><br /> restart</span><span style="font-weight: bold; color: brown;">: </span>always<br /><span style="color: #007F45;"><br /> app</span>:<span style="color: green;"><br /> build</span><span style="font-weight: bold; color: brown;">: </span>./app<span style="color: green;"><br /> restart</span><span style="font-weight: bold; color: brown;">: </span>always<span style="color: #007F45;"><br /> ports</span><span style="font-weight: bold; color: brown;">:<br /></span> - 5234:80<span style="color: #007F45;"><br /> volumes</span><span style="font-weight: bold; color: brown;">:<br /></span> - nextcloud:/var/www/html<span style="color: #007F45;"><br /> environment</span><span style="font-weight: bold; color: brown;">:<br /></span> - MYSQL_HOST=db<span style="color: #007F45;"><br /> env_file</span><span style="font-weight: bold; color: brown;">:<br /></span> - db.env<span style="color: #007F45;"><br /> depends_on</span><span style="font-weight: bold; color: brown;">:<br /></span> - db<br /> - redis<br /><span style="color: #007F45;"><br /> cron</span>:<span style="color: green;"><br /> build</span><span style="font-weight: bold; color: brown;">: </span>./app<span style="color: green;"><br /> restart</span><span style="font-weight: bold; color: brown;">: </span>always<span style="color: #007F45;"><br /> volumes</span><span style="font-weight: bold; color: brown;">:<br /></span> - nextcloud:/var/www/html<span style="color: green;"><br /> entrypoint</span><span style="font-weight: bold; color: brown;">: </span>/cron.sh<span style="color: #007F45;"><br /> depends_on</span><span style="font-weight: bold; color: brown;">:<br /></span> - db<br /> - redis<br /><span style="color: #007F45;"><br />volumes</span>:<span style="color: #007F45;"><br /> db</span><span style="font-weight: bold; color: brown;">:<br /></span> nextcloud:
We will map the server port 5234 to the docker image port 80. Save (Ctrl + O) and exit (Ctrl + X) the file.
3. The docker-compose file will get the database credential from the “db.env” file, so we need to create the file and add our database details.
<span style="color: #c20cb9; font-weight: bold;">nano</span> db.env
Add your database details in.
<span style="color: #007800;">MYSQL_ROOT_PASSWORD</span>=mysupersecurerootpassword<br /><span style="color: #007800;">MYSQL_PASSWORD</span>=mysupersecureuserpassword<br /><span style="color: #007800;">MYSQL_DATABASE</span>=nextcloud<br /><span style="color: #007800;">MYSQL_USER</span>=nextcloud
You can change the root and user password. Save (Ctrl + O) and exit (Ctrl + X) the file.
4. Next, create the app directory and add the actual Dockerfile.
<span style="color: #c20cb9; font-weight: bold;">mkdir</span> app<br /><span style="color: #7a0874; font-weight: bold;">cd</span> app<br /><span style="color: #c20cb9; font-weight: bold;">nano</span> Dockerfile
Add the following lines to the Dockerfile:
FROM nextcloud:apache<br /> <br />COPY redis.config.php <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>nextcloud<span style="color: #000000; font-weight: bold;">/</span>config<span style="color: #000000; font-weight: bold;">/</span>redis.config.php
Save (Ctrl + O) and exit (Ctrl + X) the file.
5. In the “app” folder, create the “redis.config.php” file.
<span style="color: #c20cb9; font-weight: bold;">nano</span> redis.config.php
Paste the following configuration to the php file.
<span style="color: #000000; font-weight: bold;"><?php</span><br /><span style="color: #000088;">$CONFIG</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #009900;">(</span><br /> <span style="color: #0000ff;">'memcache.local'</span> <span style="color: #339933;">=></span> <span style="color: #0000ff;">'\\OC\\Memcache\\Redis'</span><span style="color: #339933;">,</span><br /> <span style="color: #0000ff;">'memcache.locking'</span> <span style="color: #339933;">=></span> <span style="color: #0000ff;">'\\OC\\Memcache\\Redis'</span><span style="color: #339933;">,</span><br /> <span style="color: #0000ff;">'filelocking.enabled'</span> <span style="color: #339933;">=></span> <span style="color: #0000ff;">'true'</span><span style="color: #339933;">,</span><br /> <span style="color: #0000ff;">'redis'</span> <span style="color: #339933;">=></span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">(</span><br /> <span style="color: #0000ff;">'host'</span> <span style="color: #339933;">=></span> <span style="color: #0000ff;">'redis'</span><span style="color: #339933;">,</span><br /> <span style="color: #0000ff;">'port'</span> <span style="color: #339933;">=></span> <span style="color: #cc66cc;">6379</span><span style="color: #339933;">,</span><br /> <span style="color: #009900;">)</span><span style="color: #339933;">,</span><br /><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
6. Lastly, run the docker image:
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>username<span style="color: #000000; font-weight: bold;">/</span>nextcloud<br />docker-compose up <span style="color: #660033;">-d</span>
Set up Let’s Encrypt SSL Certificate
We will use certbot to obtain and manage Let’s Encrypt certificate. To get started, first install certbot.
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get update</span><br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> software-properties-common<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> add-apt-repository universe<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> add-apt-repository ppa:certbot<span style="color: #000000; font-weight: bold;">/</span>certbot<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get update</span><br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> certbot python-certbot-nginx
Next, create a Nginx conf file for the nextcloud domain:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">nano</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>sites-available<span style="color: #000000; font-weight: bold;">/</span>nextcloud
Add the following lines:
<a href="http://wiki.nginx.org/NginxHttpCoreModule#server"><span style="color: #000066;">server</span></a> <span style="color: #66cc66;">{</span><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#listen"><span style="color: #000066;">listen</span></a> 80<span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#listen"><span style="color: #000066;">listen</span></a> <span style="color: #66cc66;">[</span>::<span style="color: #66cc66;">]</span>:80 ipv6only<span style="color: #66cc66;">=</span>on<span style="color: #66cc66;">;</span><br /><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#server_name"><span style="color: #000066;">server_name</span></a> mynextcloudurl.com<span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#root"><span style="color: #000066;">root</span></a> /var/www/mynextcloudurl.com<span style="color: #66cc66;">;</span><br /><br /> <a href="http://wiki.nginx.org/NginxHttpIndexModule#index"><span style="">index</span></a> <a href="http://wiki.nginx.org/NginxHttpIndexModule#index"><span style="">index</span></a>.html<span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#location"><span style="color: #000066;">location</span></a> / <span style="color: #66cc66;">{</span><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#try_files"><span style="color: #000066;">try_files</span></a> <span style="color: #000066;">$uri</span> <span style="color: #000066;">$uri</span>/ <span style="color: #66cc66;">=</span>404<span style="color: #66cc66;">;</span><br /> <span style="color: #66cc66;">}</span><br /><span style="color: #66cc66;">}</span>
Save and exit the file. Make it active:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">ln</span> <span style="color: #660033;">-s</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>sites-available<span style="color: #000000; font-weight: bold;">/</span>nextcloud <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>sites-enabled<span style="color: #000000; font-weight: bold;">/</span><br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> systemctl reload nginx
Lastly, obtain a certificate with the command:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> certbot <span style="color: #660033;">--rsa-key-size</span> <span style="color: #000000;">4096</span> <span style="color: #660033;">--nginx</span>
When prompted, select your nextcloud url and fill up the information. Allow it to replace the conf file.
Setting up Nginx Reverse Proxy
In the Nginx conf file, add (or replace the location /
block) the following lines:
<a href="http://wiki.nginx.org/NginxHttpCoreModule#location"><span style="color: #000066;">location</span></a> / <span style="color: #66cc66;">{</span><br /> <a href="http://wiki.nginx.org/NginxHttpProxyModule#proxy_pass"><span style="">proxy_pass</span></a> <a href="http://wiki.nginx.org/NginxHttpCoreModule#http"><span style="color: #000066;">http</span></a>://localhost:5234/<span style="color: #66cc66;">;</span> <span style="color: #808080; font-style: italic;"># set this to the nextcloud port set in doccker-compose file</span><br /> <a href="http://wiki.nginx.org/NginxHttpProxyModule#proxy_set_header"><span style="">proxy_set_header</span></a> Host <span style="color: #000066;">$host</span><span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpProxyModule#proxy_set_header"><span style="">proxy_set_header</span></a> X-Real-IP <span style="color: #000066;">$remote_addr</span><span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpProxyModule#proxy_set_header"><span style="">proxy_set_header</span></a> X-Forwarded-For <span style="color: #000066;">$proxy_add_x_forwarded_for</span><span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpProxyModule#proxy_set_header"><span style="">proxy_set_header</span></a> X-Forwarded-Proto <span style="color: #000066;">$scheme</span><span style="color: #66cc66;">;</span><br /><br /> <a href="http://wiki.nginx.org/NginxHttpCoreModule#client_max_body_size"><span style="color: #000066;">client_max_body_size</span></a> 0<span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/NginxHttpHeadersModule#add_header"><span style="">add_header</span></a> Strict-Transport-Security <span style="color: #ff0000;">"max-age=31536000; includeSubDomains; preload"</span><span style="color: #66cc66;">;</span><br /> <br /> <a href="http://wiki.nginx.org/NginxHttpLogModule#access_log"><span style="">access_log</span></a> /var/log/nginx/nextcloud.access.log<span style="color: #66cc66;">;</span><br /> <a href="http://wiki.nginx.org/CoreModule#error_log"><span style="color: #b1b100;">error_log</span></a> /var/log/nginx/nextcloud.error.log<span style="color: #66cc66;">;</span><br /><span style="color: #66cc66;">}</span><br /><br /><a href="http://wiki.nginx.org/NginxHttpCoreModule#location"><span style="color: #000066;">location</span></a> <span style="color: #66cc66;">=</span> /.well-known/carddav <span style="color: #66cc66;">{</span><br /> <a href="http://wiki.nginx.org/NginxHttpRewriteModule#return"><span style="">return</span></a> 301 <span style="color: #000066;">$scheme</span>://<span style="color: #000066;">$host</span>/remote.php/dav<span style="color: #66cc66;">;</span><br /><span style="color: #66cc66;">}</span><br /><br /><a href="http://wiki.nginx.org/NginxHttpCoreModule#location"><span style="color: #000066;">location</span></a> <span style="color: #66cc66;">=</span> /.well-known/caldav <span style="color: #66cc66;">{</span><br /> <a href="http://wiki.nginx.org/NginxHttpRewriteModule#return"><span style="">return</span></a> 301 <span style="color: #000066;">$scheme</span>://<span style="color: #000066;">$host</span>/remote.php/dav<span style="color: #66cc66;">;</span><br /><span style="color: #66cc66;">}</span>
Save and exit the file. Restart Nginx:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> systemctl reload nginx
On your browser, load your nextcloud url and it should prompt you to set up your administrator account.
Securing the server (optional)
We can use fail2ban
to prevent unauthorized access to the server. For the following configuration, we will block IPs that made three unsuccessful login attempts to our Nextcloud installation.
1. Start by creating the fail2ban conf file:
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">nano</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>fail2ban<span style="color: #000000; font-weight: bold;">/</span>filter.d<span style="color: #000000; font-weight: bold;">/</span>nextcloud.conf
Add the following codes to filter out the Login failed
messages in the nextcloud logfiles:
<span style="color: #7a0874; font-weight: bold;">[</span>Definition<span style="color: #7a0874; font-weight: bold;">]</span><br />failregex = ^<span style="color: #7a0874; font-weight: bold;">{</span><span style="color: #ff0000;">"reqId"</span>:<span style="color: #ff0000;">".*"</span>,<span style="color: #ff0000;">"remoteAddr"</span>:<span style="color: #ff0000;">".*"</span>,<span style="color: #ff0000;">"app"</span>:<span style="color: #ff0000;">"core"</span>,<span style="color: #ff0000;">"message"</span>:<span style="color: #ff0000;">"Login failed: '.*' \(Remote IP: '<HOST>'\)"</span>,<span style="color: #ff0000;">"level"</span>:<span style="color: #000000;">2</span>,<span style="color: #ff0000;">"time"</span>:<span style="color: #ff0000;">".*"</span><span style="color: #7a0874; font-weight: bold;">}</span>$<br /> ^<span style="color: #7a0874; font-weight: bold;">{</span><span style="color: #ff0000;">"reqId"</span>:<span style="color: #ff0000;">".*"</span>,<span style="color: #ff0000;">"level"</span>:<span style="color: #000000;">2</span>,<span style="color: #ff0000;">"time"</span>:<span style="color: #ff0000;">".*"</span>,<span style="color: #ff0000;">"remoteAddr"</span>:<span style="color: #ff0000;">".*"</span>,<span style="color: #ff0000;">"app"</span>:<span style="color: #ff0000;">"core"</span>.<span style="color: #000000; font-weight: bold;">*</span><span style="color: #ff0000;">","</span>message<span style="color: #ff0000;">":"</span>Login failed: <span style="color: #ff0000;">'.*'</span> \<span style="color: #7a0874; font-weight: bold;">(</span>Remote IP: <span style="color: #ff0000;">'<HOST>'</span>\<span style="color: #7a0874; font-weight: bold;">)</span><span style="color: #ff0000;">".*}$<br />ignoreregex =</span>
2. Next, create the actual jail configuration for nextcloud.
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">nano</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>fail2ban<span style="color: #000000; font-weight: bold;">/</span>jail.d<span style="color: #000000; font-weight: bold;">/</span>nextcloud.conf
Add the following lines to the file. You can change the maxretry
and bantime
values according to your needs.
<span style="color: #7a0874; font-weight: bold;">[</span>nextcloud<span style="color: #7a0874; font-weight: bold;">]</span><br />enabled = <span style="color: #c20cb9; font-weight: bold;">true</span><br />port = <span style="color: #000000;">80</span>,<span style="color: #000000;">443</span><br />protocol = tcp<br />filter = nextcloud<br />maxretry = <span style="color: #000000;">3</span><br />bantime = <span style="color: #000000;">10800</span><br />logpath = <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>docker<span style="color: #000000; font-weight: bold;">/</span>volumes<span style="color: #000000; font-weight: bold;">/</span>nextcloud_nextcloud<span style="color: #000000; font-weight: bold;">/</span>_data<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>nextcloud.log
3. Restart the fail2ban service.
<span style="color: #c20cb9; font-weight: bold;">sudo</span> systemctl restart fail2ban
You can check the fail2ban status with the following commands.
<span style="color: #c20cb9; font-weight: bold;">sudo</span> fail2ban-client status<br /><span style="color: #c20cb9; font-weight: bold;">sudo</span> fail2ban-client status nextcloud
Updating Nextcloud
To update Nextcloud to the newer version, you just need to pull the new images via docker-compose and rebuild the containers.
docker-compose stop<br />docker-compose <span style="color: #c20cb9; font-weight: bold;">rm</span><br />docker-compose pull<br />docker-compose build <span style="color: #660033;">--pull</span><br />docker-compose up <span style="color: #660033;">-d</span>
That’s it.