Server installation guide - Ubuntu

In this tutorial we are going to show you how to install Gobierto in a Ubuntu Linux server.

Server requirements:

  • 6 Gb RAM as a minimum
  • 40 Gb HD as a minimum
  • 2 x CPU cores (recommend 4 if the database is in the same server)

Software requirements:

  • Ubuntu LTS
  • Ruby 2.7.4 (we recommend installing Ruby with rbenv)
  • Rubygems
  • Postgresql >= 12
  • ElasticSearch 2.4.x
  • Memcached
  • Redis
  • Nginx

External requirements:

  • Amazon AWS S3 keys
  • Rollbar or AppSignal, as exception notification tool (you can replace it easily)
  • An account in Cloudinary. You'll need the API keys.

We recommend you to prepare the credentials from these services before you continue with this
tutorial.

Ubuntu base packages

Packages required to be installed first (with apt install):

  • build-essential
  • git
  • psmisc
  • gnupg
  • zip
  • ruby-dev
  • imagemagick
  • libpq-dev
  • libicu-dev

Node & Yarn

Gobierto uses Node to compile assets and Yarn as preferred node package system:

To install Node.js 16.x:

curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash -
sudo apt install nodejs

To install Yarn:

curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo apt --import https://dl.yarnpkg.com/rpm/pubkey.gpg
sudo apt install yarn

Install Redis

sudo apt install redis-server

Depending on your needs you might want to adjust Redis configuration. Gobierto doesn't require anything special and works with a default configuration.

Install Postgres 12

In order to install Postgres 12:

sudo apt update
sudo apt -y install gnupg2
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee  /etc/apt/sources.list.d/pgdg.list

Then just install the server and the client packages:

sudo apt update
sudo apt -y install postgresql-12 postgresql-client-12

Refer to Gobierto data database setup for the special configuration that gobierto data module requires.

Install Passenger and Nginx

We recommend Nginx as webserver together with Passenger as application server:

# Install our PGP key and add HTTPS support for APT
sudo apt-get install -y dirmngr gnupg
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
sudo apt-get install -y apt-transport-https ca-certificates

# Add our APT repository
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger focal main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update

# Install Passenger + Nginx module
sudo apt-get install -y libnginx-mod-http-passenger

Then enable the module and restart nginx:

if [ ! -f /etc/nginx/modules-enabled/50-mod-http-passenger.conf ]; then sudo ln -s /usr/share/nginx/modules-available/mod-http-passenger.load /etc/nginx/modules-enabled/50-mod-http-passenger.conf ; fi
sudo ls /etc/nginx/conf.d/mod-http-passenger.conf
sudo service nginx restart

Database setup

Create the database: createdb gobierto.

Application setup

We have our preferences about which folders to use and with which permissions and users the application should be installed,
and this guide is going to follow those conventions. Feel free to adapt the guide to your infrastructure and personal perferences
.

Setup folders

  1. Choose a destination folder and create it. In our case, we prefer /var/www/gobierto:
  • /var/www/gobierto/
  • /var/www/gobierto/shared
  • /var/www/gobierto/shared/bundle
  • /var/www/gobierto/shared/config
  • /var/www/gobierto/shared/log
  • /var/www/gobierto/shared/public
  • /var/www/gobierto/shared/tmp
  • /var/www/gobierto/shared/vendor
  • /var/www/gobierto/releases
  • /var/www/gobierto/repo
  1. Copy .env.example to /var/www/gobierto/shared/.rbenv-vars and fill all the variables following this guide.

  2. Create /var/www/gobierto/shared/config/database.yml with the following content:

production:
  adapter: postgresql
  encoding: unicode
  database: gobierto
  pool: 5
  username: postgres
  password: XXXXX
  1. Review the config/application.yml file with the modules you want to enable and configure as home modules. See the complete reference of that file.

  2. Deploy the site

Gobierto doesn't include deploy recipes. We recommend to use Capistrano, and here's an example of a complete config/deploy.rb file that you can customize:

# frozen_string_literal: true

lock "3.16.0"
set :application, "gobierto"
set :repo_url, "https://github.com/PopulateTools/gobierto.git"
set :linked_files, fetch(:linked_files, []).push("config/database.yml", ".rbenv-vars")
set :linked_dirs, -> {
  [].push("log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system", "public/cache", "node_modules", "public/packs").
  concat(fetch(:gobierto_engines, []).map { |engine| "vendor/gobierto_engines/#{engine}" })
}
set :passenger_restart_with_touch, true

# Engines
set :gobierto_engines, []
# Plugins
set :gobierto_plugins, []

namespace :deploy do
  desc "Copy application configuration"
  task :copy_application_configuration do
    on roles(:all) do
      execute "cp #{shared_path}/config/application.yml #{release_path}/config/application.yml"
      execute "cp #{shared_path}/config/google_calendar_integration_client_secret.json #{release_path}/config/google_calendar_integration_client_secret.json"
    end
  end

  desc "Migrate search indexes"
  task :migrate_search_indexes do
    on roles(:all) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, "common:rebuild_multisearch_indexes"
        end
      end
    end
  end

  desc 'Update gobierto engines repos'
  task :update_gobierto_engines_repos do
    on roles(:all) do
      fetch(:gobierto_engines, []).each do |engine|
        execute "cd #{shared_path}/vendor/gobierto_engines/#{engine} && git checkout . && git pull origin"
      end
    end
  end

  desc "Create webpacker packs engines symlinks"
  task :create_webpacker_packs_symlinks do
    on roles(:all) do
      fetch(:gobierto_engines, []).each do |engine|
        execute "#{shared_path}/vendor/gobierto_engines/#{engine}/script/create_webpacker_symlinks.sh -d #{release_path}"
      end
      fetch(:gobierto_plugins, []).each do |plugin|
        execute "#{release_path}/vendor/gobierto_engines/#{plugin}/script/create_webpacker_symlinks.sh -d #{release_path}"
      end
    end
  end

  desc 'Update vendor repos'
  task :update_vendor_repos do
    invoke "deploy:update_gobierto_engines_repos"
    invoke "deploy:create_webpacker_packs_symlinks"
  end

  desc "Create translations file"
  task :js_translations do
    on roles(:all) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, "i18n:js:export"
        end
      end
    end
  end

  desc "Clear webpacker cache"
  task :clear_webpacker_cache do
    on roles(:all) do
      within release_path do
        execute "rm -rf #{shared_path}/tmp/cache/webpacker"
      end
    end
  end

  desc "Copy application configuration"
  task :force_ruby_version_with_jemalloc do
    on roles(:all) do
      execute "echo `cat #{release_path}/.ruby-version`'-jemalloc' > #{release_path}/.ruby-version"
    end
  end

  after "deploy:symlink:linked_dirs", "deploy:update_vendor_repos"
  after "deploy:symlink:linked_files", "deploy:copy_application_configuration"
  after "deploy:published", "deploy:migrate_search_indexes"
  before "deploy:assets:precompile", "deploy:js_translations"
  before "deploy:assets:precompile", "deploy:clear_webpacker_cache"
  after "deploy:symlink:linked_files", "deploy:force_ruby_version_with_jemalloc"
end
  1. (optional) Load budgets data

Once the application is working in production (without working in the HTTP server yet) we need to
load budgets data (if you enable the budgets module).

Please, refer to Gobierto budgets data load page for further information.

  1. Configure and enable the server virtual host. You can use this file as template, with SSL configuration:
server {
  listen        80 default_server;
  server_name   _; # Gobierto is multitenant, so the virtualhost must listen to multiple hosts

  root /var/www/gobierto/current/public;

  rails_env production;

  location / {
    return  301 https://$host$request_uri;
  }
}

server {
  listen 443 http2;
  server_name   _; # Gobierto is multitenant, so the virtualhost must listen to multiple hosts

  ssl on;
  ssl_certificate /etc/ssl/certs/gobierto.es.chained.crt;
  ssl_certificate_key /etc/ssl/private/gobierto.key;

  passenger_enabled on;
  client_max_body_size 50M;

  access_log      /var/log/nginx/presupuestos-gobierto_access.log;
  error_log       /var/log/nginx/presupuestos-gobierto_error.log;

  root /var/www/gobierto/current/public;

  rails_env production;

  location ~ ^/(assets|packs)/ {
    try_files $uri =404;
    expires max;
    add_header Cache-Control public;
    gzip_static on;
    add_header Last-Modified "";
    add_header ETag "";
    break;
  }

  location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
    try_files $uri =404;
    log_not_found off;
    break;
  }

  location @passenger_root {
      root /var/www/gobierto/current/public;
  }
}

Remember to update the domains (updating the variable server_name) according to your needs.

Also, configure or disable GOBIERTO_FORCE_SSL env var to force SSL in the application.

  1. Once you reload the webserver to read the new configuration you should be able to see the site up and running.

  2. If you want to enable memcached storage Gobierto supports it:

  • set GOBIERTO_CACHE_TYPE to mem_cache_store if you want to enable memcached
  • set GOBIERTO_CACHE_MEMCACHE_HOST to a valid host if your memcached is in a different server

Backups

Once the application is installed, it's convenient to generate and store backups periodically. There are 3 main data sources for backups:

1. Application log

In application log the requests sent to the application, the processes and database queries generated as consequence of the requests and the responses to the requests are recorded. If the setup folders instructions of this guide has been followed, the application log can be found in /var/www/gobierto/shared/log/.
The name of the log file uses the application environment, so it is production.log if the application is installed in production environment. It's recommended to rotate daily the log file due to the verbosity of the application. To do this you can setup logrotate by setting in /etc/logrotate.d/gobierto

/var/www/gobierto/shared/log/production.log {
    daily
    rotate 30
    compress
    dateext
    dateformat -%Y%m%d-server_name
    missingok
    notifempty
    sharedscripts
    postrotate
        touch /var/www/gobierto/current/tmp/restart.txt
    endscript
}

In this way the most recent activity of the log is in an uncompressed file with a .log extension and the entries from previous days are in compressed files with names containing with the same date of the contained activities.

2. Files uploaded with the application

Depending on the installation they can be found in the file system in which the application is located, in /var/www/gobierto/shared/public/system/attachments/ or in a cloud storage service as s3.

3. Database

It's recommended to store periodically database dumps. To do this, use pg_dump instruction is invoked. If the database user employed to create the application database is called postgres, the database is called gobierto as recommended in this guide and the database is installed in the same machine as the application the instruction to generate a dump can be:

pg_dump -U postgres -Fc -f backup_location/gobierto-date.sql.gz -Z 9 -U postgres gobierto.

The backup_location can be a directory located in the home path of the user executing the instruction and date is recommended to use the same format as the log rotation: %Y%m%d (e.g. 20191231)

If the database is installed on a different machine and port, for example database.server.org:5442 add a pair of options:

pg_dump -U postgres -h database.server.org  -p 5442 -Fc -f backup_location/gobierto-date.sql.gz -Z 9 -U postgres gobierto

Questions

If you have any question, please reach to us in [email protected] or create an issue in the
repository. We'll get back to you ASAP.