GitLab + uWSGI + Nginx on FreeBSD

Most of the details about GitLab installation under FreeBSD can be found online.
Current post contains a part about uWSGI & Nginx only.

First you have to compile uWSGI with Ruby support.
It would be faster to use version from ports:

cd /usr/ports/www/uwsgi
make extract
cd work/uwsgi-2.x.y.z

# Create config for running Python and Ruby apps together through uWSGI
printf "[uwsgi]\nmain_plugin = python,gevent,rack,rbthreads,fiber\ninherit = base" > buildconf/rackp.ini
python uwsgiconfig.py --build rackp
# or Ruby only
python uwsgiconfig.py --build ruby2

# Check that compiled binary has Python and/or Ruby in place
./uwsgi --plugins-list

cd ../..
make install

Add configuration lines into /etc/rc.conf:

uwsgi_enable="YES"
uwsgi_uid="root"
uwsgi_gid="wheel"
uwsgi_flags="--processes=0 --die-on-term --emperor-procname \"[uWSGI] Emperor\" --procname-master \"[uWSGI] Root\" --enable-threads --reload-mercy 10 --emperor /usr/local/etc/uwsgi --emperor-pidfile /var/run/uwsgi_emperor.pid --emperor-stats /tmp/uwsgistats.sock --emperor-freq 60 --binary-path /usr/local/bin/uwsgi --disable-logging --daemonize /var/log/uwsgi.log --log-truncate --log-maxsize 5242880 --log-backupname /var/log/uwsgi.log.old"

uWSGI will be running in Emperor mode with root rights and will spawn vassals under selected uids/gids containing Master process and multiple Worker processes if necessary.
Change paths and titles as you like, then proceed to creating vassal config in the selected emperor path (or use it as an example for other modes).

[uwsgi]
strict			= true
plugin			= rack
uid			= git
gid			= git
master			= true
auto-procname		= true
memory-report		= false
processes		= 2
enable-threads		= true
rbthreads		= true
threads			= 3
offload-threads		= 3
socket			= /home/git/gitlab/tmp/sockets/gitlab.socket
chdir			= /home/git/gitlab/
post-buffering		= 4096
env			= RAILS_ENV=production
# Node.js must be installed
env			= EXECJS_RUNTIME=Node
rack			= /home/git/gitlab/config.ru
rbrequire		= rubygems
rbrequire		= bundler/setup
ruby-gc-freq		= 1
disable-logging		= true
harakiri		= 60
procname		= [uWSGI] Vassal GitLab worker 
procname-master		= [uWSGI] Vassal GitLab master

Last step is to make Nginx proxy requests correctly to uWSGI and gitlab-workhorse.

Unicorn would be the 4th HTTP server if you are already using Apache, Nginx and GitLab-Workhorse. Isn’t it too many? =) So I decided to drop Unicorn and use Nginx instead, the only problem is that gitlab-workhorse have to use some auth backend, but it cannot be the same Nginx server, because requests are the same too, so they will go in a loop. Solution is to create Nginx vhost on another port to proxy requests back to uWSGI.

Prepare Nginx first by copying uwsgi_params-dist to uwsgi_params, then create vhosts like this:

upstream gitlab-workhorse {
	server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}

limit_req_zone $binary_remote_addr zone=cibuild:1m rate=2r/m;

server {
	listen 255.255.255.255:80;
	server_name domain.com;

	access_log ...;
	error_log ...;

	root /home/git/gitlab/public;
	client_max_body_size 128m;

	# Redirect all requests to gitlab-workhorse
	location / {
		# Main page shows public projects instead of sign-in page
		rewrite ^/$ /public;
		try_files $uri @gitlab-workhorse;
	}

	# Nice hack to limit gitlab-ci-multi-runner requests
	# and keep your Nginx and production logs relatively clean
	location ~ ^/ci/api/v1/builds/register\.json$ {
		access_log /dev/null;
		limit_req_status 404; # 404 = no pending builds
		limit_req zone=cibuild nodelay;
		log_not_found off;
		try_files - @gitlab-workhorse;
	}

	# Static assets
	location ~ ^/assets/ {
		gzip_static on;
		expires max;
		add_header Cache-Control public;
	}

	# Proxy to GitLab Workhorse
	location @gitlab-workhorse {
		gzip off;

		proxy_read_timeout 300;
		proxy_connect_timeout 300;
		proxy_redirect off;
		proxy_buffering off;
		proxy_request_buffering off;
		proxy_http_version 1.1;

		proxy_set_header Host $http_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;
		proxy_set_header X-Frame-Options SAMEORIGIN;

		proxy_pass http://gitlab-workhorse;
	}
}

# Backend for GitLab Workhorse
server {
	listen 255.255.255.255:8090;
	server_name domain.com;

	root /home/git/gitlab/public;
	client_max_body_size 128m;

	location / {
		gzip off;

		proxy_read_timeout 300;
		proxy_connect_timeout 300;
		proxy_redirect off;
		proxy_buffering off;
		proxy_request_buffering off;
		proxy_http_version 1.1;

		proxy_set_header Host $http_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;
		proxy_set_header X-Frame-Options SAMEORIGIN;

		include uwsgi_params;
		uwsgi_modifier1 7;
		uwsgi_pass unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
	}
}

Start gitlab-workhorse as a daemon :devil: using some lengthy command like this one and you are good to go :-)

/usr/bin/su - git -c "/usr/bin/nohup /home/git/gitlab-workhorse/gitlab-workhorse -listenNetwork unix -listenAddr /home/git/gitlab/tmp/sockets/gitlab-workhorse.socket -authBackend http://domain.com:8090 -listenUmask 000 -documentRoot /home/git/gitlab/public >/home/git/gitlab/log/gitlab-workhorse.log 2>&1 &" >/dev/null 2>&1

Leave comment

Notify of new comments using RSS