├── .profile ├── .travis.yml ├── LICENSE ├── README.md ├── bootstrap.sh ├── ssh-vvvv ├── start-stop-status └── wget2 /.profile: -------------------------------------------------------------------------------- 1 | umask 022 2 | 3 | PATH=/opt/bin:/opt/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin:/usr/local/sbin:/usr/local/bin 4 | export PATH 5 | 6 | #This fixes the backspace when telnetting in. 7 | #if [ "$TERM" != "linux" ]; then 8 | # stty erase 9 | #fi 10 | 11 | HOME=/root 12 | export HOME 13 | 14 | TERM=${TERM:-cons25} 15 | export TERM 16 | 17 | PAGER=more 18 | export PAGER 19 | 20 | PS1="`hostname`> " 21 | 22 | # --------------------------------------------------------------------------- 23 | 24 | export GIT_SSH='/usr/bin/ssh' 25 | export SYNOREL=https://github.com/wkoszek/synology/archive/ 26 | 27 | alias dir="ls -al" 28 | alias ll="ls -la" 29 | alias la="ls -la" 30 | 31 | alias debian="/var/packages/debian-chroot/scripts/start-stop-status chroot" 32 | alias screen="env TERM=xterm screen" 33 | alias wget="/root/synology/wget2" 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '2.7' 4 | script: 5 | - ./wget2 http://testdata.koszek.com/data/10.txt 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Wojciech A. Koszek 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Making Synology NAS command line usable 2 | **My Synology automation scripts** 3 | 4 | [![Build Status](https://travis-ci.org/wkoszek/synology.svg?branch=master)](https://travis-ci.org/wkoszek/synology) 5 | 6 | **This project should be converted to Ansible. Any volunteers?** 7 | 8 | I have a Synology DS214play NAS box and its command line is pretty limited. Most of the 9 | commands are trimmed down copies of their UNIX counterparts. I like my NAS 10 | being NAS, but I also wanted to be able to do useful things with it, assuming 11 | it's powered 24/7. To make its command line usable for myself 12 | in a long-term, I decided to spend some time on proper configuration. 13 | Unfortunately my NAS model isn't permitted to use Synology's Docker package, so the whole 14 | activity included: 15 | 16 | - `ipkg` installation: this will give you basic commands such as `vim` or 17 | `bash` 18 | 19 | - Debian chroot: this will let you run a Debian userland, which gives you 20 | `apt-get` and the possibility of running all sorts of stuff on your 21 | Synology box. I found it useful when experimenting with command-line 22 | backup solutions such as `zbackup`, which don't exist in `ipkg` 23 | repository. 24 | 25 | I stole some ideas from: 26 | 27 | http://www.hang321.net/en/2015/06/09/debian-chroot-on-dsm-5-2/ 28 | 29 | # How to use 30 | 31 | 1. Enable SSH on your Synology http://forum.synology.com/wiki/index.php/Enabling_the_Command_Line_Interface 32 | 2. Go to [https://synocommunity.com/](https://synocommunity.com/) and add the Community Packages to Synology software sources. 33 | 3. From the community packages tab, install Python. 34 | 4. From the community packages tab, install Debian chroot. 35 | 5. Upon installing, start Debian chroot. 36 | 37 | SSH to your NAS: 38 | 39 | ssh root@nas_ip 40 | 41 | Get the simple Python script which imitates `wget`, but unlike Synology's 42 | `wget(1)` has HTTPS support (http://www.koszek.com/blog/2015/10/04/wget-in-9-lines-of-python-for-hostile-environments/): 43 | 44 | wget -O - 'http://pastebin.com/raw.php?i=PcbNtyh9' | tr '\r' ' ' > wget2 45 | chmod 755 wget2 46 | ./wget2 https://github.com/wkoszek/synology/archive/0.1.1.tar.gz 47 | gunzip 0.1.1.tar.gz 48 | tar xf 0.1.1.tar 49 | cd synology-0.1.1 50 | ./bootstrap.sh 51 | 52 | (you may want to pick the latest `synology-x.x.x` release). 53 | 54 | This should initiate the bootstrap procedure. 55 | 56 | # What bootstrap does for you 57 | 58 | Upon running `bootstrap.sh` following things will happen: 59 | 60 | 1. `ipkg` will be fetched and installed. 61 | 2. ASH config will be updated to add `ipkg` to `PATH` 62 | 3. `.profile` will be updated with some usable aliases and mandatory settings 63 | 4. SSH keys will be generated. 64 | 5. SSH configuration will be installed for GitHub.com in case you want to push from your NAS 65 | 6. Updated start script for Debian chroot will be installed. It basically 66 | mounts home directories in the chroot directory, and also adds USB-mounted 67 | volumes there. 68 | 7. Debian's chroot environment will be started and updated. 69 | 8. Informational message will be printed. 70 | 71 | # Author 72 | 73 | - Wojciech Adam Koszek, [wojciech@koszek.com](mailto:wojciech@koszek.com) 74 | - [http://www.koszek.com](http://www.koszek.com) 75 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SYNO=syno-i686-bootstrap_1.2-7_i686.xsh 4 | URL=http://ipkg.nslu2-linux.org/feeds/optware/syno-i686/cross/unstable/${SYNO} 5 | R=/volume1/@appstore/debian-chroot/var/chroottarget/ 6 | 7 | echo "# Running ipkg / Debian chroot bootstrap" 8 | 9 | echo "# Do you want to install ipkg now? [y/n]" 10 | read A 11 | if [ "$A" = "y" ]; then 12 | ( 13 | echo "# will go HOME=${HOME}, make tmp" 14 | cd ${HOME} 15 | mkdir -p tmp && cd tmp 16 | 17 | echo "# will fetch ${URL} now" 18 | wget $URL 19 | 20 | echo "# will run ${SYNO} now" 21 | chmod 755 $SYNO 22 | ./$SYNO 23 | 24 | echo "# will add PATH to your ${HOME}/.profile" 25 | echo 'export PATH=/opt/bin:/opt/sbin:$PATH' >> $HOME/.profile 26 | ) 27 | else 28 | echo "Skipping!" 29 | fi 30 | 31 | P=`readlink ${HOME}/.profile` 32 | if [ "$P" = ".profile" ]; then 33 | echo "# ${HOME}/.profile already installed! Will skip" 34 | else 35 | if [ -f ~/.profile ]; then 36 | CMD="cp -H ~/.profile ~/.profile.`date +'%Y%m%d-%s'`" 37 | echo $CMD 38 | sh -c "$CMD" 39 | fi 40 | echo "# Installing symlink from ~/.profile -> .profile" 41 | ln -s `pwd`/.profile ${HOME}/.profile 42 | fi 43 | 44 | mkdir -p $HOME/keys 45 | if [ ! -f $HOME/keys/nas ]; then 46 | echo "# will generate SSH keys now in $HOME/keys" 47 | ssh-keygen -f $HOME/keys/nas -b 4096 -t rsa 48 | else 49 | echo "# $HOME/keys exists. Skipping SSH key generation!" 50 | fi 51 | 52 | echo "# About to enable proper GitHub configuration entry for SSH" 53 | mkdir -p ~/.ssh 54 | grep github.com ~/.ssh/config >/dev/null 2>/dev/null 55 | if [ $? -eq 0 ]; then 56 | echo "# ...$HOME/config has github.com entry already. Skipping!" 57 | else 58 | touch ~/.ssh/config 59 | ( 60 | echo "Host github.com" 61 | echo " IdentityFile /root/keys/nas" 62 | echo " User git" 63 | echo " HostName github.com" 64 | ) >> ~/.ssh/config 65 | fi 66 | 67 | S=/var/packages/debian-chroot/scripts/start-stop-status 68 | echo "# will backup to ./ and replace $S with ./start-stop-status" 69 | cp $S start-stop-status.bak 70 | cp start-stop-status $S 71 | 72 | # Based on http://www.hang321.net/en/2015/06/09/debian-chroot-on-dsm-5-2/ 73 | sed -i 's/fr.debian.org/us.debian.org/g' $R/etc/apt/sources.list 74 | cat > $R/setup.sh < myuser/synology -> Settings -> Deploy keys. Mark the key 98 | read/write to be able to push to the repository. 99 | 100 | Enjoy! Comments and feedback: Wojciech A. Koszek, wojciech@koszek.com 101 | --------------------------------------------------------------------- 102 | EOF 103 | -------------------------------------------------------------------------------- /ssh-vvvv: -------------------------------------------------------------------------------- 1 | /usr/bin/ssh -vvvv $* 2 | -------------------------------------------------------------------------------- /start-stop-status: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Package 4 | PACKAGE="debian-chroot" 5 | DNAME="Debian Chroot" 6 | 7 | # Others 8 | INSTALL_DIR="/usr/local/${PACKAGE}" 9 | PATH="${INSTALL_DIR}/bin:${PATH}" 10 | CHROOTTARGET=`realpath ${INSTALL_DIR}/var/chroottarget` 11 | 12 | 13 | start_daemon () 14 | { 15 | mkdir -p ${CHROOTTARGET}/mnt/volumeUSB1 16 | mkdir -p ${CHROOTTARGET}/mnt/volumeUSB2 17 | 18 | # Mount if install is finished 19 | if [ -f ${INSTALL_DIR}/var/installed ]; then 20 | # Make sure we don't mount twice 21 | grep -q "${CHROOTTARGET}/proc " /proc/mounts || mount -t proc proc ${CHROOTTARGET}/proc 22 | grep -q "${CHROOTTARGET}/sys " /proc/mounts || mount -t sysfs sys ${CHROOTTARGET}/sys 23 | grep -q "${CHROOTTARGET}/dev " /proc/mounts || mount -o bind /dev ${CHROOTTARGET}/dev 24 | grep -q "${CHROOTTARGET}/dev/pts " /proc/mounts || mount -o bind /dev/pts ${CHROOTTARGET}/dev/pts 25 | grep -q "${CHROOTTARGET}/home " `realpath /var/services/homes` || mount -o bind `realpath /var/services/homes` ${CHROOTTARGET}/home 26 | grep -q "${CHROOTTARGET}/volumeUSB1/usbshare" /proc/mounts || mount -o bind /volumeUSB1/usrshare ${CHROOTTARGET}/mnt/volumeUSB1 27 | grep -q "${CHROOTTARGET}/volumeUSB2/usbshare" /proc/mounts || mount -o bind /volumeUSB2/usbshare ${CHROOTTARGET}/mnt/volumeUSB2 28 | 29 | # Start all services 30 | ${INSTALL_DIR}/app/start.py 31 | fi 32 | } 33 | 34 | stop_daemon () 35 | { 36 | # Stop running services 37 | ${INSTALL_DIR}/app/stop.py 38 | 39 | # Unmount 40 | umount ${CHROOTTARGET}/dev/pts 41 | umount ${CHROOTTARGET}/dev 42 | umount ${CHROOTTARGET}/sys 43 | umount ${CHROOTTARGET}/proc 44 | umount ${CHROOTTARGET}/home 45 | umount ${CHROOTTARGET}/mnt/volumeUSB1 46 | umount ${CHROOTTARGET}/mnt/volumeUSB2 47 | } 48 | 49 | daemon_status () 50 | { 51 | `grep -q "${CHROOTTARGET}/proc " /proc/mounts` && `grep -q "${CHROOTTARGET}/sys " /proc/mounts` && `grep -q "${CHROOTTARGET}/dev " /proc/mounts` && `grep -q "${CHROOTTARGET}/dev/pts " /proc/mounts` 52 | } 53 | 54 | 55 | case $1 in 56 | start) 57 | if daemon_status; then 58 | echo ${DNAME} is already running 59 | exit 0 60 | else 61 | echo Starting ${DNAME} ... 62 | start_daemon 63 | exit $? 64 | fi 65 | ;; 66 | stop) 67 | if daemon_status; then 68 | echo Stopping ${DNAME} ... 69 | stop_daemon 70 | exit 0 71 | else 72 | echo ${DNAME} is not running 73 | exit 0 74 | fi 75 | ;; 76 | status) 77 | if daemon_status; then 78 | echo ${DNAME} is running 79 | exit 0 80 | else 81 | echo ${DNAME} is not running 82 | exit 1 83 | fi 84 | ;; 85 | chroot) 86 | chroot ${CHROOTTARGET}/ /bin/bash 87 | ;; 88 | *) 89 | exit 1 90 | ;; 91 | esac 92 | -------------------------------------------------------------------------------- /wget2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import urllib2, sys 3 | urlstr = sys.argv[1] 4 | fname = urlstr.split('/')[-1] 5 | response = urllib2.urlopen(urlstr) 6 | f = open(fname, "w") 7 | f.write(response.read()) 8 | f.close() 9 | print "written " + fname --------------------------------------------------------------------------------