Sunday, August 25, 2019

Add HTTPS to FreeNAS Nextcloud plugin

Using Let's Encrypt and certbot with auto-renewal.

I installed the Nextcloud plugin some time ago in FreeNAS and found it useful, but it had no support for HTTPS at all. Initially I only used it internally so that was okay-ish, but wanted to roam, and even internally certain integrations just won't work at all without it (WebDAV, see my previous post). So I had a working install and didn't want to have to redo it all, I just wanted to add HTTPS. Of course, it is rare to find a straightforward, and complete answer on the Internet to a specific circumstance, even one that seems like it should be common.

If I wasn't time-poor, or was starting from scratch and was aware of this limitation I'd probably have used this automation script or this guide to hardening instead, or even better, a Docker container with configuration as code, but for that to work I'd have to get Docker working again...

My instructions are partly from https://www.ixsystems.com/community/threads/nextcloud-lets-encrypt-nginx.72643/ but I did NOT allow SSH direct to the nextcloud host, I go through the FreeNAS host using jexec. You could also use the shell in the UI but it's painful.

Prerequisites:
  • A domain name which you can point to your FreeNAS host, perhaps with a subdomain using a CNAME record. 
  • Control over port forwarding to FreeNAS - you'll need to enable port 80 for certbot to work (though I am unsure if it needs to be to the Nextcloud instance, actually) 
  • Basic command line knowledge including how to connect to the specific jail 

Brief steps:
  • Connect to your nextcloud host command line - if you don't know how to do that, this guide is too brief for you, sorry :) 
  • Allow installing packages: vi /usr/local/etc/pkg/repos/FreeBSD.conf and change no to yes. (Recommended to change it back later)
  • You may want to install a more preferable editor than vi at this point. 
  • Install certbot: pkg install py27-certbot
  • certbot certonly --webroot -w /usr/local/www/nextcloud -d your-domain-name.com
  • certbot renew --dry-run
  • crontab -e and add this to regularly check and renew if necessary: 
    • 0 0,12 * * * /usr/local/bin/python2.7 -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot renew --quiet
  • Now you have a certificate and all the automation to keep it up to date!
  • Next we add HTTPS listener and redirect from HTTP - this was missing from other instructions I saw. 
  • edit /usr/local/etc/nginx/conf.d/nextcloud.conf
  • There will just be a server entry for port 80. Break it up like this:
    • server {
    •   listen 80;
    •   server_name _;

    •   return 301 https://$host$request_uri;
    • }

    • server {
    •   listen 443 ssl;
    •   ssl on;
    •   ssl_certificate "/usr/local/etc/letsencrypt/live/your-domain-name/fullchain.pem";
    •   ssl_certificate_key "/usr/local/etc/letsencrypt/live/your-domain-name/privkey.pem";

    •   server_name _;

  • service nginx configtest
  • If the above is ok: service nginx reload
  • https://scan.nextcloud.com/ to check your security 
  • Turn off the package repos again to reduce attack surface. 
It's probably a good idea to upgrade Nextcloud while you're there:

$ pkg update
$ pkg upgrade nextcloud-php71
$ cd /usr/local/www/nextcloud
$ su -m www -c "php ./occ upgrade"


Friday, April 19, 2019

Restricted SMB Share writing files as specific user/group

I have a FreeNAS server and had a need to make SMB (Windows) shares which would write files as a particular user on the server, but be available to only certain unix users. 

Specifically, I installed Nextcloud and wanted to be able to access the files and upload in bulk instead of via the web interface, or the integrated Explorer client which is convenient but only works if you want to synchronise files locally (ie keep a copy) and are happy to move everything there. 

Nextcloud writes files as user/group www/www so I had to have the SMB share write files as that user, but be accessible to my user or group. I realise that isn't the best security or auditing model, and I might have achieved the same with a complex group config between FreeNAS and the jail, but it seemed unnecessary for my home server. 

I also created the group nextcloud_files to define the FreeNAS users that could access this share. 

In short, these advanced auxiliary SMB settings worked:
  • valid users = @nextcloud_files
  • force user = www
  • force group = www
I was able to mount the share as the Windows user and copy data into it, and it appeared as the www user. 

Additionally, I tried to set it so that the shares would only be visible to the users who could access them, with either or both of these options:

  • hide unreadable = yes
  • access based share enum = Yes
But that doesn't seem to work and probably requires user-level settings on FreeNAS which is not available in the web interface, and I don't like invisible manual configuration. 

Nextcloud note: it's not a good idea to side-load files into the storage, although they do appear in the web frontend, it hasn't attributed disk usage properly and I'm not sure if this means certain metadata won't be tracked. There just doesn't seem to be a nice way to pre-load it with GBs of photos.

To update the database, there is a server-side command to re-scan all the files, ie: 


root@nextcloud:/ # sudo -u www php /usr/local/www/nextcloud/occ files:scan joel
The process control (PCNTL) extensions are required in case you want to interrupt long running commands - see http://php.net/manual/en/book.pcntl.php
Starting scan for user 1 out of 1 (joel)
+---------+-------+--------------+
| Folders | Files | Elapsed time |
+---------+-------+--------------+
| 305     | 21041 | 00:21:53     |
+---------+-------+--------------+

This is not ideal. 

Turns out there is also a WebDAV address you can alternatively map instead of a windows share, which would solve this problem! 


... but Windows doesn't like it, no matter whether it's internal, external, port included or not. Of course. 

UPDATE: I solved this and described it in another post