{"id":2506,"date":"2015-02-19T13:33:06","date_gmt":"2015-02-19T11:33:06","guid":{"rendered":"https:\/\/upcloud.com\/global\/us\/resources\/tutorials\/configure-load-balancing-nginx\/"},"modified":"2026-04-23T13:51:04","modified_gmt":"2026-04-23T12:51:04","slug":"configure-load-balancing-nginx","status":"publish","type":"tutorial","link":"https:\/\/upcloud.com\/global\/resources\/tutorials\/configure-load-balancing-nginx\/","title":{"rendered":"How to configure load balancing using Nginx"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Advantages of load balancing<\/h2>\n\n\n\n<p>Load balancing is an excellent way to scale out your application and increase its performance&nbsp;and redundancy. Nginx, a popular web server software, can be configured as a simple yet powerful load balancer to improve your server&#8217;s&nbsp;resource availability and efficiency.<\/p>\n\n\n\n<p>How does Nginx work? Nginx creates a single entry point for a distributed web application that works on multiple servers.<\/p>\n\n\n\n<p>This guide&nbsp;describes the advantages of load balancing. Learn how to set up load balancing with nginx for your cloud servers.<\/p>\n\n\n\n<p>As a prerequisite, you\u2019ll need to have at least two hosts with web server software installed and configured to see the benefit of the load balancer. If you already have one web host set up, duplicate&nbsp;it by <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/custom-server-images\/\">creating a custom image<\/a> and deploying it onto a new server at your <a href=\"https:\/\/hub.upcloud.com\/\" target=\"_blank\" rel=\"noopener\">UpCloud Control Panel<\/a>.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">Installing nginx<\/h2>\n\n\n\n<p>The first thing to do is set up a new host to serve as your load balancer. Deploy a new instance at your UpCloud Control Panel if you haven\u2019t already. Nginx packages are available in the latest versions of CentOS, Debian, and Ubuntu. So pick whichever of these you prefer.<\/p>\n\n\n\n<p>After setting up the server how you like, install the latest stable nginx. Use one of the following methods.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Debian and Ubuntu\nsudo apt-get update\n# Then install the Nginx Open Source edition\nsudo apt-get install nginx<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># CentOS\n# Install the extra packages repository\nsudo yum install epel-release\n# Update the repositories and install Nginx\nsudo yum update\nsudo yum install nginx<\/pre>\n\n\n\n<p>Once installed, change the directory to the nginx main configuration folder.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/etc\/nginx\/<\/pre>\n\n\n\n<p>Depending on your OS, the web server configuration files will be in one of two places.<\/p>\n\n\n\n<p>Ubuntu and Debian follow a rule for storing virtual host files in&nbsp;<tt>\/etc\/nginx\/sites-available\/<\/tt>, which are enabled through symbolic links to&nbsp;<tt>\/etc\/nginx\/sites-enabled\/<\/tt>. You can use the command below to enable any new virtual host files.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo ln -s \/etc\/nginx\/sites-available\/<span style=\"color: #ff0000\">vhost<\/span>&nbsp;\/etc\/nginx\/sites-enabled\/<span style=\"color: #ff0000\">vhost<\/span><\/pre>\n\n\n\n<p>CentOS users can find their host configuration files under \/etc\/nginx\/conf.d\/ in which any <em>.conf<\/em>&nbsp;type virtual host file gets loaded.<\/p>\n\n\n\n<p>Check that you find at least the default configuration, and then restart nginx.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl restart nginx<\/pre>\n\n\n\n<p>Test that the server replies to HTTP requests. Open the load balancer server\u2019s public IP address in your web browser. When you see the default welcoming page for nginx, the installation is successful.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/nginx-welcome-page.png\" alt=\"Nginx default welcome page.\"\/><\/figure>\n\n\n\n<p>If you have trouble loading the page, check that a firewall is not blocking your connection. For example on CentOS 7 the default firewall rules do not allow HTTP traffic, enable it with the commands below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo firewall-cmd --add-service=http --permanent\nsudo firewall-cmd --reload<\/pre>\n\n\n\n<p>Then, try reloading your browser.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/signup.upcloud.com\/\">Try UpCloud for free!<\/a><\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring nginx as a load balancer<\/h2>\n\n\n\n<p>When nginx is installed and tested, start to configure it for load balancing. In essence, all you need to do is set up Nginx with instructions on which type of connections to listen to and where to redirect them. Create a new configuration file using whichever text editor you prefer. For example, with <em>nano<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo nano \/etc\/nginx\/conf.d\/load-balancer.conf<\/pre>\n\n\n\n<p>In the <em>load-balancer.conf<\/em><span style=\"margin: 0px;padding: 0px\"><em>,<\/em>&nbsp;you\u2019ll need to define the following two segments:&nbsp;<em>upstream<\/em>&nbsp;and&nbsp;<em>server.<\/em>&nbsp;See<\/span> the examples below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Define which servers to include in the load balancing scheme. \n# It's best to use the servers' private IPs for better performance and security.\n# You can find the private IPs at your <a href=\"https:\/\/hub.upcloud.com\/networks\/private\" target=\"_blank\" rel=\"noopener\">UpCloud control panel<\/a> Network section.\nhttp {\n   upstream backend {\n      server 10.1.0.101; \n      server 10.1.0.102;\n      server 10.1.0.103;\n   }\n\n   # This server accepts all traffic to port 80 and passes it to the upstream. \n   # Notice that the upstream name and the proxy_pass need to match.\n\n   server {\n      listen 80; \n\n      location \/ {\n          proxy_pass http:\/\/backend;\n      }\n   }\n}<\/pre>\n\n\n\n<p>Then, save the file and exit the editor.<\/p>\n\n\n\n<p>Next, disable the default server configuration you tested earlier that was working after the installation. Again, this part differs slightly depending on your OS.<\/p>\n\n\n\n<p>On Debian and Ubuntu systems, you\u2019ll need to remove the <em>default<\/em> symbolic link from the <em>sites-enabled<\/em> folder.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo rm \/etc\/nginx\/sites-enabled\/default<\/pre>\n\n\n\n<p>CentOS hosts don\u2019t use the same linking. Instead, simply rename the <em>default.conf<\/em> in the <em>conf.d\/<\/em> directory to something that doesn\u2019t end with <em>.conf<\/em>, for example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo mv \/etc\/nginx\/conf.d\/default.conf \/etc\/nginx\/conf.d\/default.conf.disabled<\/pre>\n\n\n\n<p>Then, use the following to restart nginx.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl restart nginx<\/pre>\n\n\n\n<p>Check that nginx starts successfully. If the restart fails, take a look at the&nbsp; <em>\/etc\/nginx\/conf.d\/load-balancer.conf<\/em> you just created to make sure there are no mistypes or missing semicolons.<\/p>\n\n\n\n<p>When you enter the load balancer\u2019s public IP address in your web browser, you should pass it to one of your back-end servers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Load balancing methods<\/h2>\n\n\n\n<p>Load balancing with&nbsp;nginx uses a round-robin algorithm by default if no other method is defined, like in the first example above.&nbsp;With a round-robin scheme,&nbsp;each server is selected&nbsp;in turns according to the order you set them in the <em>load-balancer.conf<\/em>&nbsp;file. This balances the number of requests&nbsp;equally for short operations.<\/p>\n\n\n\n<p>Least connections-based load balancing is another straightforward method. As the name suggests, this method directs the requests to the server with the least active connections at that time. It works more fairly than round-robin with applications where requests sometimes take longer to complete.<\/p>\n\n\n\n<p><span style=\"margin: 0px;padding: 0px\">Add the parameter&nbsp;<em>least_conn<\/em>&nbsp;to your&nbsp;<em>upstream<\/em>&nbsp;section to enable the least connections balancing method<\/span>, as shown in the example below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">upstream backend {\n   least_conn;\n   server 10.1.0.101; \n   server 10.1.0.102;\n   server 10.1.0.103;\n}<\/pre>\n\n\n\n<p>Round-robin and least connections balancing schemes are fair and have their uses. However, they cannot provide session persistence. If your web application requires that the users are subsequently directed to the same back-end server as during their previous connection, use the IP hashing method instead. IP hashing uses the visitor&#8217;s IP address to determine which host should be selected to service the request. This allows the visitors to be directed to the same server each time, granted that the server is available and the visitor\u2019s IP address hasn\u2019t changed.<\/p>\n\n\n\n<p>To use this method, add the <em>ip_hash<\/em> -parameter to your <em>upstream<\/em>&nbsp;segment, as in the example below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">upstream backend {\n   ip_hash;\n   server 10.1.0.101; \n   server 10.1.0.102;\n   server 10.1.0.103;\n}<\/pre>\n\n\n\n<p>In a server setup where the available resources between different hosts are unequal, favouring some servers over others might be desirable. Defining server weights allows you to fine-tune the load and further balance it with nginx. The server with the highest weight in the load balancer is selected the most often.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">upstream backend {\n   server 10.1.0.101 weight=4; \n   server 10.1.0.102 weight=2;\n   server 10.1.0.103;\n}<\/pre>\n\n\n\n<p>For example, in the configuration shown above, the first server is selected twice as often as the second, which again gets twice the requests compared to the third.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Load balancing with HTTPS enabled<\/h2>\n\n\n\n<p>Enable HTTPS for your site; it is a great way to protect your visitors and their data. If you haven\u2019t yet implemented\u00a0encryption on your web hosts, we highly recommend you look at our guide for\u00a0installing<a href=\"https:\/\/upcloud.com\/global\/resources\/tutorials\/install-lets-encrypt-nginx\/\" target=\"_blank\" rel=\"noreferrer noopener\">Let\u2019s Encrypt on nginx<\/a>.<\/p>\n\n\n\n<p>Using encryption with a load balancer is easier than you might think. All you need to do is add another server section to your load balancer configuration file that listens to HTTPS traffic at port 443 with SSL. Then, set up a proxy_pass to your upstream segment, like with the HTTP in the previous example above.<\/p>\n\n\n\n<p>Open your configuration file again for editing.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo nano \/etc\/nginx\/conf.d\/load-balancer.conf<\/pre>\n\n\n\n<p>Then, add the following server segment to the end of the file.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">server {\n   listen 443 ssl;\n &nbsp; server_name <span style=\"color: #ff0000\">domain_name<\/span>;\n &nbsp; ssl_certificate \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000\">domain_name<\/span>\/cert.pem;\n   ssl_certificate_key \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000\">domain_name<\/span>\/privkey.pem;\n   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n\n &nbsp; location \/ {\n &nbsp; &nbsp; &nbsp;proxy_pass http:\/\/backend;\n &nbsp; }\n}<\/pre>\n\n\n\n<p>Then, save the file, exit the editor, and restart Nginx.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl restart nginx<\/pre>\n\n\n\n<p>Setting up encryption at your load balancer when you are using private network connections to your back end has some great advantages.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As only your UpCloud servers have access to your private network, you can terminate the SSL at the load balancer and thus only pass forward HTTP connections.<\/li>\n\n\n\n<li>It also greatly simplifies your certificate management. You can obtain and renew the certificates from a single host.<\/li>\n<\/ul>\n\n\n\n<p>With the HTTPS-enabled, you can enforce encryption on all connections to your load balancer. Simply update your server segment by listening to port 80 with a server name and a redirection to your HTTPS port. Then, remove or comment out the <em>location<\/em> portion as it\u2019s no longer needed. See the example below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">server {\n&nbsp; &nbsp;listen 80;\n&nbsp; &nbsp;server_name <span style=\"color: #ff0000\">domain_name<\/span>;\n&nbsp; &nbsp;return 301 https:\/\/$server_name$request_uri;\n\n   #location \/ {\n &nbsp; #&nbsp; &nbsp;proxy_pass http:\/\/backend;\n &nbsp; #}\n}<\/pre>\n\n\n\n<p>Save the file again after you have made the changes. Then restart nginx.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl restart nginx<\/pre>\n\n\n\n<p>Now, all connections to your load balancer will be served over an encrypted HTTPS connection. Requests to the unencrypted HTTP will be redirected to use HTTPS as well. This provides a seamless transition into encryption. Nothing is required from your visitors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Health checks<\/h2>\n\n\n\n<p>Nginx\u2019s reverse proxy implementations include passive server health checks to determine which servers are available. If a server fails to respond to a request or replies with an error, nginx will note that it has failed and try to avoid forwarding connections to that server for a time.<\/p>\n\n\n\n<p>The number of consecutive unsuccessful connection attempts within a certain time period can be defined in the load balancer configuration file. Set a parameter max_fails to the server lines. By default, when no max_fails is specified,&nbsp;this value is set to 1. Optionally, setting&nbsp;max_fails&nbsp;to 0 will disable health checks for that server.<\/p>\n\n\n\n<p>If <em>max_fails<\/em> is set to a value greater than 1, subsequent fails must happen within a specific time frame for them to count. This time frame is specified by a parameter, <em>fail_timeout<\/em>, which also defines how long the server should be considered failed. By default, the <em>fail_timeout<\/em> is set to 10 seconds.<\/p>\n\n\n\n<p>After a server is marked failed and the time&nbsp;set by <em>fail_timeout<\/em> has passed, nginx will begin gracefully probing the server with client requests. If the probes return successful, the server is again marked live and included in the load balancing as normal.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">upstream backend {\n   server 10.1.0.101 weight=5;\n   server 10.1.0.102 max_fails=3 fail_timeout=30s;\n   server 10.1.0.103;\n}<\/pre>\n\n\n\n<p>Use the health checks. They allow you to adapt your server back-end to the current demand by powering up or down hosts as required. Adding more servers during high traffic can easily increase your application performance as new resources become automatically available to your load balancer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusions on the advantages of load balancing<\/h2>\n\n\n\n<p>If you wish to improve your web application performance and availability, a load balancer is definitely something to consider. Nginx is powerful yet relatively simple to set up to load balance a web server. Together with an easy encryption solution, such as the Let\u2019s Encrypt client, it makes for a great front-end to your web farm. Check out <a rel=\"noopener\" href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html\" target=\"_blank\">the documentation for upstream<\/a> over at nginx.org to learn more.<\/p>\n\n\n\n<p>When you use multiple hosts, the load balancer protects your web service with redundancy, but the load balancer itself can still leave a single point of failure. You can improve high availability by setting up a floating IP between multiple load balancers. Check out our article about <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/floating-ip-addresses\/\">floating IPs on UpCloud<\/a> to learn more.<\/p>\n","protected":false},"author":3,"featured_media":27387,"comment_status":"open","ping_status":"closed","template":"","community-category":[274,259],"class_list":["post-2506","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2506","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/types\/tutorial"}],"author":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/comments?post=2506"}],"version-history":[{"count":2,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2506\/revisions"}],"predecessor-version":[{"id":6415,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2506\/revisions\/6415"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/media?parent=2506"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/community-category?post=2506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}