Esta pagina se ve mejor con JavaScript habilitado

GitLab bajo FreeBSD

 ·  🎃 kr0m

En este artículo explicaremos como instalar un servidor GitLab bajo FreeBSD, para una mayor flexibilidad lo instalaré en una jail utilizando Bastille .
Antes de empezar aclarar que GitLab es una aplicación escrita en Ruby por lo tanto tendremos el servidor de Ruby que incorpora GitLab y el servidor web de nuestar elección que reenviará las peticiones a GitLab y servirá el contendio estático.

Creamos la jail:

bastille create -T BaudBeauty 13.1-RELEASE 192.168.69.16/24 nfe0

Habilitamos y arrnacamos el servicio SSH:

bastille sysrc BaudBeauty sshd_enable=YES
bastille service BaudBeauty sshd start

Accedemos a la jail:

bastille console BaudBeauty

Según la documentación debemos utilizar los repositorios latest:

mkdir -p /usr/local/etc/pkg/repos
vi /usr/local/etc/pkg/repos/FreeBSD.conf

FreeBSD: {
    url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
    mirror_type: "srv",
    signature_type: "fingerprints",
    fingerprints: "/usr/share/keys/pkg",
    enabled: yes
}

Instalamos GitLab:

pkg install www/gitlab-ce

Instalamos la última versión de PostgreSQL que sea compatible con la versión de GitLab que estemos instalando, en mi caso:

gitlab-ce-15.5.6_1

La única forma que he encontrado para averiguar la versión correcta es instalar la versión mas alta e ir descendiendo hasta que el instalador no pretenda desintalarnos GitLab:

Installed packages to be REMOVED:
	gitlab-ce: 15.5.6_1
	postgresql13-client: 13.9
	rubygem-activerecord-explain-analyze: 0.1.0_4
	rubygem-pg: 1.4.4

New packages to be INSTALLED:
	postgresql15-client: 15.1
	postgresql15-contrib: 15.1
	postgresql15-server: 15.1_1

Instalamos PostgreSQL:

pkg install postgresql13-server postgresql13-contrib

PostgreSQL precisa de acceso a sysvipc pero las jails por defecto están restringidas.
Permitimos el acceso por jail, también se puede permitir de forma global en el host padre para todas las jails pero es preferible ser mas granular:

bastille config BaudBeauty set sysvmsg=new
bastille config BaudBeauty set sysvsem=new
bastille config BaudBeauty set sysvshm=new

NOTA: No utilicéis allow.sysvipc ya que se considera deprecated y otorga mas permisos de los estrictamente necesarios.

Reiniciamos la jail:

bastille stop BaudBeauty
bastille start BaudBeauty

Inicializamos y arrancamos la base de datos:

sysrc postgresql_enable=YES
service postgresql initdb
service postgresql start

Creamos el usuario git en la base de datos:

psql -d template1 -U postgres -c "CREATE USER git CREATEDB SUPERUSER;"
psql -d template1 -U postgres -c "ALTER ROLE git WITH PASSWORD 'XXXXXXXXXXXXXXXXXX';"

Creamos la base de datos que utilizará GitLab:

psql -d template1 -U postgres -c "CREATE DATABASE gitlabhq_production OWNER git;"

Comprobamos que se haya creado:

psql -d gitlabhq_production -U postgres -c "\l"

                                   List of databases
        Name         |  Owner   | Encoding | Collate |  Ctype  |   Access privileges   
---------------------+----------+----------+---------+---------+-----------------------
 gitlabhq_production | git      | UTF8     | C       | C.UTF-8 | 
 postgres            | postgres | UTF8     | C       | C.UTF-8 | 
 template0           | postgres | UTF8     | C       | C.UTF-8 | =c/postgres          +
                     |          |          |         |         | postgres=CTc/postgres
 template1           | postgres | UTF8     | C       | C.UTF-8 | =c/postgres          +
                     |          |          |         |         | postgres=CTc/postgres
(4 rows)

Permitimos el acceso desde la propia ip del servidor:

vi /var/db/postgres/data13/pg_hba.conf

# GitLab:
host    all     git     192.168.69.16/32        md5

Reiniciamos el servicio:

service postgresql restart

Comprobamos que podemos conectar con el usuario git:

psql -h localhost -U git -d gitlabhq_production

Habilitamos la extensiones pg_trgm y btree_gist:

psql -U postgres -d gitlabhq_production -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -U postgres -d gitlabhq_production -c "CREATE EXTENSION IF NOT EXISTS btree_gist;"

GitLab nos habrá instalado un Redis como dependencia, habilitamos el acceso por socket:

echo 'unixsocket /var/run/redis/redis.sock' >> /usr/local/etc/redis.conf

Indicamos los permisos del socket:

echo 'unixsocketperm 770' >> /usr/local/etc/redis.conf

Habilitamos y arrancamos Redis:

sysrc redis_enable=YES
service redis restart

Añadimos el usuario git al grupo redis:

pw groupmod redis -m git

En mi caso no hace falta configurar SSL ya que utilizo un balanceador HTTP donde termino el túnel SSL, tan solo debo indicar la ip de dicho balanceador en trusted_proxies y finalmente la cuenta de email que quiero que utilice para enviar notificaciones:

cd /usr/local/www/gitlab-ce
vi config/gitlab.yml

...
  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: flatland.alfaexploit.com
    port: 80 # Set to 443 if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
    https: false # Set to true if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
...
    trusted_proxies:
      - 192.168.69.19/32
...
    email_from: gitlab@alfaexploit.com
    email_reply_to: gitlab@alfaexploit.com

Creamos un usuario de email en el servidor de email:

gitlab@alfaexploit.com
adduser

Copiamos la configuración STMP de ejemplo y la adaptamos:

cp config/initializers/smtp_settings.rb.sample config/initializers/smtp_settings.rb
vi config/initializers/smtp_settings.rb

if Rails.env.production?
  Rails.application.config.action_mailer.delivery_method = :smtp
  secrets = Gitlab::Email::SmtpConfig.secrets

  ActionMailer::Base.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    address: "192.168.69.17",
    port: 25,
    user_name: "gitlab@alfaexploit.com",
    password: "XXXXXXXXXXX",
    ## If you are using encrypted smtp credentials then you should instead use the secrets user_name/password
    ## See: https://docs.gitlab.com/ee/administration/raketasks/smtp.html#secrets
    # user_name: secrets.username,
    # password: secrets.password,
    domain: "flatland.alfaexploit.com",
    authentication: :login,
    enable_starttls_auto: true,
    openssl_verify_mode: 'peer' # See ActionMailer documentation for other possible options
  }
end

Configuramos la key con la que la base de datos será cifrada:

vi config/secrets.yml

db_key_base: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Consultamos el número de cores que tiene el servidor:

sysctl hw.ncpu

hw.ncpu: 2

Para un servidor con 2Gb de RAM 3 workers suele ir bien, pero siempre debe cumplirse workers>=hw.ncpu:

vi config/puma.rb

workers 3

Configuramos algunas opciones del usuario git para que GitLab funcione correctamente:

su -l git -c "git config --global core.autocrlf input"
su -l git -c "git config --global gc.auto 0"
su -l git -c "git config --global repack.writeBitmaps true"
su -l git -c "git config --global receive.advertisePushOptions true"
su -l git -c "git config --global core.fsync objects,derived-metadata,reference"

Nos aseguramos de que el directorio .ssh exista:

su -l git -c "mkdir -p /usr/local/git/.ssh"

Nos aseguramos de que el directorio de los repositorios exista y tenga los permisos necesarios:

su -l git -c "mkdir -p /usr/local/git/repositories"
chown git /usr/local/git/repositories
chgrp git /usr/local/git/repositories
chmod 2770 /usr/local/git/repositories

Configuramos las credenciales de acceso a PostgreSQL:

vi config/database.yml

production:
  main:
    adapter: postgresql
    encoding: unicode
    database: gitlabhq_production
    username: git
    password: "XXXXXXXXXXXXXXX"
    host: localhost

  ci:
    adapter: postgresql
    encoding: unicode
    database: gitlabhq_production
    database_tasks: false
    username: git
    password: "XXXXXXXXXXXXXXX"
    host: localhost

Ajustamos los permisos del directorio /usr/local/share/gitlab-shell para que el usuario git tenga acceso mientras inicializa la base de datos y realiza la configuración inicial:

chown git /usr/local/share/gitlab-shell

Inicializamos la base de datos indicando el password de acceso para root, la primera vez se generan keys RSA en base a la db_key_base indicada, por este motivo dirá missing Rails.application.secrets.secret_key_base, pero se refiere a la key RSA no al password, así que todo va bien:

su -l git -c "cd /usr/local/www/gitlab-ce && rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=XXXXXXXXXXXXXXXXXX"

Missing Rails.application.secrets.secret_key_base for production environment. The secret will be generated and stored in config/secrets.yml.
Missing Rails.application.secrets.otp_key_base for production environment. The secret will be generated and stored in config/secrets.yml.
Missing Rails.application.secrets.openid_connect_signing_key for production environment. The secret will be generated and stored in config/secrets.yml.
This will create the necessary database tables and seed the database.
You will lose any previous data stored in the database.
Do you want to continue (yes/no)? yes

Dropped database 'gitlabhq_production'
Created database 'gitlabhq_production'

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/001_application_settings.rb
Creating the default ApplicationSetting record.

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/002_admin.rb
Administrator account created:

login:    root
password: ******

Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead.(called from: /usr/local/lib/ruby/gems/3.0/gems/redis-namespace-1.9.0/lib/redis/namespace.rb:479:in `call_with_namespace')

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/003_create_base_work_item_types.rb

OK

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/004_add_security_training_providers.rb

OK

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/010_settings.rb
Saved CI JWT signing key

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/998_gitlab_instance_administration_project.rb
Successfully created self monitoring project.
Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead.(called from: /usr/local/lib/ruby/gems/3.0/gems/redis-namespace-1.9.0/lib/redis/namespace.rb:479:in `call_with_namespace')
Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead.(called from: /usr/local/lib/ruby/gems/3.0/gems/redis-namespace-1.9.0/lib/redis/namespace.rb:479:in `call_with_namespace')

== Seed from /usr/local/www/gitlab-ce/db/fixtures/production/999_common_metrics.rb

Si se queja de unsupported database names: embedding, tendremos que comentar la sección embedding:

ERROR: This installation of GitLab uses unsupported database names in 'config/database.yml': embedding. The only supported ones are main, ci, main_clusterwide.
vi config/database.yml
test: &test
#  embedding:
#    adapter: postgresql
#    encoding: unicode
#    database: gitlabhq_embedding_test
#    username: postgres
#    password:
#    host: localhost

Backupeamos los secrets:

cat config/secrets.yml

Ahora que ya hemos inicializado la base de datos podemos revertir los permisos asignados:

chown root /usr/local/share/gitlab-shell

Comprobamos que todo el entorno GitLab esté funcionando correctamente, la versión de Go se puede ignorar:

su -l git -c "cd /usr/local/www/gitlab-ce && rake gitlab:env:info RAILS_ENV=production"

System information
System:		
Current User:	git
Using RVM:	no
Ruby Version:	3.0.5p211
Gem Version:	3.3.23
Bundler Version:2.3.23
Rake Version:	13.0.6
Redis Version:	7.0.7
Sidekiq Version:6.4.2
Go Version:	unknown

GitLab information
Version:	15.5.6
Revision:	Unknown
Directory:	/usr/local/www/gitlab-ce
DB Adapter:	PostgreSQL
DB Version:	13.9
URL:		http://flatland.alfaexploit.com
HTTP Clone URL:	http://flatland.alfaexploit.com/some-group/some-project.git
SSH Clone URL:	git@flatland.alfaexploit.com:some-group/some-project.git
Using LDAP:	no
Using Omniauth:	yes
Omniauth Providers: 

GitLab Shell
Version:	14.12.0
Repository storage paths:
- default: 	/usr/local/git/repositories
GitLab Shell path:		/usr/local/share/gitlab-shell

Compilamos los assets:

su -l git -c "cd /usr/local/www/gitlab-ce && yarn install --production --pure-lockfile"
su -l git -c "cd /usr/local/www/gitlab-ce && RAILS_ENV=production NODE_ENV=production USE_DB=false SKIP_STORAGE_VALIDATION=true NODE_OPTIONS='--max_old_space_size=3584' bundle exec rake gitlab:assets:compile"

NOTA: Esto tardará: Done in 1134.20s.

Eliminamos los permisos de superusuario de la base de datos:

psql -d template1 -U postgres -c "ALTER USER git WITH NOSUPERUSER;"

Habilitamos y arrancamos GitLab:

sysrc gitlab_enable=YES
service gitlab start

Instalamos Nginx:

pkg install nginx

Incluimos la configuración de GitLab:

vi /usr/local/etc/nginx/nginx.conf

...
http {
    include       mime.types;
    include       /usr/local/www/gitlab-ce/lib/support/nginx/gitlab;
...

Modificamos la configuración de Nginx para que utilice proxy protocol para determinar la ip real de las peticiones:

vi /usr/local/www/gitlab-ce/lib/support/nginx/gitlab

...
server {
  listen 0.0.0.0:80 default_server proxy_protocol;
  server_name flatland.alfaexploit.com; ## Replace this with something like gitlab.example.com
  server_tokens off; ## Don't show the nginx version number, a security best practice

  real_ip_header proxy_protocol; ## X-Real-IP or X-Forwarded-For or proxy_protocol
  real_ip_recursive off;    ## If you enable 'on'
  set_real_ip_from 192.168.69.19;
...

Comprobamos que no haya errores:

nginx -t

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

Habilitamos y arrancamos el servicio:

sysrc nginx_enable=YES
service nginx restart

Comprobamos que todo esté configurado correctamente, podemos ignorar todos los errores relacionados con sidekiq, mailroom y systemD, además en la primera ejecución se quejará de que el fichero: authorized keys no está accesible, ejecutando el check una segunda vez ya funciona:

su -l git -c "cd /usr/local/www/gitlab-ce && rake gitlab:check RAILS_ENV=production"

Checking GitLab subtasks ...

Checking GitLab Shell ...

GitLab Shell: ... GitLab Shell version >= 14.12.0 ? ... OK (14.12.0)
Running /usr/local/share/gitlab-shell/bin/check
Internal API available: OK
Redis available via internal API: OK
gitlab-shell self-check successful

Checking GitLab Shell ... Finished

Checking Gitaly ...

Gitaly: ... default ... OK

Checking Gitaly ... Finished

Checking Sidekiq ...

Sidekiq: ... Running? ... no
  Try fixing it:
  sudo -u git -H RAILS_ENV=production bin/background_jobs start
  For more information see:
  doc/install/installation.md in section "Install Init Script"
  see log/sidekiq.log for possible errors
  Please fix the error above and rerun the checks.

Checking Sidekiq ... Finished

Checking Incoming Email ...

Incoming Email: ... Reply by email is disabled in config/gitlab.yml

Checking Incoming Email ... Finished

Checking LDAP ...

LDAP: ... LDAP is disabled in config/gitlab.yml

Checking LDAP ... Finished

Checking GitLab App ...

Database config exists? ... yes
All migrations up? ... yes
Database contains orphaned GroupMembers? ... no
GitLab config exists? ... yes
GitLab config up to date? ... yes
Log directory writable? ... yes
Tmp directory writable? ... yes
Uploads directory exists? ... yes
Uploads directory has correct permissions? ... yes
Uploads directory tmp has correct permissions? ... skipped (no tmp uploads folder yet)
Systemd unit files or init script exist? ... no
  Try fixing it:
  Install the Service
  For more information see:
  doc/install/installation.md in section "Install the Service"
  Please fix the error above and rerun the checks.
Systemd unit files or init script up-to-date? ... can't check because of previous errors
Projects have namespace: ... 
GitLab Instance / Monitoring ... yes
Redis version >= 6.0.0? ... yes
Ruby version >= 2.7.2 ? ... yes (3.0.5)
Git user has default SSH configuration? ... yes
Active users: ... 1
Is authorized keys file accessible? ... yes
GitLab configured to store new projects in hashed storage? ... yes
All projects are in hashed storage? ... yes

Checking GitLab App ... Finished


Checking GitLab subtasks ... Finished

Finalmente accedemos a gitlab:
https://flatland.alfaexploit.com

Para actualizar a versiones superiores siempre seguiremos los pasos indicados en la documentación .


Troubleshooting:

Comprobar configuración GitLab:

cat /usr/local/www/gitlab-ce/config/gitlab.yml

  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: gitlab.alfaexploit.com
    port: 80 # Set to 443 if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
    https: false # Set to true if using HTTPS, see installation.md#using-https for additional HTTPS configuration details

Comprobar configuración Nginx:

cat /usr/local/www/gitlab-ce/lib/support/nginx/gitlab

Recompilar assets:

su -l git -c "cd /usr/local/www/gitlab-ce && yarn install --production --pure-lockfile"
su -l git -c "cd /usr/local/www/gitlab-ce && RAILS_ENV=production NODE_ENV=production USE_DB=false SKIP_STORAGE_VALIDATION=true NODE_OPTIONS=’--max_old_space_size=3584’ bundle exec rake gitlab:assets:compile"

Directorio repositorios:

find /usr/local/git/repositories/ -iname config
su -l git
cd /usr/local/git/repositories/@hashed/XX/XX/XX.git
git log

Tareas RAKE:

su -l git -c "cd /usr/local/www/gitlab-ce && RAILS_ENV=production NODE_ENV=production USE_DB=false SKIP_STORAGE_VALIDATION=true NODE_OPTIONS=’--max_old_space_size=3584’ bundle exec rake --tasks"

Información versiones:

su -l git -c "cd /usr/local/www/gitlab-ce && rake gitlab:env:info RAILS_ENV=production"

Información entorno de ejecución:

su -l git -c "cd /usr/local/www/gitlab-ce && rake gitlab:check RAILS_ENV=production"

Visualizar logs:

tail -f /var/log/nginx/*
tail -f /usr/local/www/gitlab-ce/log/*

Reiniciar servicios:

service nginx restart
service gitlab restart

Importar repositorio:
En la interfaz de GitLab creamos el repositorio nuevo y despues realizamos el trasvase entre repositorios.
Clonamos el repositorio antiguo:

mkdir asd
cd asd

git clone git@gitlab.alfaexploit.com:gitlab-instance-0a98b435/bastille-basicconfiguration.git

Eliminamos el origin del repositorio:

cd bastille-basicconfiguration
git fetch --tags
git remote rm origin

Añadimos el nuevo origin del repositorio:

git remote add origin git@flatland.alfaexploit.com:root/bastille-basicconfiguration.git

Subimos el contenido:

git push origin --all
git push --tags

Sinceramente si solo necesitamos un servidor de git recomiendo GitOlite antes que GitLab, ya que GitOlite sencillamente funciona, no dá problemas compilando assets, ni con las gemas de Ruby y además es un sistema mucho mas liviano.

Si te ha gustado el artículo puedes invitarme a un RedBull aquí