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 sudo privileges.
  • A domain or subdomain (this guide uses your_domain) with a DNS A record pointing to your_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:

  1. Copy or clone the plugin into /opt/redmine/plugins/ and run sudo chown -R redmine:redmine /opt/redmine/plugins.
  2. Install any new gems with cd /opt/redmine && sudo -u redmine bundle install.
  3. 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 install fails building mysql2: the MySQL client headers are missing. Install libmysqlclient-dev and run bundle install again.
  • Nginx returns 502 Bad Gateway: Puma is not running. Check sudo systemctl status redmine and sudo journalctl -u redmine -n 50; a typo in database.yml is 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_size in 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.