One place for hosting & domains

      How To Build a Slackbot in Python on Ubuntu 20.04


      The author selected the Tech Education Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Slack is a communication platform designed for workplace productivity. It includes features such as direct messaging, public and private channels, voice and video calls, and bot integrations. A Slackbot is an automated program that can perform a variety of functions in Slack, from sending messages to triggering tasks to alerting on certain events.

      In this tutorial you will build a Slackbot in the Python programming language. Python is a popular language that prides itself on simplicity and readability. Slack provides a rich Python Slack API for integrating with Slack to perform common tasks such as sending messages, adding emojis to messages, and much more. Slack also provides a Python Slack Events API for integrating with events in Slack, allowing you to perform actions on events such as messages and mentions.

      As a fun proof-of-concept that will demonstrate the power of Python and its Slack APIs, you will build a CoinBot—a Slackbot that monitors a channel and, when triggered, will flip a coin for you. You can then modify your CoinBot to fulfill any number of slightly more practical applications.

      Note that this tutorial uses Python 3 and is not compatible with Python 2.

      Prerequisites

      In order to follow this guide, you’ll need:

      • A Slack Workspace that you have the ability to install applications into. If you created the workspace you have this ability. If you don’t already have one, you can create one on the Slack website.

      • (Optional) A server or computer with a public IP address for development. We recommend a fresh installation of Ubuntu 20.04, a non-root user with sudo privileges, and SSH enabled. You can follow this guide to initialize your server and complete these steps.

      You may want to test this tutorial on a server that has a public IP address. Slack will need to be able to send events such as messages to your bot. If you are testing on a local machine you will need to port forward traffic through your firewall to your local system. If you are looking for a way to develop on a cloud server, check out this tutorial on How To Use Visual Studio Code for Remote Development via the Remote-SSH Plugin.

      Step 1 — Creating the Slackbot in the Slack UI

      First create your Slack app in the Slack API Control Panel. Log in to your workspace in Slack via a web browser and navigate to the API Control Panel. Now click on the Create an App button.

      Create Your Slack App

      Next you’ll be prompted for the name of your app and to select a development Slack workspace. For this tutorial, name your app CoinBot and select a workspace you have admin access to. Once you have done this click on the Create App button.

      Name Your Slack App and Select a Workspace

      Once your app is created you’ll be presented with the following default app dashboard. This dashboard is where you manage your app by setting permissions, subscribing to events, installing the app into workspaces, and more.

      Default Slack App Panel

      In order for your app to be able to post messages to a channel you need to grant the app permissions to send messages. To do this, click the Permissions button in the control panel.

      Select the Permissions Button in the Control Panel

      When you arrive at the OAuth & Permissions page, scroll down until you find the Scopes section of the page. Then find the Bot Token Scopes subsection in the scope and click on Add an OAuth Scope button.

      Select the Add an OAuth Scope Button

      Click on that button and then type chat:write. Select that permission to add it to your bot. This will allow the app to post messages to channels that it can access. For more information on the available permissions refer to Slack’s Documentation.

      Add the chat:write Permission

      Now that you’ve added the appropriate permission it is time to install your app into your Slack workspace. Scroll back up on the OAuth & Permissions page and click the Install App to Workspace button at the top.

      Install App to Workspace

      Click this button and review the actions that the app can perform in the channel. Once you are satisfied, click the Allow button to finish the installation.

      Install App to Workspace

      Once the bot is installed you’ll be presented with a Bot User OAuth Access Token for your app to use when attempting to perform actions in the workspace. Go ahead and copy this token; you’ll need it later.

      Save the Access Token

      Finally, add your newly installed bot into a channel within your workspace. If you haven’t created a channel yet you can use the #general channel that is created by default in your Slack workspace. Locate the app in the Apps section of the navigation bar in your Slack client and click on it. Once you’ve done that open the Details menu in the top right hand side. If your Slack client isn’t full-screened it will look like an i in a circle.

      Click on the App Details Icon

      To finish adding your app to a channel, click on the More button represented by three dots in the details page and select Add this app to a channel…. Type your channel into the modal that appears and click Add.

      Add App to a Channel

      You’ve now successfully created your app and added it to a channel within your Slack workspace. After you write the code for your app it will be able to post messages in that channel. In the next section you’ll start writing the Python code that will power CoinBot.

      Step 2 — Setting Up Your Python Developer Environment

      First let’s set up your Python environment so you can develop the Slackbot.

      Open a terminal and install python3 and the relevant tools onto your system:

      • sudo apt install python3 python3-venv

      Next you will create a virtual environment to isolate your Python packages from the system installation of Python. To do this, first create a directory into which you will create your virtual environment. Make a new directory at ~/.venvs:

      Now create your Python virtual environment:

      • python3 -m venv ~/.venvs/slackbot

      Next, activate your virtual environment so you can use its Python installation and install packages:

      • source ~/.venvs/slackbot/bin/activate

      Your shell prompt will now show the virtual environment in parenthesis. It will look something like this:

      Now use pip to install the necessary Python packages into your virtual environment:

      • pip install slackclient slackeventsapi Flask

      slackclient and slackeventsapi facilitate Python’s interaction with Slack’s APIs. Flask is a popular micro web framework that you will use to deploy your app:

      Now that you have your developer environment set up, you can start writing your Python Slackbot:

      Step 3 — Creating the Slackbot Message Class in Python

      Messages in Slack are sent via a specifically formatted JSON payload. This is an example of the JSON that your Slackbot will craft and send as a message:

      {
         "channel":"channel",
         "blocks":[
            {
               "type":"section",
               "text":{
                  "type":"mrkdwn",
                  "text":"Sure! Flipping a coin....nn"
               }
            },
            {
               "type":"section",
               "text":{
                  "type":"mrkdwn",
                  "text":"*flips coin* The result is Tails."
               }
            }
         ]
      }
      

      You could manually craft this JSON and send it, but instead let’s build a Python class that not only crafts this payload, but also simulates a coin flip.

      First use the touch command to create a file named coinbot.py:

      Next, open this file with nano or your favorite text editor:

      Now add the following lines of code to import the relevant libraries for your app. The only library you need for this class is the random library from the Python Standard Library. This library will allow us to simulate a coin flip.

      Add the following lines to coinbot.py to import all of the necessary libraries:

      coinbot.py

      # import the random library to help us generate the random numbers
      import random
      

      Next, create your CoinBot class and an instance of this class
      to craft the message payload. Add the following lines to coinbot.py to create the CoinBot class:

      coinbot.py

      ...
      class CoinBot:
      

      Now indent by one and create the constants, constructors, and methods necessary for your class. First let’s create the constant that will hold the base of your message payload. This section specifies that this constant is of the section type and that the text is formatted via markdown. It also specifies what text you wish to display. You can read more about the different payload options in the official Slack message payload documentation.

      Append the following lines to coinbot.py to create the base template for the payload:

      coinbot.py

      ...
          # Create a constant that contains the default text for the message
          COIN_BLOCK = {
              "type": "section",
              "text": {
                  "type": "mrkdwn",
                  "text": (
                      "Sure! Flipping a coin....nn"
                  ),
              },
          }
      

      Next create a constructor for your class so that you can create a separate instance of your bot for every request. Don’t worry about memory overhead here; the Python garbage collector will clean up these instances once they are no longer needed. This code sets the recipient channel based on a parameter passed to the constructor.

      Append the following lines to coinbot.py to create the constructor:

      coinbot.py

      ...
          # The constructor for the class. It takes the channel name as the a
          # parameter and sets it as an instance variable.
          def __init__(self, channel):
              self.channel = channel
      

      Now write the code that simulates to flip a coin. We’ll randomly generate a one or zero, representing heads or tails respectively.

      Append the following lines to coinbot.py to simulate the coin flip and return the crafted payload:

      coinbot.py

      ...
          # Generate a random number to simulate flipping a coin. Then return the 
          # crafted slack payload with the coin flip message.
          def _flip_coin(self):
              rand_int =  random.randint(0,1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
      
              text = f"The result is {results}"
      
              return {"type": "section", "text": {"type": "mrkdwn", "text": text}},
      

      Finally, create a method that crafts and returns the entire message payload, including the data from your constructor, by calling your _flip_coin method.

      Append the following lines to coinbot.py to create the method that will generate the finished payload:

      coinbot.py

      ...
          # Craft and return the entire message payload as a dictionary.
          def get_message_payload(self):
              return {
                  "channel": self.channel,
                  "blocks": [
                      self.COIN_BLOCK,
                      *self._flip_coin(),
                  ],
              }
      

      You are now finished with the CoinBot class and it is ready for testing. Before continuing, verify that your finished file, coinbot.py, contains the following:

      coinbot.py

      # import the random library to help us generate the random numbers
      import random
      
      # Create the CoinBot Class
      class CoinBot:
      
          # Create a constant that contains the default text for the message
          COIN_BLOCK = {
              "type": "section",
              "text": {
                  "type": "mrkdwn",
                  "text": (
                      "Sure! Flipping a coin....nn"
                  ),
              },
          }
      
          # The constructor for the class. It takes the channel name as the a 
          # parameter and then sets it as an instance variable
          def __init__(self, channel):
              self.channel = channel
      
          # Generate a random number to simulate flipping a coin. Then return the 
          # crafted slack payload with the coin flip message.
          def _flip_coin(self):
              rand_int =  random.randint(0,1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
      
              text = f"The result is {results}"
      
              return {"type": "section", "text": {"type": "mrkdwn", "text": text}},
      
          # Craft and return the entire message payload as a dictionary.
          def get_message_payload(self):
              return {
                  "channel": self.channel,
                  "blocks": [
                      self.COIN_BLOCK,
                      *self._flip_coin(),
                  ],
              }
      

      Save and close the file.

      Now that you have a Python class ready to do the work for your Slackbot, let’s ensure that this class produces a useful message payload and that you can send it to your workspace.

      Step 4 — Testing Your Message

      Now let’s test that this class produces a proper payload. Create a file named
      coinbot_test.py:

      Now add the following code. Be sure to change the channel name in the instantiation of the coinbot class coin_bot = coinbot("#YOUR_CHANNEL_HERE"). This code will create a Slack client in Python that will send a message to the channel you specify that you have already installed the app into:

      coinbot_test.py

      from slack import WebClient
      from coinbot import CoinBot
      import os
      
      # Create a slack client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      
      # Get a new CoinBot
      coin_bot = CoinBot("#YOUR_CHANNEL_HERE")
      
      # Get the onboarding message payload
      message = coin_bot.get_message_payload()
      
      # Post the onboarding message in Slack
      slack_web_client.chat_postMessage(**message)
      

      Save and close the file.

      Before you can run this file you will need to export the Slack token that you saved in Step 1 as an environment variable:

      • export SLACK_TOKEN="your_bot_user_token"

      Now test this file and verify that the payload is produced and sent by running the following script in your terminal. Make sure that your virtual environment is activated. You can verify this by seeing the (slackbot) text at the front of your bash prompt. Run this command you will receive a message from your Slackbot with the results of a coin flip:

      Check the channel that you installed your app into and verify that your bot did indeed send the coin flip message. Your result will be heads or tails.

      Coin Flip Test

      Now that you’ve verified that your Slackbot can flip a coin, create a message, and deliver the message, let’s create a Flask to perpetually run this app and make it simulate a coin flip and share the results whenever it sees certain text in messages sent in the channel.

      Step 5 — Creating a Flask Application to Run Your Slackbot

      Now that you have a functioning application that can send messages to your Slack workspace, you need to create a long running process so your bot can listen to messages sent in the channel and reply to them if the text meets certain criteria. You’re going to use the Python web framework Flask to run this process and listen for events in your channel.

      In this section you will be running your Flask application from a server with a public IP address so that the Slack API can send you events. If you are running this locally on your personal workstation you will need to forward the port from your personal firewall to the port that will be running on your workstation. These ports can be the same, and this tutorial will be set up to use port 3000.

      First adjust your firewall settings to allow traffic through port 3000:

      Now check the status of ufw:

      You will see an output like this:

      Output

      Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 3000 ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) 3000 (v6) ALLOW Anywhere (v6)

      Now create the file for your Flask app. Name this file app.py:

      Next, open this file in your favorite text editor:

      Now add the following import statements. You’ll import the following libraries for the following reasons:

      • import os – To access environment variables
      • import logging – To log the events of the app
      • from flask import Flask – To create a Flask app
      • from slack import WebClient – To send messages via Slack
      • from slackeventsapi import SlackEventAdapter – To receive events from Slack and process them
      • from coinbot import CoinBot – To create an instance of your CoinBot and generate the message payload.

      Append the following lines to app.py to import all of the necessary libraries:

      app.py

      import os
      import logging
      from flask import Flask
      from slack import WebClient
      from slackeventsapi import SlackEventAdapter
      from coinbot import CoinBot
      

      Now create your Flask app and register a Slack Event Adapter to your Slack app at the /slack/events endpoint. This will create a route in your Slack app where Slack events will be sent and ingested. To do this you will need to get another token from your Slack app, which you will do later in the tutorial. Once you get this variable you will export it as an environment variable named SLACK_EVENTS_TOKEN. Go ahead and write your code to read it in when creating the SlackEventAdapter, even though you haven’t set the token yet.

      Append the following lines to app.py to create the Flask app and register the events adapter into this app:

      app.py

      ...
      # Initialize a Flask app to host the events adapter
      app = Flask(__name__)
      
      # Create an events adapter and register it to an endpoint in the slack app for event ingestion.
      slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)
      

      Next create a web client object that will allow your app to perform actions in the workspace, specifically to send messages. This is similar to what you did when you tested your coinbot.py file previously.

      Append the following line to app.py to create this slack_web_client:

      app.py

      ...
      # Initialize a Web API client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      

      Now create a function that can be called that will create an instance of CoinBot, and then use this instance to create a message payload and pass the message payload to the Slack web client for delivery. This function will take in a single parameter, channel, which will specify what channel receives the message.

      Append the following lines to app.py to create this function:

      app.py

      ...
      def flip_coin(channel):
          """Craft the CoinBot, flip the coin and send the message to the channel
          """
          # Create a new CoinBot
          coin_bot = CoinBot(channel)
      
          # Get the onboarding message payload
          message = coin_bot.get_message_payload()
      
          # Post the onboarding message in Slack
          slack_web_client.chat_postMessage(**message)
      

      Now that you have created a function to handle the messaging aspects of your app, create one that monitors Slack events for a certain action and then executes your bot. You’re going to configure your app to respond with the results of a simulated coin flip when it sees the phrase “Hey Sammy, Flip a coin”. You’re going to accept any version of this—case won’t prevent the app from responding.

      First decorate your function with the @slack_events_adapter.on syntax that allows your function to receive events. Specify that you only want the message events and have your function accept a payload parameter containing all of the necessary Slack information. Once you have this payload you will parse out the text and analyze it. Then, if it receives the activation phrase, your app will send the results of a simulated coin flip.

      Append the following code to app.py to receive, analyze, and act on incoming messages:

      app.py

      # When a 'message' event is detected by the events adapter, forward that payload
      # to this function.
      @slack_events_adapter.on("message")
      def message(payload):
          """Parse the message event, and if the activation string is in the text,
          simulate a coin flip and send the result.
          """
      
          # Get the event data from the payload
          event = payload.get("event", {})
      
          # Get the text from the event that came through
          text = event.get("text")
      
          # Check and see if the activation phrase was in the text of the message.
          # If so, execute the code to flip a coin.
          if "hey sammy, flip a coin" in text.lower():
              # Since the activation phrase was met, get the channel ID that the event
              # was executed on
              channel_id = event.get("channel")
      
              # Execute the flip_coin function and send the results of
              # flipping a coin to the channel
              return flip_coin(channel_id)
      

      Finally, create a main section that will create a logger so you can see the internals of your application as well as launch the app on your external IP address on port 3000. In order to ingest the events from Slack, such as when a new message is sent, you must test your application on a public-facing IP address.

      Append the following lines to app.py to set up your main section:

      app.py

      if __name__ == "__main__":
          # Create the logging object
          logger = logging.getLogger()
      
          # Set the log level to DEBUG. This will increase verbosity of logging messages
          logger.setLevel(logging.DEBUG)
      
          # Add the StreamHandler as a logging handler
          logger.addHandler(logging.StreamHandler())
      
          # Run your app on your externally facing IP address on port 3000 instead of
          # running it on localhost, which is traditional for development.
          app.run(host="0.0.0.0", port=3000)
      

      You are now finished with the Flask app and it is ready for testing. Before you move on verify that your finished file, app.py contains the following:

      app.py

      import os
      import logging
      from flask import Flask
      from slack import WebClient
      from slackeventsapi import SlackEventAdapter
      from coinbot import CoinBot
      
      # Initialize a Flask app to host the events adapter
      app = Flask(__name__)
      # Create an events adapter and register it to an endpoint in the slack app for event injestion.
      slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)
      
      # Initialize a Web API client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      
      def flip_coin(channel):
          """Craft the CoinBot, flip the coin and send the message to the channel
          """
          # Create a new CoinBot
          coin_bot = CoinBot(channel)
      
          # Get the onboarding message payload
          message = coin_bot.get_message_payload()
      
          # Post the onboarding message in Slack
          slack_web_client.chat_postMessage(**message)
      
      
      # When a 'message' event is detected by the events adapter, forward that payload
      # to this function.
      @slack_events_adapter.on("message")
      def message(payload):
          """Parse the message event, and if the activation string is in the text, 
          simulate a coin flip and send the result.
          """
      
          # Get the event data from the payload
          event = payload.get("event", {})
      
          # Get the text from the event that came through
          text = event.get("text")
      
          # Check and see if the activation phrase was in the text of the message.
          # If so, execute the code to flip a coin.
          if "hey sammy, flip a coin" in text.lower():
              # Since the activation phrase was met, get the channel ID that the event
              # was executed on
              channel_id = event.get("channel")
      
              # Execute the flip_coin function and send the results of
              # flipping a coin to the channel
              return flip_coin(channel_id)
      
      if __name__ == "__main__":
          # Create the logging object
          logger = logging.getLogger()
      
          # Set the log level to DEBUG. This will increase verbosity of logging messages
          logger.setLevel(logging.DEBUG)
      
          # Add the StreamHandler as a logging handler
          logger.addHandler(logging.StreamHandler())
      
          # Run our app on our externally facing IP address on port 3000 instead of
          # running it on localhost, which is traditional for development.
          app.run(host="0.0.0.0", port=3000)
      

      Save and close the file.

      Now that your Flask app is ready to serve your application let’s test it out.

      Step 6 — Running Your Flask App

      Finally, bring everything together and execute your app.

      First, add your running application as an authorized handler for your Slackbot.

      Navigate to the Basic Information section of your app in the Slack UI. Scroll down until you find the App Credentials section.

      Slack Signing Secret

      Copy the Signing Secret and export it as the environment variable SLACK_EVENTS_TOKEN:

      • export SLACK_EVENTS_TOKEN="MY_SIGNING_SECRET_TOKEN"

      With this you have all the necessary API tokens to run your app. Refer to Step 1 if you need a refresher on how to export your SLACK_TOKEN. Now you can start your app and verify that it is indeed running. Ensure that your virtual environment is activated and run the following command to start your Flask app:

      You will see an output like this:

      (slackbot) [20:04:03] sammy:coinbot$ python app.py
       * Serving Flask app "app" (lazy loading)
       * Environment: production
         WARNING: This is a development server. Do not use it in a production deployment.
         Use a production WSGI server instead.
       * Debug mode: off
       * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)
      

      To verify that your app is up, open a new terminal window and curl the IP address of your server with the correct port at /slack/events:

      • curl http://YOUR_IP_ADDRESS:3000/slack/events

      curl will return the following:

      Output

      These are not the slackbots you're looking for.

      Receiving the message These are not the slackbots you're looking for., indicates that your app is up and running.

      Now leave this Flask application running while you finish configuring your app in the Slack UI.

      First grant your app the appropriate permissions so that it can listen to messages and respond accordingly. Click on Event Subscriptions in the UI sidebar and toggle the Enable Events radio button.

      Enable Events Button

      Once you’ve done that, type in your IP address, port, and /slack/events endpoint into the Request URL field. Don’t forget the HTTP protocol prefix. Slack will make an attempt to connect to your endpoint. Once it has successfully done so you’ll see a green check mark with the word Verified next to it.

      Event Subscriptions Request URL

      Next, expand the Subscribe to bot events and add the message.channels permission to your app. This will allow your app to receive messages from your channel and process them.

      Subscribe to bot events permissions

      Once you’ve done this you will see the event listed in your Subscribe to bot events section. Next click the green Save Changes button in the bottom right hand corner.

      Confirm and Save changes

      Once you do this you’ll see a yellow banner across the top of the screen informing you that you need to reinstall your app for the following changes to apply. Every time you change permissions you’ll need to reinstall your app. Click on the reinstall your app link in this banner to reinstall your app.

      Reinstall your app banner

      You’ll be presented with a confirmation screen summarizing the permissions your bot will have and asking if you want to allow its installation. Click on the green Allow button to finish the installation process.

      Reinstall confirmation

      Now that you’ve done this your app should be ready. Go back to the channel that you installed CoinBot into and send a message containing the phrase Hey Sammy, Flip a coin in it. Your bot will flip a coin and reply with the results. Congrats! You’ve created a Slackbot!

      Hey Sammy, Flip a coin

      Conclusion

      Once you are done developing your application and you are ready to move it to production, you’ll need to deploy it to a server. This is necessary because the Flask development server is not a secure production environment. You’ll be better served if you deploy your app using a WSGI and maybe even securing a domain name and giving your server a DNS record. There are many options for deploying Flask applications, some of which are listed below:

      There are many more ways to deploy your application than just these. As always, when it comes to deployments and infrastucture, do what works best for you.

      In any case, you now have a Slackbot that you can use to flip a coin to help you make decisions, like what to eat for lunch.

      You can also take this base code and modify it to fit your needs, whether it be automated support, resource management, pictures of cats, or whatever you can think of. You can view the complete Python Slack API docs here.



      Source link

      How To Set Up a Node.js Application for Production on Ubuntu 20.04


      Not using Ubuntu 20.04?


      Choose a different version or distribution.

      Introduction

      Node.js is an open-source JavaScript runtime environment for building server-side and networking applications. The platform runs on Linux, macOS, FreeBSD, and Windows. Though you can run Node.js applications at the command line, this tutorial will focus on running them as a service. This means that they will restart on reboot or failure and are safe for use in a production environment.

      In this tutorial, you will set up a production-ready Node.js environment on a single Ubuntu 20.04 server. This server will run a Node.js application managed by PM2, and provide users with secure access to the application through an Nginx reverse proxy. The Nginx server will offer HTTPS using a free certificate provided by Let’s Encrypt.

      Prerequisites

      This guide assumes that you have the following:

      When you’ve completed the prerequisites, you will have a server serving your domain’s default placeholder page at https://example.com/.

      Step 1 — Installing Node.js

      Let’s begin by installing the latest LTS release of Node.js, using the NodeSource package archives.

      First, install the NodeSource PPA in order to get access to its contents. Make sure you’re in your home directory, and use curl to retrieve the installation script for the most recent LTS version of Node.js from its archives.

      • cd ~
      • curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh

      You can inspect the contents of this script with nano or your preferred text editor:

      When you’re done inspecting the script, run it under sudo:

      • sudo bash nodesource_setup.sh

      The PPA will be added to your configuration and your local package cache will be updated automatically. After running the setup script from Nodesource, you can install the Node.js package:

      To check which version of Node.js you have installed after these initial steps, type:

      Output

      v14.4.0

      Note: When installing from the NodeSource PPA, the Node.js executable is called nodejs, rather than node.

      The nodejs package contains the nodejs binary as well as npm, a package manager for Node modules, so you don’t need to install npm separately.

      npm uses a configuration file in your home directory to keep track of updates. It will be created the first time you run npm. Execute this command to verify that npm is installed and to create the configuration file:

      Output

      6.14.5

      In order for some npm packages to work (those that require compiling code from source, for example), you will need to install the build-essential package:

      • sudo apt install build-essential

      You now have the necessary tools to work with npm packages that require compiling code from source.

      With the Node.js runtime installed, let’s move on to writing a Node.js application.

      Step 2 — Creating a Node.js Application

      Let’s write a Hello World application that returns “Hello World” to any HTTP requests. This sample application will help you get Node.js set up. You can replace it with your own application — just make sure that you modify your application to listen on the appropriate IP addresses and ports.

      First, let’s create a sample application called hello.js:

      Insert the following code into the file:

      ~/hello.js

      const http = require('http');
      
      const hostname="localhost";
      const port = 3000;
      
      const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World!n');
      });
      
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
      });
      

      Save the file and exit the editor.

      This Node.js application listens on the specified address (localhost) and port (3000), and returns “Hello World!” with a 200 HTTP success code. Since we’re listening on localhost, remote clients won’t be able to connect to our application.

      To test your application, type:

      You will receive the following output:

      Output

      Server running at http://localhost:3000/

      Note: Running a Node.js application in this manner will block additional commands until the application is killed by pressing CTRL+C.

      To test the application, open another terminal session on your server, and connect to localhost with curl:

      • curl http://localhost:3000

      If you get the following output, the application is working properly and listening on the correct address and port:

      Output

      Hello World!

      If you do not get the expected output, make sure that your Node.js application is running and configured to listen on the proper address and port.

      Once you’re sure it’s working, kill the application (if you haven’t already) by pressing CTRL+C.

      Step 3 — Installing PM2

      Next let’s install PM2, a process manager for Node.js applications. PM2 makes it possible to daemonize applications so that they will run in the background as a service.

      Use npm to install the latest version of PM2 on your server:

      • sudo npm install pm2@latest -g

      The -g option tells npm to install the module globally, so that it’s available system-wide.

      Let’s first use the pm2 start command to run your application, hello.js, in the background:

      This also adds your application to PM2’s process list, which is outputted every time you start an application:

      Output

      ... [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ hello │ fork │ 0 │ online │ 0% │ 25.2mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

      As indicated above, PM2 automatically assigns an App name (based on the filename, without the .js extension) and a PM2 id. PM2 also maintains other information, such as the PID of the process, its current status, and memory usage.

      Applications that are running under PM2 will be restarted automatically if the application crashes or is killed, but we can take an additional step to get the application to launch on system startup using the startup subcommand. This subcommand generates and configures a startup script to launch PM2 and its managed processes on server boots:

      The last line of the resulting output will include a command to run with superuser privileges in order to set PM2 to start on boot:

      Output

      [PM2] Init System found: systemd sammy [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Run the command from the output, with your username in place of sammy:

      • sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      As an additional step, we can save the PM2 process list and corresponding environments:

      You have now created a systemd unit that runs pm2 for your user on boot. This pm2 instance, in turn, runs hello.js.

      Start the service with systemctl:

      • sudo systemctl start pm2-sammy

      If at this point you encounter an error, you may need to reboot, which you can achieve with sudo reboot.

      Check the status of the systemd unit:

      • systemctl status pm2-sammy

      For a detailed overview of systemd, please review Systemd Essentials: Working with Services, Units, and the Journal.

      In addition to those we have covered, PM2 provides many subcommands that allow you to manage or look up information about your applications.

      Stop an application with this command (specify the PM2 App name or id):

      Restart an application:

      • pm2 restart app_name_or_id

      List the applications currently managed by PM2:

      Get information about a specific application using its App name:

      The PM2 process monitor can be pulled up with the monit subcommand. This displays the application status, CPU, and memory usage:

      Note that running pm2 without any arguments will also display a help page with example usage.

      Now that your Node.js application is running and managed by PM2, let’s set up the reverse proxy.

      Step 4 — Setting Up Nginx as a Reverse Proxy Server

      Your application is running and listening on localhost, but you need to set up a way for your users to access it. We will set up the Nginx web server as a reverse proxy for this purpose.

      In the prerequisite tutorial, you set up your Nginx configuration in the /etc/nginx/sites-available/example.com file. Open this file for editing:

      • sudo nano /etc/nginx/sites-available/example.com

      Within the server block, you should have an existing location / block. Replace the contents of that block with the following configuration. If your application is set to listen on a different port, update the highlighted portion to the correct port number:

      /etc/nginx/sites-available/example.com

      server {
      ...
          location / {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      This configures the server to respond to requests at its root. Assuming our server is available at example.com, accessing https://example.com/ via a web browser would send the request to hello.js, listening on port 3000 at localhost.

      You can add additional location blocks to the same server block to provide access to other applications on the same server. For example, if you were also running another Node.js application on port 3001, you could add this location block to allow access to it via https://example.com/app2:

      /etc/nginx/sites-available/example.com — Optional

      server {
      ...
          location /app2 {
              proxy_pass http://localhost:3001;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Once you are done adding the location blocks for your applications, save the file and exit your editor.

      Make sure you didn’t introduce any syntax errors by typing:

      Restart Nginx:

      • sudo systemctl restart nginx

      Assuming that your Node.js application is running, and your application and Nginx configurations are correct, you should now be able to access your application via the Nginx reverse proxy. Try it out by accessing your server’s URL (its public IP address or domain name).

      Conclusion

      Congratulations! You now have your Node.js application running behind an Nginx reverse proxy on an Ubuntu 20.04 server. This reverse proxy setup is flexible enough to provide your users access to other applications or static web content that you want to share.



      Source link

      How To Create a Self-Signed SSL Certificate for Apache on CentOS 8


      Not using CentOS 8?


      Choose a different version or distribution.

      Introduction

      TLS, or “transport layer security” — and its predecessor SSL — are protocols used to wrap normal traffic in a protected, encrypted wrapper. Using this technology, servers can safely send information to their clients without their messages being intercepted or read by an outside party.

      In this guide, we will show you how to create and use a self-signed SSL certificate with the Apache web server on a CentOS 8 machine.

      Note: A self-signed certificate will encrypt communication between your server and its clients. However, because it is not signed by any of the trusted certificate authorities included with web browsers and operating systems, users cannot use the certificate to automatically validate the identity of your server. As a result, your users will see a security error when visiting your site.

      Because of this limitation, self-signed certificates are not appropriate for a production environment serving the public. They are typically used for testing, or for securing non-critical services used by a single user or a small group of users that can establish trust in the certificate’s validity through alternate communication channels.

      For a more production-ready certificate solution, check out Let’s Encrypt, a free certificate authority. You can learn how to download and configure a Let’s Encrypt certificate in our How To Secure Apache with Let’s Encrypt on CentOS 8 tutorial.

      Prerequisites

      Before starting this tutorial, you’ll need the following:

      • Access to a CentOS 8 server with a non-root, sudo-enabled user. Our Initial Server Setup with CentOS 8 guide can show you how to create this account.
      • You will also need to have Apache installed. You can install Apache using dnf:

        Enable Apache and start it using systemctl:

        • sudo systemctl enable httpd
        • sudo systemctl start httpd

        And finally, if you have a firewalld firewall set up, open up the http and https ports:

        • sudo firewall-cmd --permanent --add-service=http
        • sudo firewall-cmd --permanent --add-service=https
        • sudo firewall-cmd --reload

      After these steps are complete, be sure you are logged in as your non-root user and continue with the tutorial.

      Step 1 — Installing mod_ssl

      We first need to install mod_ssl, an Apache module that provides support for SSL encryption.

      Install mod_ssl with the dnf command:

      Because of a packaging bug, we need to restart Apache once to properly generate the default SSL certificate and key, otherwise we’ll get an error reading '/etc/pki/tls/certs/localhost.crt' does not exist or is empty.

      • sudo systemctl restart httpd

      The mod_ssl module is now enabled and ready for use.

      Step 2 — Creating the SSL Certificate

      Now that Apache is ready to use encryption, we can move on to generating a new SSL certificate. The certificate will store some basic information about your site, and will be accompanied by a key file that allows the server to securely handle encrypted data.

      We can create the SSL key and certificate files with the openssl command:

      • sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/pki/tls/private/apache-selfsigned.key -out /etc/pki/tls/certs/apache-selfsigned.crt

      After you enter the command, you will be taken to a prompt where you can enter information about your website. Before we go over that, let’s take a look at what is happening in the command we are issuing:

      • openssl: This is the command line tool for creating and managing OpenSSL certificates, keys, and other files.
      • req -x509: This specifies that we want to use X.509 certificate signing request (CSR) management. X.509 is a public key infrastructure standard that SSL and TLS adhere to for key and certificate management.
      • -nodes: This tells OpenSSL to skip the option to secure our certificate with a passphrase. We need Apache to be able to read the file, without user intervention, when the server starts up. A passphrase would prevent this from happening, since we would have to enter it after every restart.
      • -days 365: This option sets the length of time that the certificate will be considered valid. We set it for one year here. Many modern browsers will reject any certificates that are valid for longer than one year.
      • -newkey rsa:2048: This specifies that we want to generate a new certificate and a new key at the same time. We did not create the key that is required to sign the certificate in a previous step, so we need to create it along with the certificate. The rsa:2048 portion tells it to make an RSA key that is 2048 bits long.
      • -keyout: This line tells OpenSSL where to place the generated private key file that we are creating.
      • -out: This tells OpenSSL where to place the certificate that we are creating.

      Fill out the prompts appropriately. The most important line is the one that requests the Common Name. You need to enter either the hostname you’ll use to access the server by, or the public IP of the server. It’s important that this field matches whatever you’ll put into your browser’s address bar to access the site, as a mismatch will cause more security errors.

      The full list of prompts will look something like this:

      Country Name (2 letter code) [XX]:US
      State or Province Name (full name) []:Example
      Locality Name (eg, city) [Default City]:Example 
      Organization Name (eg, company) [Default Company Ltd]:Example Inc
      Organizational Unit Name (eg, section) []:Example Dept
      Common Name (eg, your name or your server's hostname) []:your_domain_or_ip
      Email Address []:webmaster@example.com
      

      Both of the files you created will be placed in the appropriate subdirectories of the /etc/pki/tls directory. This is a standard directory provided by CentOS for this purpose.

      Next we will update our Apache configuration to use the new certificate and key.

      Step 3 — Configuring Apache to Use SSL

      Now that we have our self-signed certificate and key available, we need to update our Apache configuration to use them. On CentOS, you can place new Apache configuration files (they must end in .conf) into /etc/httpd/conf.d and they will be loaded the next time the Apache process is reloaded or restarted.

      For this tutorial we will create a new minimal configuration file. If you already have an Apache <Virtualhost> set up and just need to add SSL to it, you will likely need to copy over the configuration lines that start with SSL, and switch the VirtualHost port from 80 to 443. We will take care of port 80 in the next step.

      Open a new file in the /etc/httpd/conf.d directory:

      • sudo vi /etc/httpd/conf.d/your_domain_or_ip.conf

      Paste in the following minimal VirtualHost configuration:

      /etc/httpd/conf.d/your_domain_or_ip.conf

      <VirtualHost *:443>
          ServerName your_domain_or_ip
          DocumentRoot /var/www/ssl-test
          SSLEngine on
          SSLCertificateFile /etc/pki/tls/certs/apache-selfsigned.crt
          SSLCertificateKeyFile /etc/pki/tls/private/apache-selfsigned.key
      </VirtualHost>
      

      Be sure to update the ServerName line to however you intend to address your server. This can be a hostname, full domain name, or an IP address. Make sure whatever you choose matches the Common Name you chose when making the certificate.

      The remaining lines specify a DocumentRoot directory to serve files from, and the SSL options needed to point Apache to our newly-created certificate and key.

      Now let’s create our DocumentRoot and put an HTML file in it just for testing purposes:

      • sudo mkdir /var/www/ssl-test

      Open a new index.html file with your text editor:

      • sudo vi /var/www/ssl-test/index.html

      Paste the following into the blank file:

      /var/www/ssl-test/index.html

      <h1>it worked!</h1>
      

      This is not a full HTML file, of course, but browsers are lenient and it will be enough to verify our configuration.

      Save and close the file, then check your Apache configuration for syntax errors by typing:

      • sudo apachectl configtest

      You may see some warnings, but as long as the output ends with Syntax OK, you are safe to continue. If this is not part of your output, check the syntax of your files and try again.

      When all is well, reload Apache to pick up the configuration changes:

      • sudo systemctl reload httpd

      Now load your site in a browser, being sure to use https:// at the beginning.

      You should see an error. This is normal for a self-signed certificate! The browser is warning you that it can’t verify the identity of the server, because our certificate is not signed by any of the browser’s known certificate authorities. For testing purposes and personal use this can be fine. You should be able to click through to advanced or more information and choose to proceed.

      After you do so, your browser will load the it worked! message.

      Note: if your browser doesn’t connect at all to the server, make sure your connection isn’t being blocked by a firewall. If you are using firewalld, the following commands will open ports 80 and 443:

      • sudo firewall-cmd --permanent --add-service=http
      • sudo firewall-cmd --permanent --add-service=https
      • sudo firewall-cmd --reload

      Next we will add another VirtualHost section to our configuration to serve plain HTTP requests and redirect them to HTTPS.

      Step 4 — Redirecting HTTP to HTTPS

      Currently, our configuration will only respond to HTTPS requests on port 443. It is good practice to also respond on port 80, even if you want to force all traffic to be encrypted. Let’s set up a VirtualHost to respond to these unencrypted requests and redirect them to HTTPS.

      Open the same Apache configuration file we started in previous steps:

      • sudo vi /etc/httpd/conf.d/your_domain_or_ip.conf

      At the bottom, create another VirtualHost block to match requests on port 80. Use the ServerName directive to again match your domain name or IP address. Then, use Redirect to match any requests and send them to the SSL VirtualHost. Make sure to include the trailing slash:

      /etc/httpd/conf.d/your_domain_or_ip.conf

      <VirtualHost *:80>
          ServerName your_domain_or_ip
          Redirect / https://your_domain_or_ip/
      </VirtualHost>
      

      Save and close this file when you are finished, then test your configuration syntax again, and reload Apache:

      • sudo apachectl configtest
      • sudo systemctl reload httpd

      You can test the new redirect functionality by visiting your site with plain http:// in front of the address. You should be redirected to https:// automatically.

      Conclusion

      You have now configured Apache to serve encrypted requests using a self-signed SSL certificate, and to redirect unecrypted HTTP requests to HTTPS.

      If you are planning on using SSL for a public website, you should look into purchasing a domain name and using a widely supported certificate authority such as Let’s Encrypt.

      For more information on using Let’s Encrypt with Apache, please read our How To Secure Apache with Let’s Encrypt on CentOS 8 tutorial.



      Source link