#!/bin/bash SCRIPT=$(readlink -f "$0") INSTALLPATH=$(dirname "${SCRIPT}") TOPDIR=$(dirname "${INSTALLPATH}") default_ccnet_conf_dir=${TOPDIR}/ccnet default_seafile_data_dir=${TOPDIR}/seafile-data default_seahub_db=${TOPDIR}/seahub.db default_conf_dir=${TOPDIR}/conf default_pids_dir=${TOPDIR}/pids default_logs_dir=${TOPDIR}/logs pro_pylibs_dir=${INSTALLPATH}/pro/python export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} server_manual_http='https://download.seafile.com/published/seafile-manual/home.md' function welcome () { echo "-----------------------------------------------------------------" if [[ $IS_PRO_VERSION = "true" ]]; then echo "This script will guide you to config and setup your seafile professional server." else echo "This script will guide you to config and setup your seafile server." fi echo -e "\nMake sure you have read seafile server manual at \n\n\t${server_manual_http}\n" echo -e "Note: This script will guide your to setup seafile server using sqlite3," echo "which may have problems if your disk is on a NFS/CIFS/USB." echo "In these cases, we suggest you setup seafile server using MySQL." echo echo "Press [ENTER] to continue" echo "-----------------------------------------------------------------" read dummy echo } function err_and_quit () { printf "\n\n\033[33mError occured during setup. \nPlease fix possible issues and run the script again.\033[m\n\n" exit 1; } function on_ctrl_c_pressed () { printf "\n\n\033[33mYou have pressed Ctrl-C. Setup is interrupted.\033[m\n\n" exit 1; } # clean newly created ccnet/seafile configs when exit on SIGINT trap on_ctrl_c_pressed 2 function check_sanity () { if ! [[ -d ${INSTALLPATH}/seahub && -d ${INSTALLPATH}/seafile \ && -d ${INSTALLPATH}/runtime ]]; then echo echo "The seafile-server diretory doesn't contain all needed files." echo "Please make sure you have extracted all files and folders from tarball." err_and_quit; fi } function read_yes_no () { printf "[yes|no] " read yesno; while [[ "${yesno}" != "yes" && "${yesno}" != "no" ]] do printf "please answer [yes|no] " read yesno; done if [[ "${yesno}" == "no" ]]; then return 1; else return 0; fi } function check_existing_ccnet () { if [[ -d ${default_ccnet_conf_dir} ]]; then echo "\033[31m Error: \033[0m Ccnet config dir \"${default_ccnet_conf_dir}\" already exists." echo exit 1; fi echo } function check_existing_seafile () { if [[ -d ${default_seafile_data_dir} ]]; then echo "\033[31m Error: \033[0m Seafile server data dir \"${default_seafile_data_dir}\" already exists." echo exit 1; fi echo } function check_python_executable() { if [[ "$PYTHON" != "" && -x $PYTHON ]]; then return 0 fi if which python3 2>/dev/null 1>&2; then PYTHON=python3 elif !(python --version 2>&1 | grep "3\.[0-9]\.[0-9]") 2>/dev/null 1>&2; then echo echo "The current version of python is not 3.x.x, please use Python 3.x.x ." echo err_and_quit else PYTHON="python"$(python --version | cut -b 8-10) if !which $PYTHON 2>/dev/null 1>&2; then echo echo "Can't find a python executable of $PYTHON in PATH" echo "Install $PYTHON before continue." echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment variable to it" echo err_and_quit fi fi echo "Find python: $PYTHON" echo } function check_python_module () { module=$1 name=$2 hint=$3 printf " Checking python module: ${name} ... " if ! $PYTHON -c "import ${module}" 2>/dev/null 1>&2; then echo printf "\033[33m ${name} \033[m is not installed, Please install it first.\n" if [[ "${hint}" != "" ]]; then printf "${hint}" echo fi err_and_quit; fi echo -e "Done." } function check_python () { echo "Checking python on this machine ..." check_python_executable check_python_module sqlite3 python-sqlite3 echo } function check_sqlite3 () { echo -n "Checking for sqlite3 ..." if ! which sqlite3 2>/dev/null 1>&2; then echo -e "\nSqlite3 is not found. install it first.\n" echo "On Debian/Ubuntu: apt-get install sqlite3" echo "On CentOS/RHEL: yum install sqlite" err_and_quit; fi printf "Done.\n\n" } function check_system_dependency () { printf "Checking packages needed by seafile ...\n\n" check_python; check_sqlite3; printf "Checking Done.\n\n" } function ask_question () { question=$1 default=$2 key=$3 printf "${question}" printf "\n" if [[ "${default}" != "" && "${default}" != "nodefault" ]] ; then printf "[default: ${default} ] " elif [[ "${key}" != "" ]]; then printf "[${key}]: " fi } function get_server_name () { question="What would you like to use as the name of this seafile server?\nYour seafile users will be able to see the name in their seafile client." hint="You can use a-z, A-Z, 0-9, _ and -, and the length should be 3 ~ 15" ask_question "${question}\n${hint}" "nodefault" "server name" read server_name if [[ "${server_name}" == "" ]]; then echo echo "server name cannot be empty" get_server_name elif [[ ! ${server_name} =~ ^[a-zA-Z0-9_-]{3,14}$ ]]; then printf "\n\033[33m${server_name}\033[m is not a valid name.\n" get_server_name; fi echo } function get_server_ip_or_domain () { question="What is the ip or domain of this server?\nFor example, www.mycompany.com, or, 192.168.1.101" ask_question "${question}\n" "nodefault" "This server's ip or domain" read ip_or_domain if [[ "${ip_or_domain}" == "" ]]; then echo echo "ip or domain cannot be empty" get_server_ip_or_domain fi echo } # function get_ccnet_server_port () { # question="What tcp port do you want to use for ccnet server?" # hint="10001 is the recommended port." # default="10001" # ask_question "${question}\n${hint}" "${default}" # read server_port # if [[ "${server_port}" == "" ]]; then # server_port="${default}" # fi # if [[ ! ${server_port} =~ ^[0-9]+$ ]]; then # echo "\"${server_port}\" is not a valid port number. " # get_ccnet_server_port # fi # echo # } # function get_seafile_server_port () { # question="What tcp port would you like to use for seafile server?" # hint="12001 is the recommended port." # default="12001" # ask_question "${question}\n${hint}" "${default}" # read seafile_server_port # if [[ "${seafile_server_port}" == "" ]]; then # seafile_server_port="${default}" # fi # if [[ ! ${seafile_server_port} =~ ^[0-9]+$ ]]; then # echo "\"${seafile_server_port}\" is not a valid port number. " # get_seafile_server_port # fi # echo # } function get_fileserver_port () { question="What tcp port do you want to use for seafile fileserver?" hint="8082 is the recommended port." default="8082" ask_question "${question}\n${hint}" "${default}" read fileserver_port if [[ "${fileserver_port}" == "" ]]; then fileserver_port="${default}" fi if [[ ! ${fileserver_port} =~ ^[0-9]+$ ]]; then echo "\"${fileserver_port}\" is not a valid port number. " get_fileserver_port fi echo } # function get_seafile_data_dir () { # question="Where would you like to store your seafile data?" # note="Please use a volume with enough free space." # default=${default_seafile_data_dir} # ask_question "${question} \n\033[33mNote: \033[m${note}" "${default}" # read seafile_data_dir # if [[ "${seafile_data_dir}" == "" ]]; then # seafile_data_dir=${default} # fi # # if [[ -d ${seafile_data_dir} && -f ${seafile_data_dir}/seafile.conf ]]; then # echo # echo "It seems that you have already existing seafile data in ${seafile_data_dir}." # echo "Would you like to use the existing seafile data?" # if ! read_yes_no; then # echo "You have chosen not to use existing seafile data in ${seafile_data_dir}" # echo "You need to specify a different seafile data directory or remove ${seafile_data_dir} before continuing." # get_seafile_data_dir # else # use_existing_seafile="true" # fi # elif [[ -d ${seafile_data_dir} && $(ls -A ${seafile_data_dir}) != "" ]]; then # echo # echo "${seafile_data_dir} is an existing non-empty directory. Please specify a different directory" # echo # get_seafile_data_dir # elif [[ ! ${seafile_data_dir} =~ ^/ ]]; then # echo # echo "\"${seafile_data_dir}\" is not an absolute path. Please specify an absolute path." # echo # get_seafile_data_dir # elif [[ ! -d $(dirname ${seafile_data_dir}) ]]; then # echo # echo "The path $(dirname ${seafile_data_dir}) does not exist." # echo # get_seafile_data_dir # fi # echo # } function gen_ccnet_conf () { mkdir -p ${default_conf_dir} ccnet_conf=${default_conf_dir}/ccnet.conf if ! $(cat > ${ccnet_conf} <<EOF [General] EOF ); then echo "failed to generate ccnet.conf"; err_and_quit fi mkdir -p ${default_ccnet_conf_dir} } function gen_seafile_conf () { mkdir -p ${default_conf_dir} seafile_conf=${default_conf_dir}/seafile.conf if ! $(cat > ${seafile_conf} <<EOF [fileserver] port=$fileserver_port EOF ); then echo "failed to generate seafile.conf"; err_and_quit fi mkdir -p ${default_seafile_data_dir} } function gen_gunicorn_conf () { mkdir -p ${default_conf_dir} gunicorn_conf=${default_conf_dir}/gunicorn.conf.py if ! $(cat > ${gunicorn_conf} <<EOF import os daemon = True workers = 5 # default localhost:8000 bind = "127.0.0.1:8000" # Pid pids_dir = '$default_pids_dir' pidfile = os.path.join(pids_dir, 'seahub.pid') # for file upload, we need a longer timeout value (default is only 30s, too short) timeout = 1200 limit_request_line = 8190 EOF ); then echo "failed to generate gunicorn.conf.py"; err_and_quit fi } function gen_seafdav_conf () { mkdir -p ${default_conf_dir} seafdav_conf=${default_conf_dir}/seafdav.conf if ! $(cat > ${seafdav_conf} <<EOF [WEBDAV] enabled = false port = 8080 share_name = / EOF ); then echo "failed to generate seafdav.conf"; err_and_quit fi } function copy_user_manuals() { src_docs_dir=${INSTALLPATH}/seafile/docs/ library_template_dir=${default_seafile_data_dir}/library-template mkdir -p ${library_template_dir} cp -f ${src_docs_dir}/*.doc ${library_template_dir} } function parse_params() { while getopts n:i:p arg; do case $arg in n) server_name=${OPTARG} ;; i) ip_or_domain=${OPTARG} ;; p) fileserver_port=${OPTARG} ;; esac done } function validate_params() { # server_name default hostname -s if [[ "$server_name" == "" ]]; then server_name=${SERVER_NAME:-`hostname -s`} fi if [[ ! ${server_name} =~ ^[a-zA-Z0-9_-]{3,14}$ ]]; then echo "Invalid server name param" err_and_quit; fi # ip_or_domain default hostname -i if [[ "$ip_or_domain" == "" ]]; then ip_or_domain=${SERVER_IP:-`hostname -i`} fi if [[ "$ip_or_domain" != "" && ! ${ip_or_domain} =~ ^[^.].+\..+[^.]$ ]]; then echo "Invalid ip or domain param" err_and_quit; fi # fileserver_port default 8082 if [[ "${fileserver_port}" == "" ]]; then fileserver_port=${FILESERVER_PORT:-8082} fi if [[ ! ${fileserver_port} =~ ^[0-9]+$ ]]; then echo "Invalid fileserver port param" err_and_quit; fi } function usage() { echo "auto mode:" echo -e "$0 auto\n" \ "-n server name\n" \ "-i ip or domain\n" \ "-p fileserver port\n" \ "-d seafile dir to store seafile data" echo "" echo "interactive mode:" echo "$0" } # ------------------------------------------- # Main workflow of this script # ------------------------------------------- echo "-----------------------------------------------------------------" echo echo "[Warning] SQLite database support is deprecated. The support of SQLite database will be removed in version 12 or version 13." echo echo "-----------------------------------------------------------------" echo for param in $@; do if [[ "$param" == "-h" || "$param" == "--help" ]]; then usage; exit 0 fi done need_pause=1 if [[ $# -ge 1 && "$1" == "auto" ]]; then # auto mode, no pause shift parse_params $@; validate_params; need_pause=0 fi check_sanity; if [[ "${need_pause}" == "1" ]]; then welcome; fi sleep .5 check_system_dependency; sleep .5 check_existing_ccnet; check_existing_seafile; if [[ "${server_name}" == "" ]]; then get_server_name; fi if [[ "${ip_or_domain}" == "" ]]; then get_server_ip_or_domain; fi if [[ "$fileserver_port" == "" ]]; then get_fileserver_port fi sleep .5 printf "\nThis is your config information:\n\n" printf "server name: \033[33m${server_name}\033[m\n" printf "server ip/domain: \033[33m${ip_or_domain}\033[m\n" printf "seafile data dir: \033[33m${default_seafile_data_dir}\033[m\n" printf "fileserver port: \033[33m${fileserver_port}\033[m\n" if [[ "${need_pause}" == "1" ]]; then echo echo "If you are OK with the configuration, press [ENTER] to continue." read dummy fi # ------------------------------------------- # Create ccnet conf # ------------------------------------------- echo "Generating ccnet configuration in ${default_ccnet_conf_dir}..." echo gen_ccnet_conf; echo # ------------------------------------------- # Create seafile conf # ------------------------------------------- echo "Generating seafile configuration in ${default_seafile_data_dir} ..." echo gen_seafile_conf; echo # ------------------------------------------- # Generate gunicorn.conf.py # ------------------------------------------- gen_gunicorn_conf; # ------------------------------------------- # Generate seafevents.conf # ------------------------------------------- gen_seafdav_conf; # ------------------------------------------- # generate seahub/settings.py # ------------------------------------------- dest_settings_py=${TOPDIR}/conf/seahub_settings.py seahub_secret_keygen=${INSTALLPATH}/seahub/tools/secret_key_generator.py if [[ ! -f ${dest_settings_py} ]]; then key=$($PYTHON "${seahub_secret_keygen}") cat > ${dest_settings_py} <<EOF # -*- coding: utf-8 -*- SECRET_KEY = "$key" SERVICE_URL = "http://$ip_or_domain" EOF fi # ------------------------------------------- # Seahub related config # ------------------------------------------- if [[ "${need_pause}" == "1" ]]; then echo "-----------------------------------------------------------------" echo "Seahub is the web interface for seafile server." echo "Now let's setup seahub configuration. Press [ENTER] to continue" echo "-----------------------------------------------------------------" echo read dummy fi # echo "Please specify the email address and password for the seahub administrator." # echo "You can use them to login as admin on your seahub website." # echo function get_seahub_admin_email () { question="Please specify the email address for the seahub administrator:" ask_question "${question}" "nodefault" "seahub admin email" read seahub_admin_email if [[ "${seahub_admin_email}" == "" ]]; then echo "Seahub admin user name cannot be empty." get_seahub_admin_email; elif [[ ! ${seahub_admin_email} =~ ^.+@.*\..+$ ]]; then echo "${seahub_admin_email} is not a valid email address" get_seahub_admin_email; fi } function get_seahub_admin_passwd () { echo question="Please specify the password you would like to use for seahub administrator:" ask_question "${question}" "nodefault" "seahub admin password" read -s seahub_admin_passwd echo question="Please enter the password again:" ask_question "${question}" "nodefault" "seahub admin password again" read -s seahub_admin_passwd_again echo if [[ "${seahub_admin_passwd}" != "${seahub_admin_passwd_again}" ]]; then printf "\033[33mThe passwords didn't match.\033[m" get_seahub_admin_passwd; elif [[ "${seahub_admin_passwd}" == "" ]]; then echo "Password cannot be empty." get_seahub_admin_passwd; fi } # get_seahub_admin_email; # sleep .5; # get_seahub_admin_passwd; # seahub_admin_passwd_enc=$(echo -n ${seahub_admin_passwd} | sha1sum | grep -o "[0-9a-f]*") # sleep .5; # printf "\n\n" # echo "This is your seahub admin username/password" # echo # printf "admin username: \033[33m${seahub_admin_email}\033[m\n" # printf "admin password: \033[33m**************\033[m\n\n" # echo # echo "If you are OK with the configuration, press [ENTER] to continue." # read dummy # usermgr_db_dir=${default_ccnet_conf_dir}/PeerMgr/ # usermgr_db=${usermgr_db_dir}/usermgr.db # if [[ "${use_existing_ccnet}" != "true" ]]; then # # create admin user/passwd entry in ccnet db # if ! mkdir -p "${usermgr_db_dir}"; then # echo "Failed to create seahub admin." # err_and_quit; # fi # sql="CREATE TABLE IF NOT EXISTS EmailUser (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, email TEXT, passwd TEXT, is_staff bool NOT NULL, is_active bool NOT NULL, ctime INTEGER)"; # if ! sqlite3 "${usermgr_db}" "${sql}" ; then # rm -f "${usermgr_db}" # echo "Failed to create seahub admin." # err_and_quit; # fi # sql="INSERT INTO EmailUser(email, passwd, is_staff, is_active, ctime) VALUES (\"${seahub_admin_email}\", \"${seahub_admin_passwd_enc}\", 1, 1, 0);" # if ! sqlite3 "${usermgr_db}" "${sql}" ; then # rm -f "${usermgr_db}" # echo "Failed to create seahub admin." # err_and_quit; # fi # fi echo "Creating database now, it may take one minute, please wait... " echo cd ${TOPDIR}/ccnet && mkdir -m 0755 GroupMgr misc OrgMgr PeerMgr && cd - ccnet_group_db=${TOPDIR}/ccnet/GroupMgr/groupmgr.db ccnet_group_sql=${INSTALLPATH}/sql/sqlite/groupmgr.sql if ! sqlite3 ${ccnet_group_db} ".read ${ccnet_group_sql}" 2>/dev/null 1>&2; then echo "Failed to sync ccnet groupmgr database." err_and_quit; fi ccnet_config_db=${TOPDIR}/ccnet/misc/config.db ccnet_config_sql=${INSTALLPATH}/sql/sqlite/config.sql if ! sqlite3 ${ccnet_config_db} ".read ${ccnet_config_sql}" 2>/dev/null 1>&2; then echo "Failed to sync ccnet config database." err_and_quit; fi ccnet_org_db=${TOPDIR}/ccnet/OrgMgr/orgmgr.db ccnet_org_sql=${INSTALLPATH}/sql/sqlite/org.sql if ! sqlite3 ${ccnet_org_db} ".read ${ccnet_org_sql}" 2>/dev/null 1>&2; then echo "Failed to sync ccnet org database." err_and_quit; fi ccnet_user_db=${TOPDIR}/ccnet/PeerMgr/usermgr.db ccnet_user_sql=${INSTALLPATH}/sql/sqlite/user.sql if ! sqlite3 ${ccnet_user_db} ".read ${ccnet_user_sql}" 2>/dev/null 1>&2; then echo "Failed to sync ccnet user database." err_and_quit; fi seafile_db=${TOPDIR}/seafile-data/seafile.db seafile_sql=${INSTALLPATH}/sql/sqlite/seafile.sql if ! sqlite3 ${seafile_db} ".read ${seafile_sql}" 2>/dev/null 1>&2; then echo "Failed to sync seafile database." err_and_quit; fi seahub_db=${TOPDIR}/seahub.db seahub_sqls=${INSTALLPATH}/seahub/sql/sqlite3.sql if ! sqlite3 ${seahub_db} ".read ${seahub_sqls}" 2>/dev/null 1>&2; then echo "Failed to sync seahub database." err_and_quit; fi echo echo "Done." # prepare avatar folder media_dir=${INSTALLPATH}/seahub/media orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars dest_avatar_dir=${TOPDIR}/seahub-data/avatars if [[ ! -d ${dest_avatar_dir} ]]; then mkdir -p "${TOPDIR}/seahub-data" mv "${orig_avatar_dir}" "${dest_avatar_dir}" ln -s ../../../seahub-data/avatars ${media_dir} fi # Make a seafile-server symlink, like this: # /data/haiwen/ # -- seafile-server-2.0.4 # -- seafile-server-latest # symlink to 2.0.4 seafile_server_symlink=${TOPDIR}/seafile-server-latest echo echo -n "creating seafile-server-latest symbolic link ... " if ! ln -s $(basename ${INSTALLPATH}) ${seafile_server_symlink}; then echo echo echo "Failed to create symbolic link ${seafile_server_symlink}" err_and_quit; fi echo "done" echo chmod 0600 "$dest_settings_py" chmod 0700 "$default_ccnet_conf_dir" chmod 0700 "$default_seafile_data_dir" chmod 0700 "$default_conf_dir" if [[ -d ${INSTALLPATH}/pro ]]; then pro_py=${INSTALLPATH}/pro/pro.py $PYTHON ${pro_py} setup fi # ------------------------------------------- # copy user manuals to library template # ------------------------------------------- copy_user_manuals; # ------------------------------------------- # final message # ------------------------------------------- sleep 1 echo echo "-----------------------------------------------------------------" echo "Your seafile server configuration has been completed successfully." echo "-----------------------------------------------------------------" echo echo "run seafile server: ./seafile.sh { start | stop | restart }" echo "run seahub server: ./seahub.sh { start <port> | stop | restart <port> }" echo echo "-----------------------------------------------------------------" echo "If the server is behind a firewall, remember to open these tcp ports:" echo "-----------------------------------------------------------------" echo echo "port of seafile fileserver: ${fileserver_port}" echo "port of seahub: 8000" echo echo -e "When problems occur, refer to\n" echo -e " ${server_manual_http}\n" echo "for more information." echo