Hello, This is a new year gift for the one who would use Redmine beside web2py...
:) The script is largely base on new Niphold web2py nginx deployment script ( https://groups.google.com/forum/?fromgroups=#!searchin/web2py/nginx$20niphold/web2py/15J3T35_K_w/v_t1099dIf4J ). I spend many hours write it, test it and debug Redmine, so I copyright it and distribute it under CC without commercial use. Executing it in a fresh Ubuntu 12.04 server you will get : - Latest Redmine stable (2.2.0 from http://rubyforge.org), - Rails (3.2.9 from GEM) - Ruby (ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]) (Ubuntu ruby-dev package that should correspond to the latest stable Ruby) - working with Unicorn (latest stable from GEM), - web2py (latest stable) - uWSGI (I think latest stable), start in Emperor mode - Nginx (Ubuntu default) - PostgreSQL (Ubuntu default) - Redmine database will be installed in PostgreSQL - Self Signed SSL Certificat I try to make the script asking all the question at the beginning of the installation process just after launch it, but there is a confirmation asked during execution where you have to choose which language to use for the Redmine default values. Just hit enter you will get English Redmine default values. At the end of the execution, you should access your sever like this : http://IPADSRESS/ # web2py Welcome should appear http://IPADSRESS/redmine # Redmine! Please report issue, submit improvement or post any comment here, and I will be glad to improve the script. Happy new year to all! Richard --
#!/bin/bash # ------------------------------------------------------------------------------ # Description : Installation and basic configuration of web2py, uWSGI, Redmine, # Unicorn, Nginx and PostgreSQL. # Usage : Copy the script in /home/username and run it as root, you may # need to allow exectuion (chmod +x). Ex.: # sudo ./setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh # File : setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh # Author : Richard V?zina # Email : [email protected] # Copyright : Richard V?zina # Date : ven 28 d?c 2012 13:27:11 EST # Disclaimers : This script is provided "as is", without warranty of any kind. # Licence : CC BY-NC 2.5 CA # ------------------------------------------------------------------------------ echo 'setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh' echo 'Requires Ubuntu = 12.04 (May works with 12.10 not tested) and installs Redmine + Unicorn + Web2py + uWSGI + Nginx + PostgreSQL' # Check if user has root privileges if [[ $EUID -ne 0 ]]; then echo "You must run the script as root or using sudo" exit 1 fi # ------------------------------------------------------------------------------ # We concentrate here user prompts!! # Get Redmine Postgres Database Password echo -e "Redmine Postgres Database Password: \c " read REDMINEPASSWORD # Get Web2py Admin Password echo -e "Web2py Admin Password: \c " read PW cd ~ openssl genrsa 1024 > self_signed.key chmod 400 self_signed.key openssl req -new -x509 -nodes -sha1 -days 1780 -key self_signed.key > self_signed.cert openssl x509 -noout -fingerprint -text < self_signed.cert > self_signed.info # ------------------------------------------------------------------------------ apt-get update apt-get -y upgrade apt-get autoremove apt-get autoclean apt-get -y install postgresql apt-get -y install nginx-full apt-get -y install build-essential python-dev libxml2-dev python-pip unzip apt-get -y install ruby1.9.3 # Ref.: http://askubuntu.com/questions/137485/rails-3-not-using-rvm apt-get -y install libpq-dev # Required for gem1.9.3 install pg Ref.: http://stackoverflow.com/questions/6040583/unable-to-install-pg-gem-on-ubuntu-cant-find-the-libpq-fe-h-header gem1.9.3 install rails --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri gem1.9.3 install unicorn --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri gem1.9.3 install pg --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri cd /opt wget http://rubyforge.org/frs/download.php/76627/redmine-2.2.0.tar.gz wget http://rubyforge.org/frs/download.php/76628/redmine-2.2.0.tar.gz.md5 md5sum --check redmine-2.2.0.tar.gz.md5 > redmine_md5_checked_successfully if [ -f redmine_md5_checked_successfully ] then tar xvfz redmine-2.2.0.tar.gz rm redmine_md5_checked_successfully else echo "Redmine md5 check sum failed..." exit 1 fi cd redmine-2.2.0 bundle install --without development test rmagick sqlite mysql mkdir /var/www ln -s /opt/redmine-2.2.0/public /var/www/redmine chown -R www-data.www-data /var/www chown -R www-data.www-data /opt/redmine-2.2.0/public # To avoid prompt during execution of the script use psql instead of createuser #echo "Enter a postgres redmine user password twice:" #createuser -P -S -D -R -l -e redmine # createuser switch: -P --pwprompt -S --no-superuser -D --no-createdb -R --no-createrole -l --login -e --echo sudo -u postgres psql -c "CREATE ROLE redmine LOGIN; ALTER ROLE redmine WITH ENCRYPTED PASSWORD '$REDMINEPASSWORD';" # createdb wouldn't work without having root password #createdb -U postgres -w -E UTF8 -O redmine -e redmine # createdb switch: -U username --username=username -w --no-password -E Encoding -O owner --owner=owner -e --echo sudo -u postgres psql -c "CREATE DATABASE redmine WITH ENCODING='UTF8' OWNER=redmine;" cd /opt/redmine-2.2.0/config # Here we change related to an issue with new rails version as far as I understand # Ref1.: http://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_in_a_sub-URI # Preferred solution used # Ref2.: http://www.redmine.org/issues/12102 # JS and CSS was not working until I add this line 'RedmineApp::Application.routes.default_scope = { :path => "/redmine", :shallow_path => "/redmine" }' before 'RedmineApp::Application.initialize!' cp environment.rb environment.rb_original # Backup default environment.rb sed '/RedmineApp::Application.initialize!/c \RedmineApp::Application.routes.default_scope = { :path => "/redmine", :shallow_path => "/redmine" }\nRedmineApp::Application.initialize!\nRedmine::Utils::relative_url_root = "/redmine"' environment.rb_original > environment.rb # Now we configure Redmine database access #nano database.yml # paste : echo 'production: adapter: postgresql database: redmine host: localhost username: redmine password: "'$REDMINEPASSWORD'" encoding: utf8' > database.yml rake generate_secret_token RAILS_ENV=production rake db:migrate RAILS_ENV=production rake redmine:load_default_data mkdir /opt/redmine-2.2.0/tmp/pids #mkdir /opt/redmine-2.2.0/log # if not there cd /opt/redmine-2.2.0/config # Create Unicorn specific Redmine config in /opt/redmine-2.2.0/config/unicorn.rb echo '#unicorn.rb Starts here worker_processes 1 working_directory "/opt/redmine-2.2.0" # needs to be the correct directory for redmine # This loads the application in the master process before forking # worker processes # Read more about it here: # http://unicorn.bogomips.org/Unicorn/Configurator.html preload_app true timeout 45 # This is where we specify the socket. # We will point the upstream Nginx module to this socket later on listen "/tmp/unicorn_rails.socket", :backlog => 64 #directory structure needs to be created. pid "/opt/redmine-2.2.0/tmp/pids/unicorn_rails.pid" # make sure this points to a valid directory. Make sure it is named the same as the real process name in order to allow init.d script start-stop-daemon command to kill unicorn process properly # Set the path of the log files inside the log folder of the testapp stderr_path "/opt/redmine-2.2.0/log/unicorn_rails.stderr.log" stdout_path "/opt/redmine-2.2.0/log/unicorn_rails.stdout.log" before_fork do |server, worker| # This option works in together with preload_app true setting # What is does is prevent the master process from holding # the database connection defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! end after_fork do |server, worker| # Here we are establishing the connection after forking worker # processes defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection # change below if your redmine instance is running differently worker.user('\''www-data'\'', '\''www-data'\'') if Process.euid == 0 end #unicorn.rb Ends here' > unicorn.rb chown www-data:www-data unicorn.rb chown -R www-data:www-data /opt/redmine-2.2.0/tmp mkdir /etc/unicorn # Set some config for Unicorn in /etc/unicorn/redmine echo 'RAILS_ROOT=/opt/redmine-2 RAILS_ENV=production' > /etc/unicorn/redmine # Create a Unicorn Redmine start script in /etc/init.d/redmine echo '#! /bin/sh ### BEGIN INIT INFO # Provides: redmine # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: redmine initscript # Description: This script startup unicorn server and redmine and should # be placed in /etc/init.d. ### END INIT INFO # ------------------------------------------------------------------------------ # Author: Richard V?zina <[email protected]> # Base on Ubuntu 12.04 : /etc/init.d/skeleton # ven 21 d?c 2012 11:08:31 EST # ------------------------------------------------------------------------------ # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script APP=/opt/redmine-2.2.0/ PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Unicorn and Redmine" NAME=unicorn_rails DAEMON=/usr/local/bin/$NAME DAEMON_ARGS=" -E production -c $APP/config/unicorn.rb -D" PIDFILE=/opt/redmine-2.2.0/tmp/pids/$NAME.pid SCRIPTNAME=/etc/init.d/redmine # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # 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 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # 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 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don'\''t delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 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" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave '\''force-reload'\'' as an alias for '\''restart'\''. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # '\''force-reload'\'' alias # log_daemon_msg "Restarting $DESC" "$NAME" 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|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac :' > /etc/init.d/redmine chmod +x /etc/init.d/redmine # Backup default Nginx site and replace it cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default_original rm /etc/nginx/sites-available/default # Create configuration file /etc/nginx/sites-available/default echo 'upstream unicorn_server { # This is the socket we configured in unicorn.rb server unix:/tmp/unicorn_rails.socket fail_timeout=0; } server { listen 80; #return 301 https://192.168.1.126$request_uri; # http://$hostname$request_uri; # idem #http://wiki.nginx.org/Pitfalls#Taxing_Rewrites charset utf-8; server_name localhost; # $hostname; root /var/www; access_log /var/log/nginx/yoursite.access.log; error_log /var/log/nginx/yoursite.error.log; #to enable correct use of response.static_version #location ~* /(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$ { # alias /home/www-data/web2py/applications/$1/static/$2; # expires max; #} location ~* /(\w+)/static/ { root /home/www-data/web2py/applications/; #remove next comment on production #expires max; } location ~^\/(?!redmine(.*)) { #uwsgi_pass 127.0.0.1:9001; uwsgi_pass unix:///tmp/web2py.socket; include uwsgi_params; uwsgi_param UWSGI_SCHEME $scheme; uwsgi_param SERVER_SOFTWARE nginx/$nginx_version; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; if (!-f $request_filename) { proxy_pass http://unicorn_server; break; } } } server { listen 443 default_server ssl; charset utf-8; server_name localhost; # $hostname; root /var/www; ssl_certificate /etc/nginx/ssl/self_signed.cert; ssl_certificate_key /etc/nginx/ssl/self_signed.key; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_ciphers ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA; ssl_protocols SSLv3 TLSv1; keepalive_timeout 70; location ~^\/(?!redmine(.*)) { #uwsgi_pass 127.0.0.1:9001; uwsgi_pass unix:///tmp/web2py.socket; include uwsgi_params; uwsgi_param UWSGI_SCHEME $scheme; uwsgi_param SERVER_SOFTWARE nginx/$nginx_version; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; if (!-f $request_filename) { proxy_pass http://unicorn_server; break; } } }' >/etc/nginx/sites-available/default #ln -s /etc/nginx/sites-available/web2py /etc/nginx/sites-enabled/web2py #rm /etc/nginx/sites-enabled/default # We copy ssl files we previously created if [ -f /etc/nginx/ssl ] then cp ~/self_signed.* /etc/nginx/ssl/ rm ~/self_signed.* else mkdir /etc/nginx/ssl cp ~/self_signed.* /etc/nginx/ssl/ rm ~/self_signed.* fi pip install --upgrade pip PIPPATH=`which pip` $PIPPATH install --upgrade uwsgi # Prepare folders for uwsgi sudo mkdir /etc/uwsgi sudo mkdir /var/log/uwsgi # Create configuration file /etc/uwsgi/web2py.xml echo '<uwsgi> <socket>/tmp/web2py.socket</socket> <pythonpath>/home/www-data/web2py/</pythonpath> <mount>/=wsgihandler:application</mount> <master/> <processes>4</processes> <harakiri>60</harakiri> <reload-mercy>8</reload-mercy> <cpu-affinity>1</cpu-affinity> <stats>/tmp/stats.socket</stats> <max-requests>2000</max-requests> <limit-as>512</limit-as> <reload-on-as>256</reload-on-as> <reload-on-rss>192</reload-on-rss> <uid>www-data</uid> <gid>www-data</gid> <cron>0 0 -1 -1 -1 python /home/www-data/web2py/web2py.py -Q -S welcome -M -R scripts/sessions2trash.py -A -o</cron> <no-orphans/> </uwsgi>' > /etc/uwsgi/web2py.xml #Create a configuration file for uwsgi in emperor-mode #for Upstart in /etc/init/uwsgi-emperor.conf echo '# Emperor uWSGI script description "uWSGI Emperor" start on runlevel [2345] stop on runlevel [06] ## #remove the comments in the next section to enable static file compression for the welcome app #in that case, turn on gzip_static on; on /etc/nginx/nginx.conf ## #pre-start script # python /home/www-data/web2py/web2py.py -S welcome -R scripts/zip_static_files.py # chown -R www-data:www-data /home/www-data/web2py/* #end script respawn exec uwsgi --master --die-on-term --emperor /etc/uwsgi --logto /var/log/uwsgi/uwsgi.log ' > /etc/init/uwsgi-emperor.conf # Install Web2py mkdir /home/www-data cd /home/www-data wget http://web2py.com/examples/static/web2py_src.zip unzip web2py_src.zip rm web2py_src.zip # Download latest version of sessions2trash.py wget http://web2py.googlecode.com/hg/scripts/sessions2trash.py -O /home/www-data/web2py/scripts/sessions2trash.py chown -R www-data:www-data web2py cd /home/www-data/web2py sudo -u www-data python -c "from gluon.main import save_password; save_password('$PW',443)" /etc/init.d/redmine start start uwsgi-emperor /etc/init.d/nginx restart ufw allow 80 # Or check your firewall configuration

