How to Do You Install Apache Tomcat on Ubuntu Linux?

Problem scenario
You want to install Apache Tomcat on Ubuntu Linux.  How do you do this?

Solution
There are three separate ways of doing this.
Possible solution #1: Run this command: sudo apt-get -y install tomcat8
Possible solution #2: See this posting.
Possible solution #3:  Use these directions with one modification:  Step #3 has a URL that needs to be replaced with this URL:  http://apache.mirrors.ionfish.org/tomcat/tomcat-8/v8.5.58/bin/apache-tomcat-8.5.58.tar.gz

How Do You Deploy Apache Tomcat in a Docker Instance in an AWS Ubuntu Linux Server?

Problem scenario
You want to deploy Apache Tomcat in a Docker container on an AWS instance of Ubuntu Linux.  How do you do this?

Solution
1.  Install Docker.  See this link if you need assistance.
2.  Start the Docker service with this command:  sudo service docker start
3.  Run these two commands:

docker pull consol/tomcat-8.0
docker run consol/tomcat-8.0

4.  The second of the above commands will appear to hang.  Start a new Putty session to the Ubuntu server.  Continue with the directions below and leave both Putty instances up.

docker ps -a  #get the alphanumeric Docker container ID
docker inspect -f format='{{.NetworkSettings.IPAddress}}' abcd1234

#where abcd1234 is the container ID found above

# Note the IP address of the second of the above commands  You will use it again soon.

5.  Optional step if you want to use the web UI of Tomcat.  Create a second Docker container with Nginx inside it, and configure Nginx as a load balancer to distribute traffic to the Tomcat instance.  Follow these directions if you want to do this.  For step #6.d. in those directions refers to IP addresses where you want the traffic to go to.  You will have one IP address to add in the upstream block.  It will appear after the word "server", and it will be a socket for the IP address obtained in step #4 above with a :8080 at the end.  For example, step 6.d. in the Nginx in a Docker Container as an HTTP Load Balancer directions will leave you with something like this at the end of the default.conf file:

upstream {
   server 172.17.0.2:8080;
}

6.  Optional step if you did step #5 above.  You'll need to stop and start the Nginx Docker container for it to take effect.  Test it by opening a web browser and going to the external IP address of the server with these docker containers.  To find this, on the back-end of the server and outside of a Docker container, run the command "curl http://icanhazip.com".  Open a web browser on a desktop that has access to this server, and go to the IP address obtained from the curl command above.

How Do You Configure Nginx in a Docker Container to Be an HTTP Load Balancer?

Updated on 11/7/17

Problem scenario

You want a computer server (e.g., an AWS instance) to be a reverse proxy (a type of landing page users do not see that acts as a portal).  You want it to relay traffic to other IP addresses.  How do you get a server with Docker to distribute traffic to other IP endpoints?

Solution
Prerequisites
This assumes that Docker has already been installed.  To install Docker on RedHat, see this link.  To install Docker on Ubuntu, see this link.  To install Docker on Linux SUSE, run this command "sudo zypper -n in docker".  If you need more directions for installing Docker, see this posting.

The caveat with Docker on Ubuntu (as of 9/6/17) is that the web servers on the back end must not be other Nginx instances in Docker.  If the servers the HTTP load balancer (running via Nginx in a Docker container) distributes to are Apache web servers, Tomcat instances in Docker, or other Nginx servers not running in Docker or Nginx in Docker containers running on a different Docker host, then there will not be a problem.

The Docker service should be running and have access to the internet.  You will need the FQDN or IP address of one or more of the web servers that the soon-to-be-created HTTP load balancer will distribute to.

Procedures
1.  Run a command like this to create the Docker container for the distributor (or HTTP load balancer) Nginx instance:

docker run --name docker-nginxbalancer --net=host nginx

2.  Use the command "docker ps -a" to find the Docker ID of the container created by the above command.

3.  Start the Docker container (e.g., with "docker start abcd1234" where abcd1234 is the container ID).

4.  Enter the Docker container with a command like this:  docker exec -it docker-nginxbalancer bash

5.  Once inside the container, use this command to enable text-editing capabilities: apt-get update; apt-get -y install vim

6.  Modify the default.conf file.
  a) vi /etc/nginx/conf.d/default.conf
  b) In the server {} section, underneath the "location / {" subsection, comment out these lines like this:

  # root /usr/share/nginx/html;
  # index index.html index.htm;

  c)  Do not comment out the "location / {" stanza itself.  Now add a new line under this stanza near the two commented-out lines (as seen above) with this content indented the same way as the original lines above were indented:

  proxy_pass http://backend;

  d) At the very bottom of the file, add these lines (but replace the IP addresses with the FQDNs or IP addresses you want traffic to go to) .

  upstream backend {
     server 10.10.0.1;
     server 10.10.0.2;
     server 10.10.0.3;
   }

  e)  You can have as few as one server stanza above.  The IP addresses can include port numbers (that is the IP address could be a socket) or be FQDNs instead of IP addresses or sockets.  The endpoints (corresponding to the IP addresses, sockets or FQDNs) can be Apache web servers, Nginx web servers, or Apache Tomcat servers. 

If the Docker host and web servers are all AWS instances, we recommend using the servers internal IP addresses (or single IP address if you only add one server to the default.conf upstream {} block).  The Docker container may be lost (inaccessible and will not start again until an AWS Security Group change is made) if you use an external IP address instead of an internal IP address.  The reason is that the Security Group(s) involved may not allow connections to external IP addresses from the external IP addresses.  Internal IP addresses are exempt from this potential Security Group problem.

Save the changes to the file (/etc/nginx/conf.d/default.conf) when you are done.  Then exit the Docker container.

7.  Stop the Docker container with Nginx. Start the Docker container.

FFR
If you want to need to troubleshoot problems with your Nginx load balancer, see this link.

How Do You Optimize a Website’s Performance That Is Running Nginx as a Load Balancer in a Docker Container?

Problem scenario
You want web page refreshes to happen more quickly for your website when a user clicks "Reload" in her web browser.  The website you manage is powered by Nginx configured as an HTTP load balancer (aka a reverse proxy).  This Nginx configuration is in a Docker container too. The rule you want is that clients' inbound connection requests from a specific IP address should be relayed to the same Nginx server every time that client reloads the web page in the web browser. You have an Nginx server configured as a reverse proxy (aka invisible landing page or pass-through router) distributing traffic to different Nginx web servers on the back-end.  You want to build an affinity based on specific IP addresses of the client workstations and relay them to the same Nginx page that serves the web pages.  This way from the front-end a user can click "refresh" or "reload" from her web browser and she will get the HTML pages from the same Nginx server each time she clicks that.  You know that client refreshes will happen much faster if this Nginx tuning is implemented. What do you do to achieve this improved performance?

Solution
You will want traffic to be routed based on the IP address of the client and not the round-robin technique.  You will not want to use the "route to server with fewest active connections" rule either (via the least_conn directive). 

If the client's machine changes its external IP address, this solution will not work. Normally during a web browsing session, a workstation's external IP address will not change.  When creating the Docker container that will serve as the HTTP load balancer, do not assign it a port-mapping, a subnet, nor an IP address.    

1.  Run a command like this to create the Docker container for the distributor (or HTTP load balancer) Nginx instance:

docker run --name docker-nginxbalancer --net=host nginx

2.  Use the command docker ps -a to find the Docker ID of the container created by the above command.

3.  Start the Docker container (e.g., with docker start abcd1234 where abcd1234 is the container ID).

4.  Enter the Docker container with a command like this:  docker exec -it docker-nginxbalancer bash

5.  Once inside the container, use this command to enable text-editing capabilities: apt-get update; apt-get -y install vim

6.  Modify the default.conf file.
a) vi /etc/nginx/conf.d/default.conf
b) Comment out in the server {} section these lines under the "location / {" section like this:

# root /usr/share/nginx/html;
# index index.html index.htm;

c)  Do not comment out the "location / {" stanza itself.  Do add a line under this stanza near the two commented-out lines (as seen above) with this content indented the same way as the original lines above were indented:

proxy_pass http://backend;

d) At the very bottom of the file, add these lines (but replace the IP addresses below with the Nginx web servers' FQDNs or their IP addresses directly):

upstream backend {
   ip_hash;
   server 10.10.0.1;
   server 10.10.0.2;
   server 10.10.0.3;
}

7.  Stop the Docker container and restart it. If it does not come back, are you sure you did not create the Docker container with a user-defined network and an IP address?  Using "docker run" and signifying an --ip flag and --network flag with a user-defined network can make the Docker container never start again if the ip_hash directive is used in the "upstream backend" block of the default.conf file.  Such configuration (with a user-defined network and ip address) is appropriate for Docker containers with regular Nginx web servers.  Nginx as a load balancer should not be in a Docker container with a user-defined network or an assigned IP address.

8.  Test it by going to the external IP address of the Docker server in a web browser.  Click refresh and everytime you should be getting the web page from the same Nginx server.  If you are used to Nginx in Docker containers on an EC-2 (AWS) instance, you should notice that the  refresh happens much faster!

Closing Tip
If you created the Docker container with Nginx with a subnet mask and IP address, it will not work as the HTTP balancer.  Such containers are fine for supporting Nginx web servers that can participate in an HTTP load balancer.  They are not acceptable as the distributor/balancer Nginx instance itself. 

FFR
If you want to need to troubleshoot problems with your Nginx load balancer, see this link.

How Do You Use the ip_hash Directive in Nginx Running in Docker and Be Able to Stop and Start the Docker Container Again?

Problem scenario
You are using Nginx as a reverse proxy (a server that is essentially a landing page that is invisible to users and passes connection requests to other web servers like a router).  You noticed that when you added the "ip_hash;" directive in the "upstream server {}" section (also known as a block) of the /etc/nginx/conf.d/default.conf file, you lose the Docker container.  That is if you stop the Docker container once the Nginx default.conf file has this "ip_hash;" directive, the Docker container cannot be  restarted again.  What did you do wrong?

Solution
You may have created the Docker container with a user-defined network and IP address.  The Docker container that would have an Nginx default.conf file to receive an ip_hash directive would be a load balancer (or traffic distributor).  Such an Nginx instance distributes traffic and does not act as a web page.  This requires a special way of creating the Docker container with the "docker run" command.

Here is a command to create a Docker container with Nginx that will work as the load balancer:

docker run --name docker-nginxbalancer --net=host nginx

Notice there are no -p flags to configure port mapping, no user-defined networks and no IP addresses in this command.  These three things would be customary for Nginx instances that will render HTML (regular web servers) and be put in the load balancer (in the Nginx default.conf file in the upstream backend {} section thereof).

How Do You Set up Nginx as an HTTP Load Balancer So Client Requests (from Web Browsers) Do Not Go to Nginx Servers That Have Failed Several Times in Recent Attempts?

Problem scenario
To improve performance of your HTTP load balancing mechanism, you want to configure how failed members of the load balancer are dealt with. Some Nginx instances may fail in your environment. You do not want attempts to send web traffic to these instances immediately after several failures.  How do you granularly keep track of failed attempts and remove the instance from the distribution algorithm after a certain limit has been reach to improve performance by attempting only more reliable instances?

Solution
Prerequisite

You must have configured Nginx as a an HTTP load balancer (or reverse proxy server).  To do this, see this article which will actually work for Nginx distributing traffic to regular Nginx websites, Apache websites, or Nginx websites running in Docker containers. 

Procedures
Use Nginx's built-in "max_fails" and "fail_timeout" directives in the default.conf file.  These reserved words can allow you to easily configure a threshold of failures and a duration that the server should not be tried again.  Depending on your environment and how quickly the Nginx server usually returns to being operational, you can adjust accordingly.  Here is an example snippet from the default.conf file:

upstream backend {
  server 10.10.10.10 max_fails=5  fail_timeout=20s;
  server 10.10.10.11 max_fails=5  fail_timeout=20s;
  server 10.10.10.12 max_fails=10  fail_timeout=5s;
  server 10.10.10.13 max_fails=2  fail_timeout=100s;
}

These max_fails and fail_timeout settings work with Nginx in Docker no differently from Nginx running on a server directly.  The default timeout is 10 seconds (according to DigitalOcean's website).

How Do You Deploy Several Docker Containers with Nginx and Have Each of Them Work Simultaneously on a Single RedHat Server?

Problem scenario
You want to create several Docker containers each supporting Nginx.  You want to be able to browse to the different instances of Nginx from a web browser.  How do you have multiple Docker containers support Nginx on one RedHat Enterprise Linux host server?

Solution
These directions are geared toward a RHEL host server instance in AWS.

#1 Install Docker. For directions, see this link or this link.

#2 Configure a user defined network in Docker.  From the Linux server, run this command:

ip addr show # or "ip addr show | grep eth0"

Look at the results for eth0.  Find its "inet" IP address and subnet mask (e.g., 172.31.38.151/20). This is the internal IP address of the Docker server and its subnet mask in shorthand notation.  To determine the IP address of this Docker network you will create, mentally increment the last octet's integer value by 1 and keep the subnet mask, unless it is 32, for the construction of a command below.  If the last octet in the IP address is 255 and mathematically adding 1 to it will put the number above 255, find an addressable IP number not being used and within the subnet mask for the server's IP address.  (For example, you may have to increment the third octet by 1 and have the final octet be 0 or 1.)  If the subnet mask is /32, use "24" as the subnet mask for the command below (docker network create...).  If you are using Google Cloud Platform, the IP address will likely start with a 10 (the first octet will not be a 172). 

Run a command like the following, however you may want to substitute "isolated_nw1" with the name of your choice for this user-defined network.  You must substitute x.x.x.x in the draft of the command below with the IP address this network will have (possibly as simple as one greater than the last octet of the server's internal IP address).  You will likely substitute 20 with the subnet mask short hand notation that the server's internal IP address has.  

docker network create --driver bridge isolated_nw1 --subnet x.x.x.x/20

The resulting command was you substitute properly may look like this:

docker network create --driver bridge isolated_nw1 --subnet 172.31.38.152/20

Take a note of this IP address and mentally increment the last octet one more time for future usage.  You'll use that IP address later for a Docker container.

#3 Make sure the Security Group allows the Docker server to reach the internet.  If you aren't using AWS, make sure the firewall allows you to reach the internet.

#4 Run a command like this but with a different IP address:

docker run --name docker-nginx1 -p 8123:80 --network=isolated_nw1 --ip 172.31.58.153 nginx

# Substitute 172.31.58.153 with the IP address referred to in the final two sentences of step #2.  
# The IP address you choose should be visible to the subnet that you created in step #2 given the network's IP address subnet mask.  
# This IP address should also be unique to the Linux server itself.
# Change the 8123 to the TCP port of your choice. It must be unique among the containers you create with the above commands.
# Change "docker-nginx1" to the name of the container you want; it must be unique to the server itself.
# Change "isolated_nw1" to the name of the subnet mask you created earlier.
# If you prefer to not use the public nginx image, replace the "nginx" at the end with the repository name and tag of the image you want to use.  To find the repository name and tag, run a "docker images" command.  The results will have several columns; the two left-most columns will have the repository name and tag to use for any given image.

# If the command hangs after you press enter, use ctrl-c.  In our experience, the Docker container is successfully created despite not gracefully returning to the command prompt as you would normally expect.  To read about other people's experiences of the command hanging, see this link or this Docker link.

#5  Run this command to find the Docker ID: docker ps -a

#6  Start this new Docker container.  docker start <dockerID from command above>

#7 This step assumes that your Security Group has outbound connections open for the port you configured in step #4 (the left of the colon one) to the IP address of your desktop.  Open a web browser from your desktop computer.  Type in the external IP address of the Docker server with a ":8123" at the end (where 8123 is the port you used to the left of the colon in step #4's -p flag).  The URL may look like this in Chrome or Firefox:  172.31.38.151:8123

You should see "Welcome to Nginx!" in the web browser display.  You can create many different Docker containers with Nginx each working on one host server as long as the containers have these three things:
    1) names that are unique to the host server, as assigned by the --name flag in step #4.
    2) ports that are unique to the host server, as assigned left of the colon after the -p flag in step #4.
    3) a IP address that is unique to the host server, as assigned with the --ip flag in step #4.

Port 80 and the user-defined network name are things that can be be reused as you create permutations of step #4's command.  If you want confirmation you are reaching a given Docker container, modify the "Welcome to Nginx" file to something unique.  Then open a web browser and test it out.

If you don't know how to enter a Docker container, see this link. If you want to know where to find the file index.html in the container, see this link as it will be default.conf or nginx.conf. If you need to know how to get a text editor installed in a Docker container, see this link.

How Do You Have Text Fields That Have Hints (Suggested Text)?

Problem scenario
You are using PHP files (with HTML).  You have text fields that are blank by default.  These fields accept user input from the keyboard.  You want the clear text fields to have suggested text by default (to help explain to the user the type of input that is appropriate or to remind the user of content restrictions).  How do you do this?

You have a field that requests text like this HTML code (in a .php file):

<html>
<body>
<form action="anotherpage.php" method="post">

Type in text here: <input type="text" name="table"> <br>

</form>
</html>
</body>

Solution
Use the "placeholder" attribute (essentially a keyword) in this fashion (in a .php file):

<html>
<body>
<form action="anotherpage.php" method="post">

Type in text here: <input type="text" name="table" placeholder="Very cool text"> <br>

</form>
</html>
</body>

Now "very cool text" will be visible in light gray in the text field.  The "placeholder" attribute of an input tag will not work with IE version 9 or older versions.  This attribute was introduced in HTML5.  (To learn more, see this link.)  The text will not register as user text if the user does not modify the text.  The text will participate in the form as if field were empty or blank in this scenario.

If you want the default text in the field to participate in the form as if the user typed it in, this is possible.  The text will be black instead of light gray.  Use "value" instead of "placeholder" in the HTML code.

How Do You Install Octopus Deploy server to a Windows 2016 Server?

Problem scenario
You want to install Octuopus Deploy (e.g., with the 45 free trial) to an AWS instance of Windows Server 2016.  How do you do this?

Solution
This is a simple deployment of Octopus Deploy server for testing or evaluation purposes.  Literally any AWS flavor will work as only 512 MB of RAM is needed for Octopus Deploy server to work for minimal evaluation.

1.  Install SQL Server express.
  a) Using Internet Explorer 11, go to Internet Options.  Go to the Security tab.  Click on "Internet."  Scroll down to "Downloads."  For "File download" (beneath "Downloads"), choose "Enable."  Click "Ok" twice.
  b)  Go here.  Scroll 60% of the way down.  For the "SQL SErver 2016 SP1 Express" version, click "Download now."
  c) There will be a small pop up near the bottom of the browser.  Click "Run" to start.
  d) For the "installation type" choose "Basic."
  e) Read the license terms.  If you can agree, click "Accept."
  f) Leave the install location alone.  Click "Install."  
  g) You may encounter "Download successful" with an apparent pause of a couple minutes with little information about the progress of the installation.  The installation is not stuck.  Just be patient.  The installation process could take as much as 10 minutes.  At the end, choose the option "Install SSMS."
  h) Click the link for "Download SQL Server Management Studio 17.x."
  i) Click "Save"
  j) If you can agree to the License Terms and Privacy Statement, click "Install."
  h)  The process may take five to ten minutes.  At the end a restart will be required.  Click "Restart."

2.  When the server reboots, Open SSMS.  Right click "Databases" and click "New."  For the "Database name" enter "foroctopus."  Click "Ok."

3.  Install Octopus Deploy.
  a) (This first sub-step will allow the "Select platform" options buttons to actually appear in Internet Explorer 11. ) Using Internet Explorer 11, go to Internet Options.  Go to the Security tab.  Click on "Trusted sites."  Set the "Security level for this zone" to be "Medium-low."  Click "Sites" and add https://octopus.com.  Click ok.
  b) Download the Octopus Deploy MSI from this link: https://octopus.com/.  Click "Select platform" under "Octopus server."  Choose the option for Windows 64.  Click "Save" to the window prompt that pops up.
  c) Click "Run" once the .msi file has downloaded.
  d) In the Setup Wizard (for Octopus Deploy Server), click "Next."
  e) Read the End-User License Agreement.  If you can agree, check the box for "I accept the terms..." and click "Next."
  f)  For the folder path of where to install Octopus, accept the default location by just clicking "Next."
  g)  Click "Install."
  h)  After a couple minutes, click "Finish."
  i) At the "Welcome" screen, click "Get started."
  j) Type in the requested info.  You will need access to the email that is sent later on. Click the "Activate" button after you have typed in the information that they request.
  k) For the "Home" directory, leave the default and click "Next."
  l) Accept the default for the "Use Local System account" and click "Next."
  m) For the "Database" page, click the "Server name" field.  For the "Database" choose "foroctopus."
  n) Click "Next."
  o) You will get a pop up for "Add System account to Database."  The prompt will say "In order to allow Octopus...we need to grant database access to the 'NT AUTHORITY\SYSTEM' account..."  Click "OK" to grant access.
  p) For the "Web Portal" prompt, just click "Next."
  q) For the "Authentication" section, create an Octopus user with any username, password, and email of your choice.  You will need the username and password later. Click "Next."
  r) For "Installation" click "Install."  This may take over 10 minutes.  Be patient and eventually you will see "Installation successful. Happy deployments!"  Click Finish.
  s) You should see "Your Octopus server is ready to use!"  Click "Open in browser."  Internet Explorer will open.  This may take five minutes for the web UI to load.  You will see "The Octopus server is starting: Initializing database and performing migrations" and then a message about "Starting task scheduler."  Just wait.
  t) Enter the Username and Password you entered in step 2)q).  Click "Sign in."  This may take three to five minutes.

4) Undo the change made in step 3)a).  Undo the changes made in step 1)a) if you want your AWS Windows server to be very secure.  You are now done.