Installing GitLab on existing Apache Server for Ubuntu

GitLab works under built-in Nginx web server engine by default. Therefore, if you already have an existing web server, you may need some extra work to use both your existing websites and GitLab at the same time. The easiest way is to assign different ports on two different servers, but it may not be the good way because visitors have to remember the specified port every time they connect. The article presents the way to add GitLab on existing Apache server using reverse proxy approach.

Step 1: Install GitLab

To install GitLab, please type the following commands to install gitlab-ce:

sudo apt-get install curl openssh-server ca-certificates postfix
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo apt-get install gitlab-ce
sudo gitlab-ctl reconfigure

If this is the only and first website for your server, then you can just use it without any issues. However, if you already have an existing website, you will eventually find out that your existing website is replaced by GitLab you have just installed. If you have an existing Apache web server, please restart your Apache server by using the following command, and check your website again:

sudo service apache2 restart

The solution for the presented issue will be introduced in the following section.

Step 2: Modify GitLab configuration

The GitLab configuration file in Ubuntu is "/etc/gitlab/gitlab.rb". Type the following command to edit the configuration file:

sudo nano /etc/gitlab/gitlab.rb

Now, edit the following lines:

# Change GitLab port (any unused port is ok.)
external_url 'http://127.0.0.1:14500'

Save the file, and run the following command:

sudo gitlab-ctl reconfigure

Step 3: Configure Apache to use GitLab using reverse proxy

Before presenting the main entry, please make sure that you have a domain or subdomain url for applying on GitLab url. In this article, we assume that you have a url, "http://gitlabtest.yoursite.com/" for GitLab, as an example.

Now, please make sure proxy_http module is enabled on Apache engine. You can enable the module using the following command:

sudo a2enmod proxy_http

Please create an Apache site configuration for gitlab as follows:

cd /etc/apache2/sites-available/
sudo touch gitlab.conf
sudo nano gitlab.conf

Now, add the VirtualHost entry as follows:

<VirtualHost *:80>
  ServerName gitlab.yoursite.com

  ProxyRequests off
  ProxyPass / http://127.0.0.1:14500
  ProxyPassReverse / http://127.0.0.1:14500
<VirtualHost>

Now, enable the gitlab website configuration using the following command:

sudo a2ensite gitlab
sudo service apache2 restart

Step 4: Resolve an issue of displaying wrong repository url on GitLab

Because the actual GitLab is running under the bundled Nginx server, the repository url displayed on GitLab webpage may be wrong (i.e., http://127.0.0.1:14500/repo_url) and inaccessible from the actual client. You can resolve this issue by modifying the following configuration file:

sudo nano /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml

Original configuration:

## Web server settings (note: host is the FQDN, do not include http://)
host: 127.0.0.1
port: 14500
https: false

Modify the configuration as follows:

## Web server settings (note: host is the FQDN, do not include http://)
host: gitlabtest.yoursite.com
port: 80
https: false

Now, restart gitlab using the following command:

sudo gitlab-ctl restart

You can now connect to GitLab using gitlabtest.yoursite.com through the Apache server. Please note that the configuration will reset to 127.0.0.1 if you use the command gitlab-ctl reconfigure. Therefore, you have to modify the setting again if you reconfigure GitLab.

Note 1: If you want to use https…

If you want to setup GitLab using https, you need some extra configurations. Assuming that you already have a valid certificate, key, and root ca, please follow the instruction below.

Modify GitLab settings

First, modify /etc/gitlab/gitlab.rb as follows:

# Change GitLab port (any unused port is ok.)
external_url 'https://127.0.0.1:14500'

...
################
# GitLab Nginx #
################
...
nginx['ssl_certificate'] = "/path/to/certificate.crt"
nginx['ssl_certificate_key'] = "/path/to/certificate_key.key"

Then, reconfigure GitLab by using the following command:

sudo gitlab-ctl reconfigure

Now, modify /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml as follows:

## Web server settings (note: host is the FQDN, do not include http://)
host: gitlabtest.yoursite.com
port: 443
https: true

Finally, restart gitlab-ctl by typing the following command:

sudo gitlab-ctl restart

Modify Apache settings

To configure https reverse proxy on Apache, modify the /etc/apache2/sites-available/gitlab.conf on Apache as follows:

<VirtualHost *:80>
  ServerName gitlabtest.yoursite.com
  Redirect permanent / https://gitlabtest.yoursite.com/
</VirtualHost> 

<VirtualHost *:443>
  ServerName gitlabtest.yoursite.com

  # Certificate
  SSLEngine on
  SSLCertificateFile /path/to/certificate.crt
  SSLCertificateKeyFile /path/to/certificate_key.key
  SSLCertificateChainFile /path/to/certificate_ca.crt

  # Proxy
  SSLProxyEngine on
  SSLProxyVerify none
  SSLProxyCheckPeerCN off
  SSLProxyCheckPeerName off
  SSLProxyCheckPeerExpire off

  ProxyPass / https://127.0.0.1:14500/
  ProxyPassReverse / https://127.0.0.1:14500/
</VirtualHost>

Now, type the following command to restart Apache, and you can not use GitLab through https.

sudo service apache2 restart

Note 2: if you want to limit access by IP…

If you want to limit GitLab access by IP, add the following statement on gitlab.conf:

<Proxy *>
  Order Deny,Allow
  Deny from all
  Allow from your_ip_address
<Proxy>

Conclusion

As presented above, you can use GitLab with existing Apache server setting up reverse proxy on Apache and connect to bundled Nginx engine on GitLab. I think there may be other ways to configure Apache with GitLab, and the approach we presented is one of the way. Please let us know if there is a better way to configure it.

References

[1] forum.gitlab.com, "[SOLVED] Setting up Gitlab on Ubuntu 14.04 with Apache2 without owning a domain name," GitLab Forum, 27-Apr-2015. [Online]. Available: https://forum.gitlab.com/t/solved-setting-up-gitlab-on-ubuntu-14-04-with-apache2-without-owning-a-domain-name/679/2
[2] superuser.com, "js, and css not appearing after installing gitlab," Superuser, 19-Nov-2015. [Online]. Available: http://superuser.com/questions/1002827/js-and-css-not-appearing-after-installing-gitlab
[3] Goedecke, "Setup GitLab on Debian 7 with existing Apache WebServer," GitLab Forum, 17-Sep-2015. [Online]. Available: https://kevingoedecke.me/2015/09/17/setup-gitlab-on-debian-7-with-existing-apache-webserver/
[4] stackoverflow.com, "Gitlab in a subdirectory with apache and passenger," kevingoedecke.me, 29-Jul-2013. [Online]. Available: http://stackoverflow.com/questions/17924644/gitlab-in-a-subdirectory-with-apache-and-passenger
[5] Tully, "Running GitLab from a subdirectory on Apache," shanetully.com, 23-Aug-2012. [Online]. Available: https://shanetully.com/2012/08/running-gitlab-from-a-subdirectory-on-apache/
[6] redmine.org, "Redmine in a subdirectory," redmine.org, 03-Sep-2008. [Online]. Available: http://www.redmine.org/boards/2/topics/2244

Login Problem on WordPress for Android

I tried to login to my WordPress blog using WordPress for Andoroid, but I received the following error:

I tried to fix this issue for a long time, but it took a long time to find the solution for it. There was no problem with logging in to the wordpress.com blogs, and I could even logging into my alternative blog installed on my Bluehost web server without any problem. There are a number of causes for it, but I could make it work by installing the correct version of xml and xmlrpc module that runs my WordPress engine.

Finding the Root Cause

The following listing is the application log from WordPress for Android:

01 - WordPress.onCreate
02 - App comes from background
03 - ConnectionChangeReceiver.setEnabled true
04 - Connection status changed, isConnected=true
...
13 - No documented SNI support on Android <4.2, trying with reflection
14 - Established TLSv1.2 connection with www.cheonghyun.com using TLS_RSA_WITH_AES_128_CBC_SHA
15 - No HTTP error document document from the server
16 - system.listMethods failed on: https://www.cheonghyun.com/xmlrpc.php - exception: HTTP status code: 500 was returned. Internal Server Error
17 - StackTrace: org.xmlrpc.android.XMLRPCException: HTTP status code: 500 was returned. Internal Server Error
	at org.xmlrpc.android.XMLRPCClient$Caller.callXMLRPC(XMLRPCClient.java:547)
	at org.xmlrpc.android.XMLRPCClient$Caller.access$000(XMLRPCClient.java:430)
	at org.xmlrpc.android.XMLRPCClient.call(XMLRPCClient.java:231)
	at org.xmlrpc.android.XMLRPCClient.call(XMLRPCClient.java:226)
	at org.xmlrpc.android.XMLRPCUtils.doSystemListMethodsXMLRPC(XMLRPCUtils.java:96)
	at org.xmlrpc.android.XMLRPCUtils.checkXMLRPCEndpointValidity(XMLRPCUtils.java:203)
	at org.xmlrpc.android.XMLRPCUtils.verifyXmlrpcUrl(XMLRPCUtils.java:291)
	at org.xmlrpc.android.XMLRPCUtils.verifyOrDiscoverXmlRpcUrl(XMLRPCUtils.java:250)
	at org.wordpress.android.ui.accounts.helpers.FetchBlogListWPOrg$FetchBlogListTask.doInBackground(FetchBlogListWPOrg.java:55)
	at org.wordpress.android.ui.accounts.helpers.FetchBlogListWPOrg$FetchBlogListTask.doInBackground(FetchBlogListWPOrg.java:35)
	at android.os.AsyncTask$2.call(AsyncTask.java:287)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
	at java.util.concurrent.FutureTask.run(FutureTask.java:137)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
	at java.lang.Thread.run(Thread.java:856)
...
26 - The XML-RPC endpoint was not found by using our 'smart' cleaning approach. Time to start the Endpoint discovery process
27 - The app will call the RSD discovery process on the following URLs: [https://www.cheonghyun.com]
28 - Downloading the HTML content at the following URL: https://www.cheonghyun.com
29 - RSD endpoint found at the following address: https://www.cheonghyun.com/xmlrpc.php?rsd
30 - Downloading the RSD document...
31 - Extracting the XML-RPC Endpoint address from the RSD document
32 - Found the XML-RPC endpoint in the HTML document!!!
33 - Trying system.listMethods on the following URL: https://www.cheonghyun.com/xmlrpc.php
34 - No documented SNI support on Android <4.2, trying with reflection
35 - Established TLSv1.2 connection with www.cheonghyun.com using TLS_RSA_WITH_AES_128_CBC_SHA
36 - No HTTP error document document from the server
37 - system.listMethods failed on: https://www.cheonghyun.com/xmlrpc.php - exception: HTTP status code: 500 was returned. Internal Server Error
38 - StackTrace: org.xmlrpc.android.XMLRPCException: HTTP status code: 500 was returned. Internal Server Error
	at org.xmlrpc.android.XMLRPCClient$Caller.callXMLRPC(XMLRPCClient.java:547)
	at org.xmlrpc.android.XMLRPCClient$Caller.access$000(XMLRPCClient.java:430)
	at org.xmlrpc.android.XMLRPCClient.call(XMLRPCClient.java:231)
	at org.xmlrpc.android.XMLRPCClient.call(XMLRPCClient.java:226)
	at org.xmlrpc.android.XMLRPCUtils.doSystemListMethodsXMLRPC(XMLRPCUtils.java:96)
	at org.xmlrpc.android.XMLRPCUtils.checkXMLRPCEndpointValidity(XMLRPCUtils.java:203)
	at org.xmlrpc.android.XMLRPCUtils.discoverSelfHostedXmlrpcUrl(XMLRPCUtils.java:393)
	at org.xmlrpc.android.XMLRPCUtils.verifyOrDiscoverXmlRpcUrl(XMLRPCUtils.java:257)
	at org.wordpress.android.ui.accounts.helpers.FetchBlogListWPOrg$FetchBlogListTask.doInBackground(FetchBlogListWPOrg.java:55)
	at org.wordpress.android.ui.accounts.helpers.FetchBlogListWPOrg$FetchBlogListTask.doInBackground(FetchBlogListWPOrg.java:35)
	at android.os.AsyncTask$2.call(AsyncTask.java:287)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
	at java.util.concurrent.FutureTask.run(FutureTask.java:137)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
	at java.lang.Thread.run(Thread.java:856)
...

The application log tells that the engine causes an internal server error (500) while loading xmlrpc.php. To find out the detail, I looked into the error.log from Apache Engine. We can acquire error.log from /var/log/apache2/error.log on Ubuntu.

[Sun Oct 16 23:29:00.403764 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP Fatal error:  Call to undefined function xml_parser_create() in /var/www/html_main/wp-includes/class-IXR.php on line 264
[Sun Oct 16 23:29:00.403882 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP Stack trace:
[Sun Oct 16 23:29:00.403896 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   1. {main}() /var/www/html_main/xmlrpc.php:0
[Sun Oct 16 23:29:00.403913 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   2. wp_xmlrpc_server->serve_request() /var/www/xmlrpc.php:84
[Sun Oct 16 23:29:00.403922 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   3. IXR_Server->IXR_Server() /var/www/wp-includes/class-wp-xmlrpc-server.php:197
[Sun Oct 16 23:29:00.403930 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   4. IXR_Server->__construct() /var/www/wp-includes/class-IXR.php:440
[Sun Oct 16 23:29:00.403938 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   5. IXR_Server->serve() /var/www/wp-includes/class-IXR.php:432
[Sun Oct 16 23:29:00.403945 2016] [:error] [pid 2200] [client CLIENT_IP:PORT] PHP   6. IXR_Message->parse() /var/www/wp-includes/class-IXR.php:464

According to the stack trace of error.log, the engine causes an error on processing messages and related functions.

Solution

Install the correct version of xml and xmlrpc Apache2 Module

As I stated in the beginning, I solved the login issue by installing the correct version of xml and xmlrpc module. The command line is as follows:

sudo apt-get install php5.6-xml
sudo apt-get install php5.6-xmlrpc
sudo service apache2 restart

The installation commands above depends on the php version and .htaccess configuration you are using. You can find out the current php version by creating a simple php file on your web server with the following script. Please note that the php version you installed on Apache engine and the version that you are currently using can be different.

<?php echo phpversion(); ?>

If the php version is 5.6, you can use the installation command above to solve it. (As mentioned above, you can use php -v to find out the php version from the web server engine, but the php version you are actually using can be different by .htaccess configuration or others. Therefore, checking version using php file may be more accurate than checking the php engine version.)

Reinstalling xml, xmlrpc

Some websites stated that they solved the login issue by reinstalling xml and xmlrpc modules [1, 2]. You can check the installed modules by using “php -m”.

[PHP Modules]
calendar
Core
ctype
date
...
tokenizer
wddx
xdebug
xml
xmlreader
xmlrpc
xmlwriter
zlib

If there is no xml or xmlrpc module in the list, install the module using the following command:

sudo apt-get install php-xml
sudo apt-get install php-xmlrpc

If the problem persists, reinstall the module using the following command:

sudo apt-get purge php-xml
sudo apt-get purge php-xmlrpc

.htaccess Accesss Right and PHP Version

The problem could be the access right of xmlrpc.php [3]. If this was the cause, your server would return 403 Forbidden error, rather than I mentioned above. Please modify .htaccess as follows:

<Files xmlrpc.php>
    Order allow,deny
    Allow from all
</Files>

Sometimes the problem could be the php version; you can modify the php version you wish to use by creating .htaccess file as follows (php 5.6):

# Use PHP5.6 as default
AddHandler application/x-httpd-php56 .php

References

[1] Alexander, “Fixing Errors «Jetpack: site_inaccessible,» zakharovlx.com, 08-Apr-2016. [Online]. Available: https://zakharovlx.com/category/dev/wordpress/.
[2] http://tecfused.com/, “PHP Fatal error: Uncaught Error: Call to undefined function xml_parser_create(),” tecfused.com, 08-Sep-2016. [Online]. Available: http://www.tecfused.com/2016/09/php-fatal-error-uncaught-error-call-undefined-function-xml_parser_create/.
[3] JigmeDatse, “[Resolved] The Jetpack server was unable to communicate with your site [HTTP 500],” WordPress.org, 22-Sep-2016. [Online]. Available: https://wordpress.org/support/topic/the-jetpack-server-was-unable-to-communicate-with-your-site-http-500/.

PortFast, BPDU Guard, BPDU Filtering, and UplinkFast

BPDU (Bridge Protocol Data Unit): A specialized frame to transfer the spanning tree information in 801.d STP (Spanning Tree Protocol).
RSTP (IEEE 802.w, Rapid Spanning Tree Protocol): A standard protocol revised from STP (Spanning Tree Protocol).

RSTP and STP Port States

Operational State STP State (802.1d) RSTP State (802.1w) Forwards Data Frames?
Enabled Blocking Discarding No
Enabled Listening Discarding No
Enabled Learning Learning No
Enabled Forwarding Forwarding Yes
Disabled Disabled Discarding No

PortFast

PortFast is Cisco’s technology to speed up convergence for access ports when they become active. PortFast mode supports only nontrunking access ports which do not transmit or receive BPDUs for preventing loops occured in a network. The following shows how to enable portfast on Cisco switch:

Switch> enable
Switch# configure terminal
Switch (config)# interface fastEthernet 0/1
Switch (config-if)# spanning-tree portfast

BPDU Guard

Portfast BPDU guard prevents loops by moving a nontrunking port into an errdisable state when a BPDU is received on that port. By enabling BPDU guard, spanning tree shuts down Portfast-enabled interfaces instead of putting them into the spanning tree blocking state.

BPDU Filtering

BPDU filtering allows to avoid transmitting BPDUs on Portfast-enabled ports that are connected to end system. By enabling Portfast on the switch, spanning tree places ports in the forwarding state immediately, instead of going through the listening, learning, and forwarding states.

UplinkFast

Uplinkfast provides fast convergence using uplink groups in the network access layer after a spanning tree topology change. An uplink group is a set of ports (per VLAN), only one of which is forwarding at any given time. Specifically, an uplink group consists of the root port (which is forwarding) and a set of blocked ports (not including self-looped ports). The uplink group provides an alternate path in case the currently forwarding link fails.

References

Cisco Systems, Inc. “Configuring Spanning Tree PortFast, BPDU Guard, BPDU Filter, UplinkFast, BackboneFast, and Loop Guard.” In Catalyst 4500 Series, Catalyst 2948G, Catalyst 2948G-GE-TX, and Catalyst 2980G Switches Software Configuration Guide, 8.1-8.20, 2007. http://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst4000/8-2glx/configuration/guide/stp_enha.html.

[Utility] DirectDraw Compatibility Tool: resolve graphics problem on old games

If you are experiencing an graphics issue (i.e., unexpected rainbow color on screen) on playing old games on operating systems newer than those games (such as StarCraft), you can fix this issue using DirectDraw Compatibility Tool.

The solution of the issue is simple. Please download and run "DirectDraw_Compatibility_Tool.exe" linked below, select the executable file of the game, and click "Apply"

The principle of the solution stated above is adding registry value to resolve compatibiliity problem of DirectDraw. For Starcraft, you can temporarily resolve the color issue by exiting explorer.exe process during the gameplay.

Because the root cause of this problem is from the compatibility issue of ddraw.dll with Windows 7, you may try to replace ddraw.dll with another that the compability issue is resolved. However, you may try this approach with your own risk because you need to replace the system dll file.

Note: I cannot guarantee the last solution of replacing ddraw.dll because I naver tried it. The ddraw.dll is located on C:\Windows\System32.

Download DirectDraw Compatibility Tool
DirectDraw_Compatibility_Tool_1.01.rar

Download modified ddraw.dll (mod)
ddhack10.rar