목차

Xenial Xerus 설치 기록

미니서버를 2016년 5월 31일부로 14.04에서 16.04로 새로 설치하였다. 많이 변한 건 없는데, 해 놓은 게 많아서인지 설정할 것이 많았다. 특히 Nginx 변환 부분은 조금 힘들었음. 설치 기록을 남겨 본다.

Ubuntu 16.04 설치

/dev/sdb1을 시스템, /dev/sda1을 주 저장소로 지정하였다. /dev/sda1을 이전과 마찬가지로 /media/storage(스토리지)에 마운트하여 사용하는 전략은 변함이 없다. 일부 읽기, 쓰기가 잦은 시스템의 디렉토리를 스토리지로 연결하는 전략을 쓴다. 예를 들면 /var/log, /tmp 은 심볼릭 링크 처리하고 실제로는 /media/storage/log, /media/storage/tmp가 역할을 대신한다.

우분투 설치는 매우 심플하게 한다. 스토리지를 기본으로 마운팅하게 하는 것 이외에는 그냥 있는 그대로의 설정을 사용하는 편이다. 사실 USB 스틱에서 부팅하는 방식이니 당연히 복잡하게 할 이유가 없다.

사용자 계정 패스워드를 입력하는 단계에서 패스워드를 평문으로 확인할 수 있도록 체크박스가 추가되었다는 점이 특이하다. 그 외에는 외견상 변한 점은 없다. 기본으로 삼바 서버와 OpenSSH 서버 패키지를 설치해 주고 설치를 마친다. 부팅 모두 문제 없다.

예전에는 기본 리포지터리를 다음이나 다른 곳으로 변경했었지만, 지금은 그것마저도 별 필요 없는 듯.

Database 설치

데이터베이스는 간결하게 mysql-server를 사용하기로 했다.

apt-get install mysql-server

데이터베이스 저장소 변경

시스템이 USB 스틱 메모리에 위치한지라, 여기에 계속 읽기/쓰기가 반복되는 것이 조금 껄끄럽다 생각했다. MySQL 5.5 → 5.7로 마이그레이션하는 것이라 귀찮지만 미리 SQL 파일로 미리 데이터베이스를 모두 덤프해 두었다.

예전에는 눈치를 못챘거나 없었던 디렉토리가 생겼다.

이 세 디렉토리도 같이 옮기기로 결정.

AppArmor 설정 변경

나는 /tmp, /var/tmp를 모두 스토리지의 tmp 디렉토리로 심볼릭 링크를 걸었기 때문에, tmp 디렉토리까지도 설정을 변경해야 한다. 그러므로 /etc/apparmor.d/abstractions/user-tmp 파일의 마지막 부분에 다음 항목을 추가한다.

  # media/storage/tmp
  owner /media/storage/tmp/**         rwkl,
  /media/storage/tmp/                 rw,

다음으로 MySQL과 관련된 부분을 수정한다. /etc/apparmor.d/usr.sbin.mysqld

# Allow data dir access
  /media/storage/mysql/ r,
  /media/storage/mysql/** rwk,

# Allow data files dir access
  /media/storage/mysql-files/ r,
  /media/storage/mysql-files/** rwk,

# Allow keyring dir access
  /media/storage/mysql-keyring/ r,
  /media/storage/mysql-keyring/** rwk,

# Allow log file access
  /media/storage/log/mysql.err rw,
  /media/storage/log/mysql.log rw,
  /media/storage/log/mysql/ r,
  /media/storage/log/mysql/** rw,

my.cnf 변경

/etc/mysql/mysql.conf.d/mysqld.cnf

버퍼 사이즈, 캐시 사이즈는 적절히 조정해줬다. 기준이 없으니 적절히 더 주는 정도?

datadir		= /media/storage/mysql
tmpdir		= /media/storage/tmp

PHP 7.0

PHP 7.0이 기본으로 되었다. 쓰지 않을 이유가 없다. Nginx를 쓰기로 결정한 이상 FPM 방식을 사용해야 한다.

apt-get install php php-fpm php-gd php-mcrypt php-mbstring

FPM에서 발생하는 에러를 덤프하려면 /etc/php/7.0/fpm/pool.d/www.conf'

catch_workers_output = yes

php.ini에는 여러 사이트에서 입을 모아 설정을 변경하려는 부분이 있다. /etc/php/7.0/php.ini

cgi.fix_pathinfo=0

그리고 적절하게 업로드 사이즈를 변경해준다.

upload_max_filesize = 64M
post_max_size = 64M

pool 조정

특정 사이트의 PHP 실행 유저를 다르게 만들어 동작시킬 때 사용한다. /etc/php/7.0/fpm/pool.d 디렉토리의 www.conf 기본 파일을 적절히 편집해서 변경한다.

nginx설정에서 원하는 사이트의 fastcgi 소켓 경로를 변경해 준다. opcache 문제도 있을 수 있는데, 이건 그냥 스킵.

참고 사이트

NGINX

내 도메인이 주소가 아닌 직접 IP 접속은 같은 공유기 안의 주소가 아니면 오지 못하도록 막을 필요가 있다.

/etc/nginx/sites-available/default

# allow only localhost
allow 192.168.0.0/24;
allow 192.168.10.0/24;
deny all;

웹 애플리케이션 세팅

PhpMyAdmin

apt-get install phpmyadmin

/media/storage/www-data/conf.d/phpmyadmin.conf

phpmyadmin.conf
location /phpmyadmin {
	alias /usr/share/phpmyadmin;
	index index.php index.html index.htm;
	location ~ ^/phpmyadmin/(.+\.php)$ {
		root /usr/share;
		fastcgi_pass unix:/run/php/php7.0-fpm.sock;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;
	}
}

이 파일을 default에서 삽입한다.

# Include PhpMyAdmin address
include /media/storage/www-data/conf.d/phpmyadmin.conf;

Dokuwiki

vhost-wiki.conf
# Nginx Configuration

# 아래 설정은 https 적용 이후 http -> https 이동에 사용됨.
server {
    listen 	    80;
    server_name     wiki.changwoo.pe.kr;
    return          301 https://$server_name$request_uri;
}

server {
	listen 80;

	server_name wiki.changwoo.pe.kr;

	client_max_body_size 32M;
	client_body_buffer_size 256k;

	root /media/storage/www-data/changwoo.pe.kr/wiki;

	index doku.php;

	# Remember to comment the below out when you're installing, and uncomment it when done.
	location ~ /(data/|conf/|bin/|inc/|install.php) {
		 deny all;
	}

	# Uncomment this prevents images being displayed ! 
    #location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    #    expires 31536000s;
    #    add_header Pragma "public";
    #    add_header Cache-Control "max-age=31536000, public, must-revalidate, proxy-revalidate";
    #    log_not_found off;
    #}
    
	location / {
		try_files $uri $uri/ @dokuwiki;
	}

	location @dokuwiki {
        rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
        rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
        rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
        rewrite ^/(.*) /doku.php?id=$1&$args last;
    }

	location ~ \.php {
		include snippets/fastcgi-php.conf;
		
		fastcgi_buffers 16 16k;
		fastcgi_buffer_size 32k;

		fastcgi_pass unix:/run/php/php7.0-fpm.sock;
	}

	location  ~ /\.ht {
		deny all;
	}
}

nginx라면 복구 이후 멋진 URL에서 .htaccess 방식을 선택해야 문서가 올바르게 보인다.

WordPress

이 녀석은 조금 복잡하다.

wordpress-restrictions.conf
# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
	log_not_found off;
	access_log off;
}

location = /robots.txt {
	allow all;
	log_not_found off;
	access_log off;
}

# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
	deny all;
}

# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
	deny all;
}
wordpress.conf
# WordPress single site rules.
# Designed to be included in any server {} block.

# This order might seem weird - this is attempted to match last if rules below fail.
# http://wiki.nginx.org/HttpCoreModule
location / {
	try_files $uri $uri/ /index.php?$args;
}

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
	access_log off;
	log_not_found off;
	expires max;
}

# Uncomment one of the lines below for the appropriate caching plugin (if used).
#include global/wordpress-wp-super-cache.conf;
#include global/wordpress-w3-total-cache.conf;

# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ [^/]\.php(/|$) {
	fastcgi_split_path_info ^(.+?\.php)(/.*)$;
	if (!-f $document_root$fastcgi_script_name) {
		return 404;
	}
	# This is a robust solution for path info security issue and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default)

#	include fastcgi_params;
#	fastcgi_index index.php;
#	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#	fastcgi_intercept_errors on;
#	fastcgi_pass php;

	include snippets/fastcgi-php.conf;
	fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
vhost-wordpress.conf
# 아래 설정은 https 적용 이후 http -> https 이동에 사용됨.
server {
    listen 	    80;
    server_name     wiki.changwoo.pe.kr;
    return          301 https://$server_name$request_uri;
}

server {
	server_name blog.changwoo.pe.kr;
	
	root /media/storage/www-data/changwoo.pe.kr/wordpress;

	index index.php;

        # wp-login.php, wp-admin 접근을 IP로 제한 (단, wp-ajax.php는 AJAX를 활용해야 하므로 허용)
        location ~ ^/(wp-admin(?!/admin-ajax\.php)|wp-login.php) {
            allow 192.168.0.0/24;
            deny all;
            include snippets/fastcgi-php.conf;
	    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

	include /media/storage/www-data/conf.d/wordpress-restrictions.conf;
	include /media/storage/www-data/conf.d/wordpress.conf;
}

Ampache

그동안 모바일 기기에서 제대로 재생이 되지 않는 문제가 있었다가, nginx 설정을 변경해 줌으로써 해결하였다. 아래는 성공한 설정 텍스트. 이 쪽의 설정을 가져와 문제가 되는 부분을 적절히 수정한 것.

vhost-ampache.conf
server {
 
    # listen to
    #listen  [::]:used_port; #ssl; ipv6 optional with ssl enabled
    listen   80; #ssl; ipv4 optional with ssl enabled
 
    server_name stream.changwoo.pe.kr;
    charset utf-8;
 
    # Logging, error_log mode [notice] is necessary for rewrite_log on,
    # (very usefull if rewrite rules do not work as expected)
 
       error_log       /var/log/ampache/error.log; #notice;
       access_log      /var/log/ampache/access.log;
       # rewrite_log     on;
 
    # only optional for ssl encryption enabled: Path to certificate/key
 
        # ssl_certificate         /etc/ssl/certs/cert.crt;
        # ssl_certificate_key     /etc/ssl/private/key.key;
 
    root  /media/storage/www-data/changwoo.pe.kr/ampache;
    index index.php;
 
    # Somebody said this helps, in my setup it doesn't prevent temporary saving in files
    proxy_max_temp_file_size 0;
 
    # Rewrite rule for Subsonic backend
    if ( !-d $request_filename ) {
        rewrite ^/rest/(.*).view$ /rest/index.php?action=$1 last;
        rewrite ^/rest/fake/(.+)$ /play/$1 last;
    }
 
    # Rewrite rule for Channels
    if (!-d $request_filename){
      rewrite ^/channel/([0-9]+)/(.*)$ /channel/index.php?channel=$1&target=$2 last;
    }
 
    # Beautiful URL Rewriting
    # rewrite ^/play/ssid/(.*)/type/(\w+)/oid/([0-9]+)/uid/([0-9]+)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&name=$5 last;
    # rewrite ^/play/ssid/(.*)/type/(\w+)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&name=$7 last;
    # rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&player=$7&name=$8 last;
    # rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/transcode_to/(w+)/bitrate/([0-9]+)/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&transcode_to=$7&bitrate=$8&player=$9&name=$10 last;
 
    # Subsonic Apps (not working!)
    # rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/content_length/(.*)/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&content_length=$7&player=$8&name=$9 redirect;
    # rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/bitrate/([0-9]+)/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&bitrate=$7&player=$8&name=$9 redirect;
    # rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&player=$7&name=$8 redirect;
 
    # the following line was needed for me to get downloads of single songs to work
    rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/action/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4action=$5&name=$6 last;
 
    location /play/ssid {
        if (!-e $request_filename) {
            # Subsonic Apps
            rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/content_length/(.*)/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&content_length=$7&player=$8&name=$9 last;
            rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/bitrate/([0-9]+)/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&bitrate=$7&player=$8&name=$9 last;
            rewrite ^/play/ssid/(.*)/type/(.*)/oid/([0-9]+)/uid/([0-9]+)/client/(.*)/noscrobble/([0-1])/player/(.*)/name/(.*)$ /play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&client=$5&noscrobble=$6&player=$7&name=$8 last;
            break;
        }
    }
 
    location /play {
        if (!-e $request_filename) {
            rewrite ^/play/art/([^/]+)/([^/]+)/([0-9]+)/thumb([0-9]*)\.([a-z]+)$ /image.php?object_type=$2&object_id=$3&auth=$1;
            break;
        }
 
        rewrite ^/([^/]+)/([^/]+)(/.*)?$ /play/$3?$1=$2;
        rewrite ^/(/[^/]+|[^/]+/|/?)$ /play/index.php last;
        break;
    }
 
   location /rest {
      limit_except GET POST {
         deny all;
      }
   }
 
   location ^~ /bin/ {
      deny all;
      return 403;
   }
 
   location ^~ /config/ {
      deny all;
      return 403;
   }
 
   location / {
      limit_except GET POST HEAD{
         deny all;
      }
   }
 
   location ~ ^/.*.php {
        try_files $uri = 404;
        fastcgi_index index.php;
 
    # sets the timeout for requests in [s] , 60s are normally enough
        fastcgi_read_timeout 600s;
 
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 
    # Mitigate HTTPOXY https://httpoxy.org/
        fastcgi_param HTTP_PROXY "";
 
    # has to be set to on if encryption (https) is used:
        # fastcgi_param HTTPS on;
 
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
 
    # chose as your php-fpm is configured to listen on
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        # fastcgi_pass 127.0.0.1:8000/;
   }
 
   # Rewrite rule for WebSocket
   location /ws {
        rewrite ^/ws/(.*) /$1 break;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8100/;
   }
}

Python 계열 세팅

내가 운용 중인 모든 애플리케이션은 Python3로 작성되어 있으니, 그 쪽으로 세팅을 맞춘다.

apt install python3-pip

virtualenv, virtualenvwrapper도 다시 설정해 주자.

pip3 install virtualenv virtualenvwrapper

uwsgi는 시스템 쪽으로 맞춰 줬다.

pip3 install uwsgi

Nginx

miniserver-apps.conf
# Nginx configuration for miniserver-apps
upstream django {
	server unix://<unix_socket>
}

server {
	
	listen 80;
	
	server_name apps.changwoo.pe.kr;

	charset utf-8;

	client_max_body_size 8M;

	location /favicon.ico {
		access_log off;
		log_not_found off;
	}

	location /static {
		alias <path_to_application>/static;
	}

	location / {
		uwsgi_pass django;
		include    uwsgi_params;
	}
}

uWSGI

앱이 하나일 때는 아래와 같이 간단하게 master로 돌렸다.

miniserver-apps.ini
[uwsgi]
# Djnago project base directory
chdir  = <project root>

# WSGI Python module
module = miniserver.wsgi

# Virtualenv path
home   = <virtualenv path>

master    = true
processes = 4
socket    = <path-to-socket>
vacuum    = true

chmod-socket = 664
chown-socket = owner:group

enable-threads = true

pidfile   = <path-to-pidfile>
daemonize = <path-to-log>

그러나 복수의 앱을 운영해야 할 시점이 생기자 엡퍼러(emperor) 모드가 필요해졌다. 엠퍼러 모드는 간단하게 이렇게 쓸 수 있다.

uwsgi-emperor.ini
uid=owner

daemonize=<path-to-log>

emperor=<path-to-store-vassals>

<path-to-store-vassals>에는 그룹으로 돌릴 ini 파일들을 넣으면 된다. 즉 miniserver-apps.ini 파일 같은 것을 그대로 이 디렉토리에 넣으면 되는데, 이 때 주의할 점은 몇몇 설정들은 이미 엠퍼러에서 진행되었으므로 삭제해야 한다. 예를 들어 miniserver-apps.ini에서 demonize, uid 같은 설정값은 에러를 낼 수 있다.

rc.local

매번 부팅때마다 돌려 줘야 하므로,

/usr/local/bin/uwsgi --ini ini_file.ini

자 이렇게 대략 세팅해 주면 파이썬은 돌아간다.

uwsgi --stop /tmp/project-master.pid
uwsgi --reload /tmp/project-master.pid
kill -HUP `cat /tmp/project-master.pid`
killall -s INT uwsgi

사용자 계정 생성

changwoo 계정 생성

useradd -m -d /media/storage/changwoo -s /bin/bash

Samba

삼바는 이미 설치되어 있으므로 아주 간단하게 내부에서 공유 디렉토리만 되도록 설정 추가한다.

/etc/samba/smb.conf

[changwoo]
path = /media/storage/changwoo
writable = yes
create mask = 0644
directory mask = 0755

심볼릭 링크를 추가하기 위해 다음과 같은 세팅을 주었다1)

[global]
allow insecure wide links = yes

[share]
follow symlinks = yes
wide links = yes
service smbd restart

Dropbox

dropbox
#!/bin/sh
#
# Copied from http://forums.dropbox.com/topic.php?id=38529#post-414344
# Modified by jay@gooby.org (@jaygooby on Twitter)

### BEGIN INIT INFO
# Provides: dropbox
# Required-Start: $local_fs $remote_fs $network $syslog $named
# Required-Stop: $local_fs $remote_fs $network $syslog $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# X-Interactive: false
# Short-Description: dropbox service
### END INIT INFO

# dropbox service
DROPBOX_USERS="changwoo"

start() {
  echo "Starting dropbox..."
  for dbuser in $DROPBOX_USERS; do
    HOMEDIR=$(getent passwd $dbuser | cut -d: -f6)

    DAEMON=$(find $HOMEDIR/.dropbox-dist/dropbox-lnx.* -name dropboxd)

    if [ -x $DAEMON ]; then
      HOME="$HOMEDIR" start-stop-daemon -b -o -c $dbuser -S -u $dbuser -x $DAEMON -p "$HOMEDIR/.dropbox/dropbox.pid"
    fi
  done
}

stop() {
  echo "Stopping dropbox..."
    for dbuser in $DROPBOX_USERS; do
      HOMEDIR=$(getent passwd $dbuser | cut -d: -f6)

      DAEMON=$(find $HOMEDIR/.dropbox-dist/dropbox-lnx.* -name dropbox)

      if [ -x $DAEMON ]; then
        start-stop-daemon -o -c $dbuser -K -u $dbuser -x $DAEMON
      fi
  done
}

status() {
  for dbuser in $DROPBOX_USERS; do
    dbpid=$(pgrep -u $dbuser dropbox)
    if [ -z $dbpid ] ; then
      echo "dropboxd for USER $dbuser: not running."
    else
      echo "dropboxd for USER $dbuser: running (pid $dbpid)"
    fi
 done
}

case "$1" in

start)
start
;;

stop)
stop
;;

restart|reload|force-reload)

stop
start
;;

status)
status
;;

*)
echo "Usage: /etc/init.d/dropbox {start|stop|reload|force-reload|restart|status}"
exit 1

esac

exit 0

/etc/init.d/dropbox

Torrent

언제나 그렇듯 deluge를 애용한다.

apt-get install deluge-common deluge-web deluged

같이 데몬 스크립트도 설치되지만, 이 스크립트는 web UI를 기본 지원하지 않아 불만족스럽다. 기존 스크립트로 대체한다.

/etc/default/deluge-daemon

deluge-daemon
# Configuration for /etc/init.d/deluge-daemon

# The init.d script will only run if this variable non-empty.
DELUGED_USER="changwoo"             # !!!CHANGE THIS!!!!

# Should we run at startup?
RUN_AT_STARTUP="YES"

/etc/init.d/deluge-daemon

deluge-daemon
#!/bin/sh
### BEGIN INIT INFO
# Provides:          deluge-daemon
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Should-Start:      $network
# Should-Stop:       $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Daemonized version of deluge and webui.
# Description:       Starts the deluge daemon with the user specified in
#                    /etc/default/deluge-daemon.
### END INIT INFO

# Author: Adolfo R. Brandes 
# Updated by: Jean-Philippe "Orax" Roemer

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Deluge Daemon"
NAME1="deluged"
NAME2="deluge"
DAEMON1=/usr/bin/deluged
DAEMON1_ARGS="-d -c /media/storage/changwoo/.config/deluge -L info -l /media/storage/changwoo/.config/deluge/deluge.log"             # Consult `man deluged` for more options
DAEMON2=/usr/bin/deluge-web
DAEMON2_ARGS=""               # Consult `man deluge-web` for more options
PIDFILE1=/var/run/$NAME1.pid
PIDFILE2=/var/run/$NAME2.pid
UMASK=022                     # Change this to 0 if running deluged as its own user
PKGNAME=deluge-daemon
SCRIPTNAME=/etc/init.d/$PKGNAME

# Exit if the package is not installed
[ -x "$DAEMON1" -a -x "$DAEMON2" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$PKGNAME ] && . /etc/default/$PKGNAME

# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

if [ -z "$RUN_AT_STARTUP" -o "$RUN_AT_STARTUP" != "YES" ]
then
   log_warning_msg "Not starting $PKGNAME, edit /etc/default/$PKGNAME to start it."
   exit 0
fi

if [ -z "$DELUGED_USER" ]
then
    log_warning_msg "Not starting $PKGNAME, DELUGED_USER not set in /etc/default/$PKGNAME."
    exit 0
fi

#
# Function to verify if a pid is alive
#
is_alive()
{
   pid=`cat $1` > /dev/null 2>&1
   kill -0 $pid > /dev/null 2>&1
   return $?
}

#
# Function that starts the daemon/service
#
do_start()
{
   # Return
   #   0 if daemon has been started
   #   1 if daemon was already running
   #   2 if daemon could not be started

   is_alive $PIDFILE1
   RETVAL1="$?"

   if [ $RETVAL1 != 0 ]; then
       rm -f $PIDFILE1
       start-stop-daemon --start --background --quiet --pidfile $PIDFILE1 --make-pidfile \
       --exec $DAEMON1 --chuid $DELUGED_USER --user $DELUGED_USER --umask $UMASK -- $DAEMON1_ARGS
       RETVAL1="$?"
   else
       is_alive $PIDFILE2
       RETVAL2="$?"
       [ "$RETVAL2" = "0" -a "$RETVAL1" = "0" ] && return 1
   fi

   is_alive $PIDFILE2
   RETVAL2="$?"

   if [ $RETVAL2 != 0 ]; then
        sleep 2
        rm -f $PIDFILE2
        start-stop-daemon --start --background --quiet --pidfile $PIDFILE2 --make-pidfile \
        --exec $DAEMON2 --chuid $DELUGED_USER --user $DELUGED_USER --umask $UMASK -- $DAEMON2_ARGS
        RETVAL2="$?"
   fi
   [ "$RETVAL1" = "0" -a "$RETVAL2" = "0" ] || return 2
}

#
# Function that stops the daemon/service
#
do_stop()
{
   # Return
   #   0 if daemon has been stopped
   #   1 if daemon was already stopped
   #   2 if daemon could not be stopped
   #   other if a failure occurred

   start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user $DELUGED_USER --pidfile $PIDFILE2
   RETVAL2="$?"
   start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user $DELUGED_USER --pidfile $PIDFILE1
   RETVAL1="$?"
   [ "$RETVAL1" = "2" -o "$RETVAL2" = "2" ] && return 2

   rm -f $PIDFILE1 $PIDFILE2

   [ "$RETVAL1" = "0" -a "$RETVAL2" = "0" ] && return 0 || return 1
}

case "$1" in
  start)
   [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME1"
   do_start
   case "$?" in
      0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
      2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
   esac
   ;;
  stop)
   [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME1"
   do_stop
   case "$?" in
      0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
      2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
   esac
   ;;
  restart|force-reload)
   log_daemon_msg "Restarting $DESC" "$NAME1"
   do_stop
   case "$?" in
     0|1)
      do_start
      case "$?" in
         0) log_end_msg 0 ;;
         1) log_end_msg 1 ;; # Old process is still running
         *) log_end_msg 1 ;; # Failed to start
      esac
      ;;
     *)
        # Failed to stop
      log_end_msg 1
      ;;
   esac
   ;;
  *)
   echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
   exit 3
   ;;
esac

:

패키지로 설치된 /etc/init.d/deluged는 실행되지 않도록 수정.

/etc/init.d# systemctl disable deluged
chmod -x /etc/init.d/deluged

동작하도록 재설정

systemctl daemon-reload
service deluge-daemon start

CronTab

python-onedrive

이 프로젝트는 폐기되었지만, 간단하게 쓰고 있었고 당분간은 동작하므로 그냥 쓴다.

apt install python-pip requests pyYAML

~/.lcrc에 client id, secret을 설정하고

onedrive-cli quota

스크립트들

도쿠위키는 월요일 오전 4시에, 워드프레스는 월요일 오전 5시에 백업.

  0  4  *   *   1     /media/storage/changwoo/Dropbox/MiniServer/scripts/dokuwiki_autobackup
  0  5  *   *   1     /media/storage/changwoo/Dropbox/MiniServer/scripts/wp_backup.sh

Resilio-Sync

Resilio-Sync 로 비트토렌트 방식의 싱크. 라즈베리 파이에서 BitTorrentSync로 데이터 동기화하기 같은 문서로도 작성한 바가 있다. 이게 이름이 바뀌었다.

가정용은 무료이니 나같이 그냥 비디오 디렉토리 공유하는 수준에서는 괜찮은 선택인 것 같다.

deb 패키지가 제공되니 깔아 주면 그만이다. service resilio-sync start 명령으로 실행하면 되는데, 변경은 다음과 같은 명령으로

$ sudo systemctl edit resilio-sync.service 
 
[Service]
User=changwoo
Group=changwoo
PIDFile=
PIDFile=/home/changwoo/.config/resilio-sync/sync.pid
ExecStartPre=
ExecStartPre=/bin/mkdir -p /home/changwoo/.config/resilio-sync
ExecStartPre=/bin/chown -R changwoo:changwoo /home/changwoo/.config/resilio-sync
ExecStart=
ExecStart=/usr/bin/rslsync --config /home/changwoo/.config/resilio-sync/config.json

systemctl edit 명령은 파일 자체를 변경하는 것이 아니라 overriding 하는 방식이다.그리고 override 할 때 기존 명령어는 한번 비워주는 작업이 필요하다. 그래서 “ExexStart=” 같은 라인이 생기는 것이다. 저것이 없으면 에러.

$ sudo systemctl cat resilio-sync.service
 
[Unit]
Description=Resilio Sync service
Documentation=https://help.getsync.com/
After=network.target network-online.target
 
[Service]
Type=forking
User=rslsync
Group=rslsync
UMask=0002
Restart=on-failure
PermissionsStartOnly=true
PIDFile=/var/run/resilio-sync/sync.pid
ExecStartPre=/bin/mkdir -p /var/run/resilio-sync
ExecStartPre=/bin/chown -R rslsync:rslsync /var/run/resilio-sync
ExecStart=/usr/bin/rslsync --config /etc/resilio-sync/config.json
 
[Install]
WantedBy=multi-user.target
 
# /etc/systemd/system/resilio-sync.service.d/override.conf
[Service]
User=changwoo
Group=changwoo
PIDFile=
PIDFile=/home/changwoo/.config/resilio-sync/sync.pid
ExecStartPre=
ExecStartPre=/bin/mkdir -p /home/changwoo/.config/resilio-sync
ExecStartPre=/bin/chown -R changwoo:changwoo /home/changwoo/.config/resilio-sync
ExecStart=
ExecStart=/usr/bin/rslsync --config /home/changwoo/.config/resilio-sync/config.json

이렇게 덧붙여지는 것을 참고하자.

SSL 설비

이제는 필수로 구비하자. Let's Encrypt가 있다. 아래의 가이드를 따라하면 어렵지 않다.

3개월마다 갱신해야 하는데, 나는 아직 자동 갱신을 하지는 않았다. 나중에 확인하고 달아 보도록 하자.