Install Nginx as a WebDav File Server on CentOS 7

I've grown tired of trying to use OwnCloud to automatically backup photos and videos from both my Android phone, and my wife's iPhone. It always seems that something breaks within a month or two of it being setup, and I also don't like that OwnCloud holds those files in a separate location.

Ultimately, I wanted a file sync solution that I could sync my photos and videos from various phones/devices, directly to my user's home directory (which is a NFS share on my ZFS server). As an example, here is what the directory looks like for my user directory:
/tanks/tank_data_01/users/dhorn/photos/phone/

Within that directory, I have a folder for each phone I've had in the last 5-6 years. I.E., nexus_6p, htc_one, galaxy_s2, etc. My entire user directory is mounted on all my devices via NFS, so I want an automated solution that allows me to sync photos/videos from my phone, and be able to view them with Finder from by MBP (for example), and not have to pull them from OwnCloud. To accomplish this, I decided to use WebDav via Nginx, and mount my user directory on this server and give the Nginx permissions to write to this ./dhorn/photos/phone directory, and use a separate server stanza in my Nginx config for my wifes phone, in her user directory.

So...this post is for installing Nginx from source with the WebDav modules, and configuring a basic WebDav server via HTTP (I'm proxying this WebDav instance through my dedicated Nginx Reverse Proxy instance for SSL over WAN).

As usual, this guide is specific for CentOS 7. In my setup I have SELinux disabled (sed -i /etc/selinux/config -r -e 's/^SELINUX=.*/SELINUX=disabled/g'). If you disable selinux (or firewalld), you do so at your own risk. It is not advisable to do either if your server is directly accessible on the internet (this one should not be), so please do so at your own risk! At the bottom of this post I've included the simple rules needed for firewalld (on a CentOS 7.2 minimal install, you will need to install firewalld as firewalld is no longer included in the CentOS 7 default minimal install).

Let's Get Started!

1.) updates and pre-requisites:
yum -y install epel-release expat-devel httpd-tools unzip wget
yum -y groupinstall "Development tools"
yum -y update && systemctl reboot
2.) nginx from source:
# nginx user
useradd -r nginx
usermod -s /sbin/nologin nginx

# install pcre 8.39
cd /tmp
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.39.tar.gz
tar -zxf pcre-8.39.tar.gz
cd pcre-8.39
./configure
make && make install

# install zlib 1.2.8
cd /tmp
wget http://zlib.net/zlib-1.2.8.tar.gz
tar -zxf zlib-1.2.8.tar.gz
cd zlib-1.2.8
./configure
make && make install

# install openssl 1.0.2h
cd /tmp
wget http://www.openssl.org/source/openssl-1.0.2h.tar.gz
tar -zxf openssl-1.0.2h.tar.gz
cd openssl-1.0.2h
./config --prefix=/usr
make && make install

# nginx dav ext module
cd /tmp
wget -c https://github.com/arut/nginx-dav-ext-module/archive/v0.0.2.zip -O nginx-dav-ext-module-v0.0.2.zip
unzip nginx-dav-ext-module-v0.0.2.zip

# install nginx 1.11.1
cd /tmp
wget http://nginx.org/download/nginx-1.11.1.tar.gz
tar -zxf nginx-1.11.1.tar.gz
cd nginx-1.11.1
./configure --user=nginx --group=nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module --with-stream --with-pcre=../pcre-8.39 --with-zlib=../zlib-1.2.8 --without-http_empty_gif_module --with-http_dav_module --add-module=../nginx-dav-ext-module-0.0.2
make && make install
3.) configure nginx:
mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
mkdir -p /etc/nginx/conf.d
vi /etc/nginx/nginx.conf
---
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    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;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
}
---

vi /etc/nginx/conf.d/webdav.conf
---
server {
  listen  80;
  server_name  localhost;
  root /mnt/webdav/files;
  client_body_temp_path   /mnt/webdav/temp;

  location / {
    dav_methods  PUT DELETE MKCOL COPY MOVE;
    dav_ext_methods  PROPFIND OPTIONS;
    create_full_put_path  on;
    dav_access  user:rw group:rw all:rw;
    autoindex  on;
    client_max_body_size  1G;   # File size limit for new files

    auth_basic  "closed site";
    auth_basic_user_file /mnt/webdav/.htpasswd;
  }
}
---

vi /usr/lib/systemd/system/nginx.service
---
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
KillSignal=SIGQUIT
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
---
4.) create htpasswd user(s):
htpasswd -c /mnt/webdav/.htpasswd 'user'   # input new password when prompted
5.) cleanup:
rm -rf /tmp/pcre-8.39* /tmp/zlib-1.2.8* /tmp/openssl-1.0.2h* /tmp/nginx-dav-ext* /tmp/nginx-1.11.1*
systemctl enable nginx.service
systemctl start firewalld.service
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
reboot

At this point, Nginx is installed and a basic WebDav server is configured. If you browse to your new WebDav instance in a web browser, you should be able to see a directory listing of any existing files in that directory, but you will not be able to upload any new files via a web browser. You will have to use a WebDav client (mobile app, Windws/Mac/Linux app, etc) which is the ideal way to manage these files.

Lastly, I want to add further clarification on my specific setup using existing directories (mounted as NFS shares). Here is what my /etc/nginx/conf.d/webdav.conf file looks like:

server {
  listen  80;
  server_name  localhost;
  root /mnt/users;
  client_body_temp_path  /mnt/webdav/temp;

  location /user1/ {
    dav_methods  PUT DELETE MKCOL COPY MOVE;
    dav_ext_methods  PROPFIND OPTIONS;
    create_full_put_path  on;
    dav_access  user:rw group:rw all:rw;
    autoindex  on;
    client_max_body_size  10G;

    auth_basic  "closed site";
    auth_basic_user_file /mnt/webdav/.user1_htpasswd;
  }

  location /user2/ {
    dav_methods  PUT DELETE MKCOL COPY MOVE;
    dav_ext_methods  PROPFIND OPTIONS;
    create_full_put_path  on;
    dav_access  user:rw group:rw all:rw;
    autoindex  on;
    client_max_body_size  10G;

    auth_basic  "closed site";
    auth_basic_user_file /mnt/webdav/.user2_htpasswd;
  }
}

I have my user directories mounted via NFS on this WebDav server, mounted to /mnt/users. That root dir (which contains folders named for each user) is not browsable from this WebDav server, as designed. For each user, I have to create a new location and .htpasswd file specific for that user. For permissions, I have UID's and GID's mapped the same across my storage box and by WebDav box, and each user directory is owned by that users user and group. For example, /tanks/tank_data_01/users/dhorn is owned by dhorn:dhorn. User nginx is a member of the dhorn group. Thus, Webdav has read-write permissions to that directory.

With my current setup, I am able to use mobile apps (such as Synchronize Ultime on Android and PhotoSync on iOS) to auto-sync new photos and videos right to my user directory. Since I proxy this WebDav instance through my SSL-terminating Reverse Proxy instance, I can access/upload files from anywhere as long as my phone has an internet connection (and with using these apps, I can set rules to not upload unless on WiFi and/or plugged in, set schedules or location rules, etc). I finally have the solution I want, with the control that I want! I may also experiment with using WebDav as my mount of choice to my clients, instead of NFS (which will all depend on performance).

Give it a try, and let me know what you think!


Related Posts


Share on: Twitter | Facebook | Google+ | Email


comments powered by Disqus