Redmine is an open source project management and issue tracking application built on Ruby on Rails, with per-project trackers, wikis, time tracking and Gantt charts. In this tutorial you will install Redmine 6 on Ubuntu 24.04 using the distribution's Ruby 3.2 and MySQL 8, run it under Puma as a systemd service, publish it through Nginx with a Let's Encrypt certificate, and configure email and backups.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 2 GB of RAM (4 GB if the same server runs other applications).
- A non-root user with
sudoprivileges. - A domain or subdomain (this guide uses
your_domain) with a DNSArecord pointing toyour_server_ip. - Ports 80 and 443 open to the internet.
Step 1 - Installing Ruby, MySQL and build dependencies
Redmine 6.0 supports Ruby 3.1 to 3.3, and Ubuntu 24.04 ships Ruby 3.2, so there is no need for a version manager such as RVM. Install Ruby with its development headers, the compiler toolchain needed to build native gems, the MySQL server and client library, ImageMagick for thumbnails, and Nginx:
sudo apt update
sudo apt install ruby-full build-essential libyaml-dev zlib1g-dev libmysqlclient-dev mysql-server imagemagick nginx
Install a current Bundler from RubyGems, since Redmine 6 expects a newer version than the one packaged by Ubuntu:
sudo gem install bundler
Verify the versions:
ruby -v
bundle -v
ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux-gnu]
Bundler version 2.x.x
Open the firewall for SSH and web traffic:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Step 2 - Creating the database
On Ubuntu, the MySQL root account authenticates through the Unix socket, so sudo mysql opens a shell without a password. Run the hardening script first to remove anonymous users and the test database:
sudo mysql_secure_installation
Then open the MySQL shell:
sudo mysql
Create the database and a dedicated user. Replace your_db_password with a strong password:
CREATE DATABASE redmine CHARACTER SET utf8mb4;
CREATE USER 'redmine'@'localhost' IDENTIFIED BY 'your_db_password';
GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Check that the new account works:
mysql -u redmine -p -e 'SHOW DATABASES;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| redmine |
+--------------------+
Step 3 - Downloading Redmine
Redmine will run under its own unprivileged system user, with /opt/redmine as both its home and installation directory:
sudo useradd --system --create-home --home-dir /opt/redmine --shell /usr/sbin/nologin redmine
Download the latest 6.0 release. Check the Redmine download page for the current version number and adjust the commands if a newer point release is available:
cd /tmp
wget https://www.redmine.org/releases/redmine-6.0.4.tar.gz
Extract it directly into /opt/redmine and hand ownership to the redmine user:
sudo tar --no-same-owner -xzf redmine-6.0.4.tar.gz -C /opt/redmine --strip-components=1
sudo chown -R redmine:redmine /opt/redmine
sudo chmod 755 /opt/redmine
The chmod lets your own user enter the directory to run the commands below; useradd creates home directories with mode 750 on Ubuntu 24.04.
Step 4 - Configuring the database connection
Redmine reads its database settings from config/database.yml. Create the file:
sudo -u redmine nano /opt/redmine/config/database.yml
Add the production connection, using the password from Step 2:
production:
adapter: mysql2
database: redmine
host: localhost
username: redmine
password: "your_db_password"
encoding: utf8mb4
variables:
transaction_isolation: "READ-COMMITTED"
The READ-COMMITTED isolation level is the one Redmine recommends for MySQL to avoid deadlocks under concurrent use. Restrict the file, since it contains a password:
sudo chmod 600 /opt/redmine/config/database.yml
Step 5 - Installing gems and initializing Redmine
Puma, the application server you will use, is not part of Redmine's production dependencies. Add it through Gemfile.local, a file Redmine's Gemfile loads automatically:
echo "gem 'puma'" | sudo -u redmine tee /opt/redmine/Gemfile.local
Tell Bundler to install gems inside the application directory and to skip development and test dependencies, then install them. This step compiles native extensions and can take a few minutes:
cd /opt/redmine
sudo -u redmine bundle config set --local path 'vendor/bundle'
sudo -u redmine bundle config set --local without 'development test'
sudo -u redmine bundle install
...
Bundle complete! ... Gemfile dependencies, ... gems now installed.
Gems in the groups 'development' and 'test' were not installed.
Generate the secret used to sign session cookies, create the database schema and load the default roles, trackers and statuses:
sudo -u redmine bundle exec rake generate_secret_token
sudo -u redmine bundle exec rake db:migrate RAILS_ENV=production
sudo -u redmine bundle exec rake redmine:load_default_data RAILS_ENV=production REDMINE_LANG=en
Compile the stylesheets and JavaScript into public/assets:
sudo -u redmine bundle exec rake assets:precompile RAILS_ENV=production
Step 6 - Running Redmine with Puma under systemd
A systemd unit starts Redmine at boot and restarts it if it crashes. Create the unit file:
sudo nano /etc/systemd/system/redmine.service
[Unit]
Description=Redmine (Puma)
After=network.target mysql.service
Wants=mysql.service
[Service]
Type=simple
User=redmine
Group=redmine
WorkingDirectory=/opt/redmine
Environment=RAILS_ENV=production
ExecStart=/usr/local/bin/bundle exec puma -e production -b tcp://127.0.0.1:3000 -w 2 -t 5:5
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Puma listens only on 127.0.0.1:3000, with two worker processes of five threads each; Nginx will be the only public entry point. Start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now redmine
sudo systemctl status redmine --no-pager
● redmine.service - Redmine (Puma)
Loaded: loaded (/etc/systemd/system/redmine.service; enabled; preset: enabled)
Active: active (running) since ...
Check that Redmine answers locally:
curl -sI http://127.0.0.1:3000 | head -n 1
HTTP/1.1 200 OK
If the service fails, read its log with sudo journalctl -u redmine -n 50.
Step 7 - Configuring Nginx and HTTPS
Create an Nginx server block that proxies requests to Puma:
sudo nano /etc/nginx/sites-available/redmine
server {
listen 80;
listen [::]:80;
server_name your_domain;
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Enable it, remove the default site and test the configuration:
sudo ln -s /etc/nginx/sites-available/redmine /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Request a certificate with Certbot. The Nginx plugin adds the HTTPS listener and an HTTP to HTTPS redirect to the server block:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain
Confirm automatic renewal works:
sudo certbot renew --dry-run
Open https://your_domain and sign in with the default account admin / admin. Set a strong password straight away (Redmine prompts you, or use My account). Then go to Administration > Settings > General and set Host name and path to your_domain and Protocol to HTTPS, so links in emails point to the right address.
Step 8 - Configuring outgoing email
Redmine sends notifications for new issues, updates and password resets. Create the configuration file from the shipped example:
sudo -u redmine cp /opt/redmine/config/configuration.yml.example /opt/redmine/config/configuration.yml
sudo -u redmine nano /opt/redmine/config/configuration.yml
Find the production: section at the end of the file (or add it) and set your SMTP provider's details:
production:
email_delivery:
delivery_method: :smtp
smtp_settings:
address: "smtp.your_provider.com"
port: 587
domain: "your_domain"
authentication: :login
user_name: "your_smtp_user"
password: "your_smtp_password"
enable_starttls_auto: true
Protect the file and restart Redmine:
sudo chmod 600 /opt/redmine/config/configuration.yml
sudo systemctl restart redmine
In Administration > Settings > Email notifications, set the Emission email address and click Send a test email. The test message goes to the address of the logged-in administrator.
Step 9 - Installing plugins
Redmine plugins are Rails engines that live in /opt/redmine/plugins/<plugin_name>. The procedure is the same for every plugin; always check that the plugin states support for Redmine 6.0 first:
- Copy or clone the plugin into
/opt/redmine/plugins/and runsudo chown -R redmine:redmine /opt/redmine/plugins. - Install any new gems with
cd /opt/redmine && sudo -u redmine bundle install. - Run the plugin migrations:
cd /opt/redmine
sudo -u redmine bundle exec rake redmine:plugins:migrate RAILS_ENV=production
sudo systemctl restart redmine
Installed plugins appear under Administration > Plugins.
Step 10 - Scheduling backups
The data you need to back up is the database, the uploaded files in files/ and the two configuration files. Create a backup script:
sudo nano /usr/local/sbin/redmine-backup
#!/usr/bin/env bash
set -euo pipefail
umask 077
BACKUP_DIR=/var/backups/redmine
APP_DIR=/opt/redmine
STAMP=$(date +%F-%H%M)
mkdir -p "$BACKUP_DIR"
# Runs as root, so MySQL authenticates through the Unix socket
mysqldump --single-transaction redmine | gzip > "$BACKUP_DIR/redmine-db-$STAMP.sql.gz"
tar -czf "$BACKUP_DIR/redmine-files-$STAMP.tar.gz" -C "$APP_DIR" \
files config/database.yml config/configuration.yml
find "$BACKUP_DIR" -type f -mtime +14 -delete
Make it executable, run it once and check the result:
sudo chmod 700 /usr/local/sbin/redmine-backup
sudo /usr/local/sbin/redmine-backup
sudo ls -lh /var/backups/redmine
-rw------- 1 root root 180K Sep 25 10:40 redmine-db-2026-09-25-1040.sql.gz
-rw------- 1 root root 12K Sep 25 10:40 redmine-files-2026-09-25-1040.tar.gz
Schedule it nightly:
echo '15 2 * * * root /usr/local/sbin/redmine-backup' | sudo tee /etc/cron.d/redmine-backup
Copy the backups off the server regularly, for example with rsync to another host.
Troubleshooting
bundle installfails buildingmysql2: the MySQL client headers are missing. Installlibmysqlclient-devand runbundle installagain.- Nginx returns 502 Bad Gateway: Puma is not running. Check
sudo systemctl status redmineandsudo journalctl -u redmine -n 50; a typo indatabase.ymlis the usual cause. - Links in notification emails use
localhost:3000: set Host name and path and Protocol under Administration > Settings > General. - Uploads larger than a few MB are rejected: raise Maximum attachment size under Administration > Settings > Files and keep
client_max_body_sizein Nginx at least as large.
Conclusion
Redmine 6 is now running on Ubuntu 24.04 under Puma and systemd, behind Nginx with HTTPS, with email notifications and nightly backups. Next, create your first project and adjust roles and trackers under Administration, enable the REST API if you want to integrate other tools, and when a new release comes out, upgrade by extracting it into a new directory, copying over config/database.yml, config/configuration.yml, files/ and plugins/, and running the database migrations.
