Project

General

Profile

HowToInstallRedmineOnUbuntuServer » History » Version 15

Dimitry Profus, 2011-11-05 02:38

1 1 Dimitry Profus
h1. HowTo Install Redmine 1.2.x with Mercurial and Subversion on Ubuntu Server 10.04
2
3
{{toc}}
4
5 2 Dimitry Profus
h2. Pre-install
6
7
# Set the timezone
8
<pre>
9
$ dpkg-reconfigure tzdata
10
11 11 Dimitry Profus
Select your timezone and exit.
12 2 Dimitry Profus
</pre>
13
# Set your hostname
14
<pre>
15 15 Dimitry Profus
$ sudo nano /etc/hostname
16 2 Dimitry Profus
17 5 Dimitry Profus
Enter your server name and save.
18 3 Dimitry Profus
19
eg.
20
21
redmine
22 2 Dimitry Profus
</pre>
23
# Map your fully qualified domain name (FQDN) to localhost
24
<pre>
25
$ sudo nano /etc/hosts
26
27
Add a line mapping local host to your FQDN and hostname and save. 
28
29
eg. 
30
31
127.0.0.1 redmine.domain.com redmine
32
</pre>
33
34 1 Dimitry Profus
h2. Redmine Installation
35
36
# Install the LAMP stack
37
<pre>
38
$ sudo tasksel install lamp-server
39
</pre>
40
# Install the required packages
41
<pre>
42 14 Joe Zhou
$ sudo apt-get install build-essential subversion libmysqlclient15-dev libdigest-sha1-perl libgemplugin-ruby libgemplugin-ruby1.8 libruby-extras libruby1.8-extras rails rake ruby rubygems rubygems1.8 ruby1.8-dev libopenssl-ruby1.8 
43 1 Dimitry Profus
</pre>
44
# Install the required Ruby gems
45
<pre>
46
$ sudo gem install rails -v=2.3.11 --no-ri --no-rdoc
47
$ sudo gem install rake -v=0.8.7 --no-ri --no-rdoc
48
$ sudo gem uninstall rake -v=0.9.2 
49
$ sudo gem install i18n -v=0.4.2 --no-ri --no-rdoc
50
$ sudo gem install mysql --no-ri --no-rdoc
51
</pre> 
52
# Download Redmine into /user/share/redmine directory
53
<pre>
54
$ sudo svn co http://redmine.rubyforge.org/svn/branches/1.2-stable /usr/share/redmine
55
</pre>
56
# Create an empty MySQL database and accompanying user named redmine for example.
57
<pre>
58
$ mysql -u root -p
59
(enter the mysql root user password)
60
> create database redmine character set utf8;
61
> create user 'redmine'@'localhost' identified by '[password]';
62
> grant all privileges on redmine.* to 'redmine'@'localhost' identified by '[password]';
63
> exit
64
</pre>
65
# Copy config/database.yml.example to config/database.yml and edit this file in order to configure your database settings for "production" environment.
66
<pre>
67
$ sudo cp /usr/share/redmine/config/database.yml.example /usr/share/redmine/config/database.yml
68
69
$ sudo nano /usr/share/redmine/config/database.yml
70
71
Modify to the following and save (ctrl+x)
72
73
production:
74
  adapter: mysql
75
  socket: /var/run/mysqld/mysqld.sock
76
  database: redmine
77
  host: localhost
78
  username: redmine
79
  password: [password]
80
  encoding: utf8
81
</pre>
82
# Generate a session store secret.
83
<pre>
84
$ cd /usr/share/redmine
85
86
$ sudo rake generate_session_store
87
</pre>
88
# Create the database structure, by running the following command under the application root directory:
89
<pre>
90
$ cd /usr/share/redmine
91
92
$ sudo rake db:migrate RAILS_ENV="production" 
93
</pre>
94
# Insert default configuration data in database, by running the following command:
95
<pre>
96
$ sudo RAILS_ENV=production rake redmine:load_default_data
97
</pre>
98
# Setting up permissions
99
<pre>
100
$ cd /usr/share/redmine
101 8 Dimitry Profus
$ sudo chown -R www-data:www-data files log tmp public/plugin_assets
102 1 Dimitry Profus
</pre>
103
# Test using the webrick web server
104
<pre>
105
$ cd /usr/share/redmine
106
107
$ ruby script/server webrick -e production
108
109
Point your web browser at http://[my server ip]:3000
110
111
You should now see the application welcome page.
112
</pre>
113
114
115
h2. Apache Integration
116
117
# Install the required packages
118
<pre>
119
$ sudo apt-get install libapache2-mod-passenger
120
</pre>
121
# Add a symbolic link to the public redmine web directory
122
<pre>
123
$ sudo ln -s /usr/share/redmine/public /var/www/redmine
124
</pre>
125
# Configure Passanger to run as www-data
126
<pre>
127
$ sudo nano /etc/apache2/mods-available/passenger.conf
128
129
Add the follow line and save (ctrl+x)
130
131
PassengerDefaultUser www-data
132
</pre>
133
# Create a new Apache site file
134
<pre> 
135
$ sudo nano /etc/apache2/sites-available/redmine 
136
</pre>
137
Add the following lines and save (ctrl+x)
138
<pre>
139
<VirtualHost *:80>
140
        ServerAdmin webmaster@localhost
141
        DocumentRoot /var/www
142
        ServerName myservername
143
        
144
        RewriteEngine on
145
        RewriteRule   ^/$  /redmine  [R]
146
147
        <Directory /var/www/redmine>
148
                RailsBaseURI /redmine
149
                PassengerResolveSymlinksInDocumentRoot on
150
        </Directory>
151
152
        ErrorLog /var/log/apache2/error.log
153
154
        # Possible values include: debug, info, notice, warn, error, crit,
155
        # alert, emerg.
156
        LogLevel warn
157
158
        CustomLog /var/log/apache2/access.log combined
159
</VirtualHost>
160
</pre>
161
For SSL add the following text instead
162
<pre>
163
<VirtualHost *:443>
164
        ServerAdmin webmaster@localhost
165
        DocumentRoot /var/www
166
        ServerName myservername
167
168
        SSLEngine On
169
        SSLCertificateFile /etc/apache2/ssl/redmine.pem
170
171
        RewriteEngine on
172
        RewriteRule   ^/$  /redmine  [R]
173
174
        <Directory /var/www/redmine>
175
                RailsBaseURI /redmine
176
                PassengerResolveSymlinksInDocumentRoot on
177
        </Directory>
178
179
        ErrorLog /var/log/apache2/error.log
180
181
        # Possible values include: debug, info, notice, warn, error, crit,
182
        # alert, emerg.
183
        LogLevel warn
184
185
        CustomLog /var/log/apache2/access.log combined
186
</VirtualHost>
187
</pre>
188
# Enable the Redmine website
189
<pre>
190
$ sudo a2dissite default
191
$ sudo a2ensite redmine
192
</pre> 
193
# Enable the Passenger and Rewite modules and restart Apache
194
<pre>
195
$ sudo a2enmod passenger
196
$ sudo a2enmod rewrite
197
$ sudo /etc/init.d/apache2 restart
198
</pre> 
199
# Test the setup
200
<pre>
201
Open up your favorite web browser and goto
202
203
http://[my site or ip]/redmine
204
</pre>
205
206
h2. Mercurial Integration
207
208
# Install the latest Mercurial release 
209
<pre>
210
$ sudo apt-get install python-software-properties
211
$ sudo add-apt-repository ppa:mercurial-ppa/releases
212
$ sudo apt-get update
213
$ sudo apt-get install mercurial libapache-dbi-perl libapache2-mod-perl2
214
</pre>
215
# Create the hg web directory
216
<pre>
217
$ sudo mkdir -p /var/hg/repos
218
</pre>
219
# Create the web cgi script file
220
<pre>
221
$ sudo nano /var/hg/hgwebdir.cgi
222
223
Add the following and save
224
225
#!/usr/bin/env python
226
#
227
from mercurial import demandimport; demandimport.enable()
228
from mercurial.hgweb.hgwebdir_mod import hgwebdir
229
import mercurial.hgweb.wsgicgi as wsgicgi
230
application = hgwebdir('hgweb.config')
231
wsgicgi.launch(application)
232
</pre>
233
# Create the cgi web config file 
234
<pre>
235
$ sudo nano /var/hg/hgweb.config
236
237
Add the following and save
238
239
[paths]
240
/=/var/hg/repos/**
241
242
[web]
243
allow_push = *
244
push_ssl = false
245
allowbz2 = yes
246
allowgz = yes
247
allowzip = yes
248
</pre>
249
# Setup permissions
250
<pre>
251
$ sudo chown -R www-data:www-data /var/hg
252
$ sudo chmod gu+x /var/hg/hgwebdir.cgi
253
</pre>
254
# Create a Apache config file
255
<pre>
256
$ sudo nano /etc/apache2/conf.d/hg.config
257
258
Add the following and save
259
 
260
PerlLoadModule Apache::Redmine
261
ScriptAlias /hg  "/var/hg/hgwebdir.cgi"
262
<Location /hg  >
263
	AuthType Basic
264
	AuthName "Redmine Mercurial Repository" 
265
	Require valid-user
266
267
	#Redmine auth
268
	PerlAccessHandler Apache::Authn::Redmine::access_handler
269
	PerlAuthenHandler Apache::Authn::Redmine::authen_handler
270
	RedmineDSN "DBI:mysql:database=redmine;host=localhost" 
271
	RedmineDbUser "redmine" 
272
	RedmineDbPass "password" 
273
</Location>
274
</pre>
275
# Add a symbolic link to Redmine.pm
276
<pre>
277
$ sudo ln -s /usr/share/redmine/extra/svn/Redmine.pm /usr/lib/perl5/Apache/Redmine.pm
278
$ sudo ln -s /usr/share/redmine/extra/svn/Redmine.pm /usr/lib/perl5/Apache2/Redmine.pm  
279
</pre>
280
# Enable the required Apache modules and restart Apache
281
<pre>
282
$ sudo /etc/init.d/apache2 restart
283
</pre>
284
# Create a new test repository and project in Redmine
285
<pre>
286
$ sudo hg init /var/hg/repos/test
287
$ sudo chown -R www-data:www-data /var/hg/repos/test
288
289
Create a new project with and identifier 'test'
290
291
In the project Settings > Repository set
292
SCM: Mercurial
293
Path to repository: /var/hg/repos/test
294
Press the 'Create' button
295
296
Goto to the Repository tab of the test project
297
</pre>
298
# View the test repository in the web browser 
299
<pre>
300
> http://[my site name]/hg/test
301
</pre>
302
303
h2. Subversion Integration
304
305
# Install the latest Mercurial release 
306
<pre>
307
$ sudo apt-get install subversion libapache2-svn libapache-dbi-perl libapache2-mod-perl2
308
</pre>
309
# Create the svn repository directory
310
<pre>
311
$ sudo mkdir /var/svn
312
</pre>
313
# Setup permissions
314
<pre>
315
$ sudo chown -R www-data:www-data /var/svn
316
</pre>
317
# Add a symbolic link to Redmine.pm
318
<pre>
319
$ sudo ln -s /usr/share/redmine/extra/svn/Redmine.pm /usr/lib/perl5/Apache/Redmine.pm
320
$ sudo ln -s /usr/share/redmine/extra/svn/Redmine.pm /usr/lib/perl5/Apache2/Redmine.pm  
321
</pre>
322
# Create a Apache config file
323
<pre>
324
$ sudo nano /etc/apache2/conf.d/svn.config
325
</pre>
326
Add the following and save
327
<pre>
328
PerlLoadModule Apache::Redmine
329
<Location /svn>
330
	DAV svn
331
	SVNParentPath "/var/svn" 
332
	Order deny,allow
333
	Deny from all
334
	Satisfy any
335
336
	PerlAccessHandler Apache::Authn::Redmine::access_handler
337
	PerlAuthenHandler Apache::Authn::Redmine::authen_handler
338
	AuthType Basic
339
	AuthName "Redmine Subversion Repository" 
340
341
	#read-only access    
342
	<Limit GET PROPFIND OPTIONS REPORT>
343
		Require valid-user
344
		Allow from [my server ip]
345
		# Allow from another-ip
346
		 Satisfy any
347
	</Limit>
348
		# write access
349
		<LimitExcept GET PROPFIND OPTIONS REPORT>
350
		Require valid-user
351
	</LimitExcept>
352
353
	## for mysql
354
	RedmineDSN "DBI:mysql:database=redmine;host=localhost" 
355
	RedmineDbUser "redmine" 
356
	RedmineDbPass "password" 
357
</Location>
358
</pre>
359
# Enable the required Apache modules and restart Apache
360
<pre>
361
$ sudo a2enmod dav_svn
362
$ sudo /etc/init.d/apache2 restart
363
</pre>
364
# Create a new test repository
365
<pre>
366
$ sudo svnadmin create /var/svn/test
367
$ sudo chown -R www-data:www-data /var/svn/test
368
</pre>
369
370
h2. Automate Repository Creation
371
372
# Enable WS for repository management and generate and API key
373
<pre>
374
* From the Redmine Administration menu select Settings
375
* Click on the Repositories tab
376
* Enable the 'Enable WS for repository management' checkbox
377
* Click the 'Generate a key' link 
378
* Press the 'Save' button
379
</pre>
380
# Modify reposman.rb
381
<pre>
382
$ sudo nano /usr/share/extra/svn/reposman.rb
383
384
Add the following to module SCM and save  
385
386
  module Mercurial
387
    def self.create(path)
388
      Dir.mkdir path
389
      Dir.chdir(path) do
390
        system_or_raise "hg init"
391
      end
392
    end
393
  end
394
</pre>
395
# Schedule the reposman.rb script to run every minute
396
<pre>
397
$ sudo nano /etc/cron.d/redmine
398
</pre>
399
Add one of the following lines (not both) and save.
400
(Note: you will need to replace [my API key]  with the API key you generated in step 1) 
401
.
402
To create subversion repositories add:
403
<pre>
404
* * * * * root ruby /usr/share/redmine/extra/svn/reposman.rb --redmine localhost/redmine --scm Subversion --svn-dir /var/hg/repos --owner www-data --url file:///var/svn --key=[my API key] >> /var/log/reposman.log
405
</pre>
406
OR to create Mecurial repositories add:
407
<pre>
408
* * * * * root ruby /usr/share/redmine/extra/svn/reposman.rb --redmine localhost/redmine --scm Mercurial --svn-dir /var/hg/repos --owner www-data --url /var/hg/repos --key=[my API key] >> /var/log/reposman.log
409
</pre>
410
411
h2. Automatic refresh of repositories in Redmine
412
413
# Schedule the fetch_changesets script to run every 15 minutes
414
<pre>
415
$ sudo nano /var/cron.d/redmine
416
417
Add the following line and save
418
419
*/15 * * * * root ruby /usr/share/redmine/script/runner "Repository.fetch_changesets" -e production > /dev/null 2>&1
420
</pre>
421
# Setup a changegroup script on the Mercurial server to run fetch_changesets after each push to a Mercurial repository 
422
<pre>
423
$ sudo nano /var/hg/changegroup-hook
424
</pre>
425
Add the following text and save
426
(Note: you will need to replace [your API key] the API key you generated in Redmine
427
<pre>
428
#!/bin/sh
429
curl "http://localhost/redmine/sys/fetch_changesets?key=[your API key]"  > /dev/null 2>&1
430
</pre>
431
Setup permissions
432
<pre>
433
$ sudo chown www-data:www-data /var/hg/changegroup-hook
434
$ sudo chmod ug+x /var/hg/changegroup-hook
435
</pre>
436
Modify the hgweb.config file
437
<pre>
438
$ sudo nano /var/hg/hgweb.config
439
</pre>
440
Add the following section and save
441
<pre>
442
[hooks]
443
changegroup = /var/hg/changegroup-hook
444
</pre>
445
446
h2. Email Integration
447
448
# Install and configure Sendmail
449
<pre>
450
$ sudo apt-get install sendmail
451
$ sudo sendmailconfig
452
453
(Answer Yes to all questions which you will be asked)
454
</pre>
455
# Update the Redmine configuration file
456
<pre>
457
$ sudo nano /usr/share/redmine/config/configuration.yml
458
459
Add the following text and save
460
461
 production:
462
   email_delivery:
463
     delivery_method: :sendmail
464
</pre>
465
466
h2. Backup to Amazon S3 cloud storage
467
468
# Create an account at http://aws.amazon.com/ 
469
# Create a S3 bucket using the aws management console https://console.aws.amazon.com/ec2/home
470
# View your Access Keys at https://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key
471
# Build and install fuse to 2.8.4
472
<pre>
473
$ sudo wget https://launchpad.net/ubuntu/+archive/primary/+files/fuse_2.8.4.orig.tar.gz
474
$ cd fuse-2.8.4/
475
$ tar xzf fuse_2.8.4.orig.tar.gz 
476
$ sudo ./configure 
477
$ sudo make
478
$ sudo make install
479
</pre>
480
# Build and install s3fs 1.61 
481
<pre>
482
$ sudo apt-get install libxml2-dev
483
$ wget http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz
484
$ tar xzf s3fs-1.61.tar.gz 
485
$ cd s3fs-1.61/
486
$ sudo ./configure 
487
$ sudo make
488
$ sudo make install
489
</pre>
490
# Create a s3fs password file
491
<pre>
492
$ sudo nano /etc/passwd-s3fs
493
</pre>
494
Added your 'Access Key ID' and 'Secret Access Key' separated by a colon
495
<pre>
496
[accessKeyId]:[secretAccessKey]
497
</pre>
498
Setup permissions
499
<pre>
500 6 Dimitry Profus
sudo chmod 640 /etc/passwd-s3fs
501 1 Dimitry Profus
</pre> 
502
# Create mounting point
503
<pre>
504
$ sudo mkdir /mnt/s3
505
</pre>
506
# Mount your S3 bucket
507
<pre>
508
$ sudo s3fs [your-s3-bucket-name] /mnt/s3 -ouse_cache=/tmp -o allow_other
509
</pre>
510
# Test it worked and unmount
511
<pre>
512
$ echo hello > /mnt/s3/welcome.txt
513
$ ls /mnt/s3
514
$ sudo umount /mnt/s3
515
</pre>
516
# Create upstart job to mount the s3 file system start up
517
<pre>
518
$ sudo nano /etc/init/s3.conf
519
</pre>
520
Add the following text and save.
521
<pre>
522
description "Mount Amazon S3 file system on system start"
523
524
start on (local-filesystems and net-device-up IFACE!=lo)
525
stop on runlevel [016]
526
527
respawn
528
529
exec s3fs -f [your-s3-bucket-name] /mnt/s3 -ouse_cache=/tmp -o allow_other
530
</pre>
531
# Start the s3 job
532
<pre>
533
sudo start s3
534
</pre>
535
# Test it worked
536
<pre>
537
$ echo hello > /mnt/s3/welcome2.txt
538
$ ls /mnt/s3
539
</pre>
540
# Create the backup script file
541
<pre>
542
$ sudo apt-get install mailutils
543
$ sudo nano /usr/local/bin/backup-redmine.sh
544
</pre>
545
Add the following text and save.
546
<pre>
547 13 Dimitry Profus
#!/bin/bash
548 1 Dimitry Profus
# Script to backup Redmine files to a mounted storage device
549
# with daily, weekly, monthly backup rotation
550
551 12 Dimitry Profus
# Sysadmin email address
552
sysadmin_email="admin@domain.com"
553 1 Dimitry Profus
554
# What to backup
555 12 Dimitry Profus
db_dump_file="/usr/share/redmine/db/redmine-database-dump.sql"
556 1 Dimitry Profus
557 13 Dimitry Profus
backup_files="$db_dump_file /usr/share/redmine/files /var/hg /var/svn /etc/apache2/conf.d/hg.conf"
558 12 Dimitry Profus
backup_files="$backup_files /etc/apache2/sites-available/redmine /etc/init/s3.conf /etc/cron.d/redmine"
559
backup_files="$backup_files /usr/local/bin/backup-redmine.sh"
560
561 1 Dimitry Profus
# Where to backup to
562 12 Dimitry Profus
backup_dir="/mnt/s3"
563 1 Dimitry Profus
564
# Set database access
565 12 Dimitry Profus
redmine_db_name="redmine"
566
redmine_db_user="redmine"
567
redmine_db_password="password"
568 1 Dimitry Profus
569
# Encryption
570 12 Dimitry Profus
encrypt="true"
571 13 Dimitry Profus
secret_passphrase="password"
572 1 Dimitry Profus
573 12 Dimitry Profus
# Set rotation schedule in units of days ( 0 = disabled )
574 1 Dimitry Profus
daily_remove_older_than=6
575 12 Dimitry Profus
weekly_remove_older_than=31
576 1 Dimitry Profus
monthly_remove_older_than=62
577
578
# Redirect stderr to a log file
579 12 Dimitry Profus
error_log="/tmp/backup-redmine.log"
580 1 Dimitry Profus
exec 6>&2
581
exec 2>$error_log
582
583
on_exit() {
584
    # Restore IO output
585
    exec 2>&6  6>$-
586
587
    # Check for errors
588
    if [ -s "$error_log" ]; then
589 12 Dimitry Profus
        logger -t "$0" -s "#### Backup Failed ####"
590
        logger -t "$0" -s -f "$error_log"
591
        cat "$error_log" | mail -s "Backup failed!"  $sysadmin_email
592 1 Dimitry Profus
     else
593 12 Dimitry Profus
        logger -t "$0" -s "Backup Complete"
594 1 Dimitry Profus
    fi
595
596
    # Clean up
597
    rm -f $error_log
598
}
599
600
trap on_exit EXIT SIGHUP SIGINT SIGQUIT SIGTERM
601
602
# Setup variables for the archive filename.
603
hostname=$(hostname -s)
604
date_stamp=`date +%Y-%m-%d`                    # Date p e.g 2011-12-31
605
date_day_of_week=`date +%A`                    # Day of the week e.g. Monday
606
date_day_of_month=`date +%e`                   # Date of the Month e.g. 27
607
608
# Is the  backup directory mounted?
609
mount | grep -sq "$backup_dir"
610
if  [ $? != 0 ]; then
611
   echo "backup destination ${backup_dir} is not mounted" >&2
612
  exit 1
613 12 Dimitry Profus
fi
614 1 Dimitry Profus
615 12 Dimitry Profus
# Delete old archives
616 13 Dimitry Profus
find "${backup_dir}" -mtime +"$monthly_remove_older_than" -type f -name "${hostname}_fullbackup_monthly*" -exec rm {} \;
617
find "${backup_dir}" -mtime +"$weekly_remove_older_than" -type f -name "${hostname}_fullbackup_weekly*" -exec rm {} \;
618
find "${backup_dir}" -mtime +"$daily_remove_older_than" -type f -name "${hostname}_fullbackup_daily*" -exec rm {} \;
619 1 Dimitry Profus
620 12 Dimitry Profus
# Determine the backup schedule
621 1 Dimitry Profus
if [[ $monthly_remove_older_than -gt "0" && $date_day_of_month == "1" ]]; then
622 12 Dimitry Profus
    schedule="monthly"
623
elif [[ $weekly_remove_older_than -gt "0" && $date_day_of_week == "Saturday" ]]; then
624
    schedule="weekly"
625
elif [[ $daily_remove_older_than -gt "0" ]]; then
626
    schedule="daily"
627
else
628 1 Dimitry Profus
    echo "Invalid backup rotation schedule" >&2
629 12 Dimitry Profus
    exit 1
630 1 Dimitry Profus
fi
631 12 Dimitry Profus
632 13 Dimitry Profus
archive_file="${backup_dir}/${hostname}_fullbackup_${schedule}_${date_stamp}.tgz"
633 12 Dimitry Profus
634 1 Dimitry Profus
# Dump the redmine database
635 12 Dimitry Profus
rm -f "${db_dump_file}"
636 1 Dimitry Profus
mysqldump --user="${redmine_db_name}" --password="${redmine_db_password}" "${redmine_db_name}" > $db_dump_file
637
638
# Write the archive file to the backup directory
639
if [ $encrypt == "true" ]; then
640 13 Dimitry Profus
    tar czP ${backup_files} | gpg -c -z 0 --yes --no-use-agent --passphrase="${secret_passphrase}" -o "${archive_file}.gpg"
641 1 Dimitry Profus
else
642 13 Dimitry Profus
    tar czfP "${archive_file}" ${backup_files}
643 1 Dimitry Profus
fi
644
645
if [ -s "$error_log" ]; then
646
    exit 1
647
else
648
    exit 0
649
fi
650
</pre>
651
# Setup permissions 
652
<pre>
653 6 Dimitry Profus
sudo chmod 770 /usr/local/bin/backup-redmine.sh
654 1 Dimitry Profus
</pre>
655
# Schedule the backup to run once a day at 12am
656
<pre>
657
$ sudo nano /etc/cron.d/redmine
658
659
Add the following line and save
660
661
0 0 * * * root /usr/local/bin/backup-redmine.sh
662
</pre>
663
# Test the script
664
<pre>
665
$ sudo backup-redmine.sh
666
$ ls -R /mnt/s3
667
</pre>