(Last Updated On: April 5, 2019)

In our last article, we covered installation of Semaphore Ansible Web UI on Debian/Ubuntu and CentOS Linux distributions. This guide will focus on installing and configuring Nginx as a reverse proxy for Semaphore Ansible Web UI.

The only pre-requisite for this setup are:

  • CentOS / RHEL / Ubuntu or Debian Linux distribution.
  • Installed and working Semaphore
  • User account with sudo privileges

Step 1: Install Semaphore Ansible Web UI

You should have installed Semaphore before proceeding with this setup. Use below guides for reference.

How to Setup Semaphore Ansible Web UI on Ubuntu / Debian

How to Install Semaphore Ansible Web UI on CentOS 7

Step 2: Install Nginx Web Server

Install Nginx Web server on your Semaphore server or a difference instance which will be used as proxy server for Semaphore.

# Install Nginx on Ubuntu / Debian
$ sudo apt-get -y install nginx

# Install Nginx on CentOS
$ sudo yum -y install nginx

Once the service is installed, start it and set to be started at system boot.

sudo systemctl start nginx
sudo systemctl enable nginx

Verify that status of nginx service is “running“.

$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2019-04-05 09:39:45 CEST; 8s ago
Docs: man:nginx(8)
Process: 12190 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 12189 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 12193 (nginx)
Tasks: 2 (limit: 4915)
CGroup: /system.slice/nginx.service
├─12193 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─12194 nginx: worker process
Apr 05 09:39:45 mydebian systemd[1]: Starting A high performance web server and a reverse proxy server…
Apr 05 09:39:45 mydebian systemd[1]: nginx.service: Failed to read PID from file /run/nginx.pid: Invalid argument
Apr 05 09:39:45 mydebian systemd[1]: Started A high performance web server and a reverse proxy server.

Step 3: Configure Nginx

Create semaphore nginx configuration file.

sudo vim /etc/nginx/conf.d/semaphore.conf

Paste below contents to the file.

upstream semaphore {
    server 127.0.0.1:3000;
  }

server {
  	listen 80;
  	server_name ansible.example.com;
    	client_max_body_size 0;
    	chunked_transfer_encoding on;

    location / {
      proxy_pass http://semaphore/;
      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_buffering off;
      proxy_request_buffering off;
    }

    location /api/ws {
      proxy_pass http://semaphore/api/ws;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Origin "";
    }
}

ansible.example.com should be change to match the domain you want to use.

Restart nginx

sudo systemctl restart nginx

If you don’t have DNS, add a line to your /etc/hosts file with Nginx server IP and host name.

192.168.10.15 ansible.example.com

You should be able to access semaphore web interface with domain name configured in Nginx http://ansible.example.com.

Step 4: Configure https

It is recommended to use SSL certificate in your Nginx configuration to secure access to semaphore. Let’s obtain Let’s Encrypt Certificate for this use.

Install certbot-auto:

sudo wget https://dl.eff.org/certbot-auto -P /usr/local/bin
chmod a+x /usr/local/bin/certbot-auto

Stop nginx service.

sudo systemctl stop nginx

Then request for Let’s Encrypt SSL certificates.

export DOMAIN="ansible.example.com"
export EMAIL="[email protected]"
sudo certbot-auto certonly --standalone -d $DOMAIN --preferred-challenges http --agree-tos -n -m $EMAIL --keep-until-expiring

You should get output similar to this:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ansible.computingforgeeks.com
Waiting for verification…
Cleaning up challenges
IMPORTANT NOTES:
Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/ansible.computingforgeeks.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/ansible.computingforgeeks.com/privkey.pem
Your cert will expire on 2019-07-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot-auto
again. To non-interactively renew all of your certificates, run
"certbot-auto renew"
Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

Configure Nginx with SSL settings.

upstream semaphore {
    server 127.0.0.1:3000;
  }

server {
  	listen 80;
  	server_name ansible.example.com;
        return 301 https://$host$request_uri;
}

server {
  	listen 443 ssl;
  	server_name ansible.example.com;
 	# add Strict-Transport-Security to prevent man in the middle attacks
    	add_header Strict-Transport-Security "max-age=31536000" always;

    	# SSL
    	ssl_certificate /etc/letsencrypt/live/ansible.example.com/fullchain.pem;
    	ssl_certificate_key /etc/letsencrypt/live/ansible.example.com/privkey.pem;
  
 	# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
    	ssl_protocols TLSv1.1 TLSv1.2;
    	ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    	ssl_prefer_server_ciphers on;
    	ssl_session_cache shared:SSL:10m;
  
    	# disable any limits to avoid HTTP 413 for large image uploads
    	client_max_body_size 0;
  
    	# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
    	chunked_transfer_encoding on;

    location / {
      proxy_pass http://semaphore/;
      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_buffering off;
      proxy_request_buffering off;
    }

    location /api/ws {
      proxy_pass http://semaphore/api/ws;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Origin "";
    }
}

Replace example.com with your domain name.

Validate Nginx configuration.

# nginx  -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart Nginx

sudo systemctl restart nginx

Access Semaphore console via https://example.com:

You now have a secure access to Semaphore Ansible Web UI with host name instead of access through an IP address and port 3000.