Private cloud on Windows Desktop
Introduction
Many users have a desktop computer (or a laptop) running most of the day. Each person at home has a smartphone with a lot of contacts, SMS, photos and other important files.
Unfortunately, everything is not connected: why should I transfer all my contacts or photos to a cloud server in order to copy it to my computer, 50 cm away? (Answer: because data is money and so you get a easy-to-use for free).
Target of this article is to run some services in a “human understandable way” without leaving home. Services means sharing information (i.e. contacts, calendar) between users and devices of the home.
Home network is protected from the outside through the Internet Box rented by the internet provider. In the local network, there is no need to encrypt the data, making it easier to configure the solution. Data may be encrypted on the mobile devices as those are leaving the home network. This part is not covered by the article, but is explained here.
Requirements
Technically, the solution shall fullfill the following points:
- Multi user solution.
- A server must run in the background on a Windows 10 desktop machine.
- Several users must be able to continue to work as usually on the desktop machine.
- Data shall not leave from home (excepts on mobile phones).
- Installation shall be moderatly difficult and easy to follow.
(- Instalation shall be updated easily – Not tested at the moment) - It must be possible to easily uninstall all software.
- Mobile clients must exist.
- Following services must be proposed:
- Contacts
- SMS
- Calendar
- Photos
- Notes
- Tasks
- Synchronize data
Restrictions: the server is not architected for running all the time and for many users. It may be accessible in the local network but not from outside, this to maximize the security of the solution and to reduce its complexity.
Answer: Nextcloud on Docker
Nextcloud is a proven platform providing the required services (and more). It is based on a PHP framework and requires a database. German federal IT has chosen it.
The use of docker containers is allowing to limit at the maximum the required footprint of the additional services.
Docker allows to run software in an isolated and minimal environment, named Container. Each container target a single task (Web server, database).
Caution: the following is just a technical documentation. Author does not take responsability on any data loss caused by following those instructions. Mentioned trademarks are ownership of their author. No free support will be offered.
A focus is done on Free and Open-Source software. Consider participating to the common efforts, with your skills, time or money.
Technical overview of the implementation
Prerequisites The machine shall have at least 8GB RAM, CPU or graphics performances are not limiting in this case. An account with administrative rights is required on the host computer.
A Windows professional license is preferred but Home edition shall be sufficient. In Windows Explorer, open the properties of the node This PC to see the version of Windows in use.
A cooking receipt script, docker-compose.yml will be used for this solution. Such a file contains a description of the docker commands to download and run the different docker containers. Required files will be downloaded if not present.
Windows Firewall must be stopped for the services to be available in the local network. This shall be OK as long as the local network is behind a box providing NAT (Network Adress Translation) functionalities.
Tools
Here a list of the tools used to run the proposed solution. Those are well-known, mature and maintained.
Docker for Windows or Docker Toolbox
Docker Desktop is the state-of-the-art solution for running containers. It requires Windows 10 professional due to the use of the hypervisor Hyper-V feature.
Alternative is Docker Toolbox, a legacy technology, but supporting Windows 10 Home.
This software contains all the tools required to create, manage and execute docker containers. The setup will configure the required Windows features, like Hyper-V.
The documentation contains the required instruction to check the installation and the basic commands.
Nextcloud
The Nextcloud docker appliance will be preferred to any community-driven package. This provides most of the functionalities required for the proposed solution.
PostgreSQL
Most of the implementation will make use of MariaDB, but I, personally recommend the use of PostgreSQL.
As a fork of Oracle MySQL, MariaDB may be encumbered by some limitations in the future (Hint: MySQL lecture of the GPL license is ‘different’), due to some license infrigement, forcing many users to upgrade or to switch to an alternative.
Alpine Linux, Nginx, PHP-FPM
The following tools are running behind the scene:
- Alpine Linux: Operating system reduced at its minimum.
- Nginx: Light-weight web server
- PHP-FM is an alternative implementation of an internal process. Using this or another is just a matter of choice.
Files required
Docker-compose.yml file
Save the following code to a file docker-compose.yml to any directory on your computer
version: '3'
services:
db:
image: postgres:alpine
restart: always
volumes:
- db:/var/lib/postgresql/data
env_file:
- db.env
app:
image: nextcloud:fpm-alpine
restart: always
volumes:
- nextcloud-html:/var/www/html
environment:
- POSTGRES_HOST=db
env_file:
- db.env
depends_on:
- db
web:
build: ./web
restart: always
ports:
- 80:80
volumes:
- nextcloud-html:/var/www/html:ro
- nextcloud-data:/var/www/html/data:rw
depends_on:
- app
volumes:
db:
nextcloud-html:
nextcloud-data:
db.env
Copy the following content in a file db.env located in the same directory than docker-compose.yml.
POSTGRES_PASSWORD=MyPassword
POSTGRES_DB=nextcloud
POSTGRES_USER=nextcloud
NEXTCLOUD_TRUSTED_DOMAINS=IP-OF-WINDOWS-HOST
Note: Best practice is to use long and complex passwords.
web\nginx.conf
Create a directory web in the directory where are located docker-compose.yml and db.env.
The configuration of the web server nginx is kept outside and will be injected at run-time.
Copy the following content in a file nginx.conf.
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
upstream php-handler {
server app:9000;
}
server {
listen 80;
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
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;
# Path to the root of your installation
root /var/www/html;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
# The following rule is only needed for the Social app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
# set max upload size
client_max_body_size 10G;
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/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;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
location / {
rewrite ^ /index.php;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
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;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
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;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}
}
web\Dockerfile
Copy the following content in a file Dockerfile bin the subdirectory web.
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
This file will perform some initial configuration in the docker container running the web server nginx: copy the nginx configuration file.
Executer script: runme.bat
Copy the following code to a file runme.bat to your local drive. Replace C:\Documents\NextCloud-Docker with the directory where docker-compose.yml is located.
@echo off
cd /d C:\Documents\NextCloud-Docker
docker-compose up -d
pause
This script will start the docker container in the background.
Clients
NextCloud supports the standard protocols CalDAV, CardDAV, allowing connecting it to many other software.
On Windows
- Nextcloud client allows each user to synchronize many types of data with the Nextcloud server.
- Thunderbird Lightning calendar integration allows a form of Groupware
- QOwnNotes is a note taking tool that can synchronize with a Nextcloud server. It can extend your browser, execute some scripts.
On Android
- F-Droid is a third-party catalog of Free and Open-source applications. From there several tools can be used to synchronize different services.
- This article explains how to synchronize tasks, calendars and contacts.
Backup
This point is the reason behind this article. I did not found any easy how-to to follow, and due to Docker containers are running Linux, itsself running on Hyper-V, managed by Windows… I wonder how it’s work and has to test carefully this solution.
As dockers commands can be executed directly on the containers, and due to the use of persistent docker volumes, it shall work, but need to be more test.
Nextcloud is based on files stored on the web server and data stored in the dabase. So we need to copy the files from the web server and execute a backup of the database (why a tool is required to save the content of the database is beyond the scope of the article).
docker cp docker-compose_web_1:/var/www/html/data/user/files C:\Documents\NextCloudApps
docker exec docker-compose_db_1 pg_dump -c -U nextcloud nextcloud > C:\LS\Docker\PGBackup.sql
Some links:
- https://github.com/ReinerNippes/nextcloud_on_docker/blob/master/roles/prep_backup/templates/backup_nextcloud.sh.j2
- https://docs.docker.com/storage/volumes/#backup-restore-or-migrate-data-volumes
- https://www.postgresql.org/docs/9.0/app-pgdump.html
- https://github.com/istepanov/docker-pg_dump
Upgrades
According to the Nextcloud documentation, an upgrade is performed by pulling the latest image. Due to the usage of containers, no data is lost.
Download (pull) the data and restart the system in the background (-d: daemon)
docker-compose pull
docker-compose up -d
Alternatives
Cozy
https://cozy.io/en/ – Howto: https://opensource.com/article/17/2/cozy-personal-cloud
If docker is installed, cozy can be installed with a couple of lines (to be adjusted for running on windows):
docker build -t cozy/full github.com/cozy-labs/cozy-docker
docker run --restart=always -d -p 80:80 -p 443:443 --name=moncozy --volume=/home/cozy/backup:/media -e DOMAIN=my.domain.com -e TERM=xterm/backup cozy/full
More information on https://github.com/cozy/cozy-setup/wiki/2.4.-The-Docker-Way