One place for hosting & domains

      Ubuntu

      How To Configure Jenkins with SSL Using an Nginx Reverse Proxy on Ubuntu 20.04


      Not using Ubuntu 20.04?


      Choose a different version or distribution.

      Introduction

      By default, Jenkins comes with its own built-in Winstone web server listening on port 8080, which is convenient for getting started. It’s also a good idea, however, to secure Jenkins with SSL to protect passwords and sensitive data transmitted through the web interface.

      In this tutorial, you will configure Nginx as a reverse proxy to direct client requests to Jenkins.

      Prerequisites

      To begin, you’ll need the following:

      Step 1 — Configuring Nginx

      In the prerequisite tutorial How to Secure Nginx with Let’s Encrypt on Ubuntu 20.04, you configured Nginx to use SSL in the /etc/nginx/sites-available/example.com file. Open this file to add your reverse proxy settings:

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

      In the server block with the SSL configuration settings, add Jenkins-specific access and error logs:

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

      . . . 
      server {
              . . .
              # SSL Configuration
              #
              listen [::]:443 ssl ipv6only=on; # managed by Certbot
              listen 443 ssl; # managed by Certbot
              access_log            /var/log/nginx/jenkins.access.log;
              error_log             /var/log/nginx/jenkins.error.log;
              . . .
              }
      

      Next let’s configure the proxy settings. Since we’re sending all requests to Jenkins, we’ll comment out the default try_files line, which would otherwise return a 404 error before the request reaches Jenkins:

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

      . . .
                 location / {
                      # First attempt to serve request as file, then
                      # as directory, then fall back to displaying a 404.
                      # try_files $uri $uri/ =404;        }
      . . . 
      

      Let’s now add the proxy settings, which include:

      • proxy_params: The /etc/nginx/proxy_params file is supplied by Nginx and ensures that important information, including the hostname, the protocol of the client request, and the client IP address, is retained and available in the log files.
      • proxy_pass: This sets the protocol and address of the proxied server, which in this case will be the Jenkins server accessed via localhost on port 8080.
      • proxy_read_timeout: This enables an increase from Nginx’s 60 second default to the Jenkins-recommended 90 second value.
      • proxy_redirect: This ensures that responses are correctly rewritten to include the proper host name.

      Be sure to substitute your SSL-secured domain name for example.com in the proxy_redirect line below:

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

      Location /  
      . . .
                 location / {
                      # First attempt to serve request as file, then
                      # as directory, then fall back to displaying a 404.
                      # try_files $uri $uri/ =404;
                      include /etc/nginx/proxy_params;
                      proxy_pass          http://localhost:8080;
                      proxy_read_timeout  90s;
                      # Fix potential "It appears that your reverse proxy setup is broken" error.
                      proxy_redirect      http://localhost:8080 https://example.com;
      

      Once you’ve made these changes, save the file and exit the editor. We’ll hold off on restarting Nginx until after we’ve configured Jenkins, but we can test our configuration now:

      If all is well, the command will return:

      Output

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

      If not, fix any reported errors until the test passes.

      Note:
      If you misconfigure the proxy_pass (by adding a trailing slash, for example), you will get something similar to the following in your Jenkins Configuration page.

      Jenkins error: Reverse proxy set up is broken

      If you see this error, double-check your proxy_pass and proxy_redirect settings in the Nginx configuration.

      Step 2 — Configuring Jenkins

      For Jenkins to work with Nginx, you will need to update the Jenkins configuration so that the Jenkins server listens only on the localhost interface rather than on all interfaces (0.0.0.0). If Jenkins listens on all interfaces, it’s potentially accessible on its original, unencrypted port (8080).

      Let’s modify the /etc/default/jenkins configuration file to make these adjustments:

      • sudo nano /etc/default/jenkins

      Locate the JENKINS_ARGS line and add --httpListenAddress=127.0.0.1 to the existing arguments:

      /etc/default/jenkins

      . . .
      JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT --httpListenAddress=127.0.0.1"
      

      Save and exit the file.

      To use the new configuration settings, restart Jenkins:

      • sudo systemctl restart jenkins

      Since systemctl doesn’t display output, check the status:

      • sudo systemctl status jenkins

      You should see the active (exited) status in the Active line:

      Output

      ● jenkins.service - LSB: Start Jenkins at boot time Loaded: loaded (/etc/init.d/jenkins; generated) Active: active (exited) since Mon 2018-07-09 20:26:25 UTC; 11s ago Docs: man:systemd-sysv-generator(8) Process: 29766 ExecStop=/etc/init.d/jenkins stop (code=exited, status=0/SUCCESS) Process: 29812 ExecStart=/etc/init.d/jenkins start (code=exited, status=0/SUCCESS)

      Restart Nginx:

      • sudo systemctl restart nginx

      Check the status:

      • sudo systemctl status nginx

      Output

      ● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2018-07-09 20:27:23 UTC; 31s ago Docs: man:nginx(8) Process: 29951 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited, status=0/SUCCESS) Process: 29963 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 29952 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 29967 (nginx)

      With both servers restarted, you should be able to visit the domain using either HTTP or HTTPS. HTTP requests will be redirected automatically to HTTPS, and the Jenkins site will be served securely.

      Step 3 — Testing the Configuration

      Now that you have enabled encryption, you can test the configuration by resetting the administrative password. Let’s start by visiting the site via HTTP to verify that you can reach Jenkins and are redirected to HTTPS.

      In your web browser, enter http://example.com, substituting your domain for example.com. After you press ENTER, the URL should start with https and the location bar should indicate that the connection is secure.

      You can enter the administrative username you created in How To Install Jenkins on Ubuntu 20.04 in the User field, and the password that you selected in the Password field.

      Once logged in, you can change the password to be sure it’s secure.

      Click on your username in the upper-right-hand corner of the screen. On the main profile page, select Configure from the list on the left side of the page:

      Navigate to Jenkins password page

      This will take you to a new page, where you can enter and confirm a new password:

      Jenkins create password page

      Confirm the new password by clicking Save. You can now use the Jenkins web interface securely.

      Conclusion

      In this tutorial, you configured Nginx as a reverse proxy to Jenkins’ built-in web server to secure your credentials and other information transmitted via the web interface. Now that Jenkins is secure, you can learn how to set up a continuous integration pipeline to automatically test code changes. Other resources to consider if you are new to Jenkins are the Jenkins project’s “Creating your first Pipeline” tutorial or the library of community-contributed plugins.



      Source link

      How To Install WordPress on Ubuntu 20.04 with a LAMP Stack


      Not using Ubuntu 20.04?


      Choose a different version or distribution.

      Introduction

      WordPress is an extremely popular open-source technology for making websites and blogs on the internet today. Used by 63% of all websites that use a content management system (CMS), WordPress sites represent 36% of all websites that are currently online.

      There are many different approaches to getting access to WordPress and some setup processes are more complex than others. This tutorial is intended for those who desire to install and administer a WordPress instance on an unmanaged cloud server via the command line. Though this approach requires more steps than a ready-made WordPress installation, it offers administrators greater control over their WordPress environment.

      If you are looking to access a ready-made WordPress installation, DigitalOcean Marketplace offers a one-click app to get you started with WordPress through installation when spinning up your server.

      Depending on your needs and goals, you may find other options that are more suitable. As open-source software, WordPress can be freely downloaded and installed, but to be available on the web, you will likely need to purchase cloud infrastructure and a domain name. Continue following this guide if you are interested in working through the server-side installation and set up of a WordPress site.

      This tutorial will be using a LAMP (Linux, Apache, MySQL, and PHP) stack, which is one option for a server architecture that supports WordPress by providing the Linux operating system, Apache web server, MySQL database, and PHP programming language. We’ll install and set up WordPress via LAMP on a Linux Ubuntu 20.04 server.

      Prerequisites

      In order to complete this tutorial, you will need access to an Ubuntu 20.04 server and will need to complete these steps before beginning this guide:

      • Set up your server by following our Ubuntu 20.04 initial server setup guide, and ensure you have a non-root sudo user.
      • Install a LAMP stack by following our LAMP guide to install and configure this software.
      • Secure your site: WordPress takes in user input and stores user data, so it is important for it to have a layer of security. TLS/SSL is the technology that allows you to encrypt the traffic from your site so that your and your users’ connection is secure. Here are two options available to you to meet this requirement:
        • If you have a domain name… you can secure your site with Let’s Encrypt, which provides free, trusted certificates. Follow our Let’s Encrypt guide for Apache to set this up.
        • If you do not have a domain… and you are just using this configuration for testing or personal use, you can use a self-signed certificate instead. This provides the same type of encryption, but without the domain validation. Follow our self-signed SSL guide for Apache to get set up.

      When you are finished with the setup steps, log into your server as your sudo user and continue below.

      Step 1 — Creating a MySQL Database and User for WordPress

      The first step that we will take is a preparatory one. WordPress uses MySQL to manage and store site and user information. We have MySQL installed already, but we need to make a database and a user for WordPress to use.

      To get started, log into the MySQL root (administrative) account by issuing this command (note that this is not the root user of your server):

      You will be prompted for the password you set for the MySQL root account when you installed the software.

      Note: If you cannot access your MySQL database via root, as a sudo user you can update your root user’s password by logging into the database like so:

      Once you receive the MySQL prompt, you can update the root user’s password. Here, replace new_password with a strong password of your choosing.

      • ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'new_password';

      You may now type EXIT; and can log back into the database via password with the following command:

      Within the database, we can create an exclusive database for WordPress to control. You can call this whatever you would like, but we will be using the name wordpress in this guide. Create the database for WordPress by typing:

      • CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

      Note: Every MySQL statement must end in a semi-colon (;). Check to make sure this is present if you are running into any issues.

      Next, we are going to create a separate MySQL user account that we will use exclusively to operate our new database. Creating specific databases and accounts can support us from a management and security standpoint. We will use the name wordpressuser in this guide, but feel free to use whatever name is relevant for you.

      We are going to create this account, set a password, and grant access to the database we created. We can do this by typing the following command. Remember to choose a strong password here for your database user where we have password:

      • CREATE USER 'wordpressuser'@'%' IDENTIFIED WITH mysql_native_password BY 'password';

      Next, let the database know that our wordpressuser should have complete access to the database we set up:

      • GRANT ALL ON wordpress.* TO 'wordpressuser'@'%';

      You now have a database and user account, each made specifically for WordPress. We need to flush the privileges so that the current instance of MySQL knows about the recent changes we’ve made:

      Exit out of MySQL by typing:

      In the next step, we’ll lay some foundations for WordPress plugins by downloading PHP extensions for our server.

      Step 2 — Installing Additional PHP Extensions

      When setting up our LAMP stack, we only required a very minimal set of extensions in order to get PHP to communicate with MySQL. WordPress and many of its plugins leverage additional PHP extensions.

      We can download and install some of the most popular PHP extensions for use with WordPress by typing:

      • sudo apt update
      • sudo apt install php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip

      This will lay the groundwork for installing additional plugins into our WordPress site.

      Note: Each WordPress plugin has its own set of requirements. Some may require additional PHP packages to be installed. Check your plugin documentation to discover its PHP requirements. If they are available, they can be installed with apt as demonstrated above.

      We will need to restart Apache to load these new extensions, we’ll be doing more configurations on Apache in the next section, so you can wait until then, or restart now to complete the PHP extension process.

      • sudo systemctl restart apache2

      Step 3 — Adjusting Apache’s Configuration to Allow for .htaccess Overrides and Rewrites

      Next, we will be making a few minor adjustments to our Apache configuration. Based on the prerequisite tutorials, you should have a configuration file for your site in the /etc/apache2/sites-available/ directory.

      In this guide, we’ll use /etc/apache2/sites-available/wordpress.conf as an example here, but you should substitute the path to your configuration file where appropriate. Additionally, we will use /var/www/wordpress as the root directory of our WordPress install. You should use the web root specified in your own configuration. If you followed our LAMP tutorial, it may be your domain name instead of wordpress in both of these instances.

      Note: It’s possible you are using the 000-default.conf default configuration (with /var/www/html as your web root). This is fine to use if you’re only going to host one website on this server. If not, it’s better to split the necessary configuration into logical chunks, one file per site.

      With our paths identified, we can move onto working with .htaccess so that Apache can handle configuration changes on a per-directory basis.

      Enabling .htaccess Overrides

      Currently, the use of .htaccess files is disabled. WordPress and many WordPress plugins use these files extensively for in-directory tweaks to the web server’s behavior.

      Open the Apache configuration file for your website with a text editor like nano.

      • sudo nano /etc/apache2/sites-available/wordpress.conf

      To allow .htaccess files, we need to set the AllowOverride directive within a Directory block pointing to our document root. Add the following block of text inside the VirtualHost block in your configuration file, making sure to use the correct web root directory:

      /etc/apache2/sites-available/wordpress.conf

      <Directory /var/www/wordpress/>
          AllowOverride All
      </Directory>
      

      When you are finished, save and close the file. In nano, you can do this by pressing CTRL and X together, then Y, then ENTER.

      Enabling the Rewrite Module

      Next, we can enable mod_rewrite so that we can utilize the WordPress permalink feature:

      This allows you to have more human-readable permalinks to your posts, like the following two examples:

      http://example.com/2012/post-name/
      http://example.com/2012/12/30/post-name
      

      The a2enmod command calls a script that enables the specified module within the Apache configuration.

      Enabling the Changes

      Before we implement the changes we’ve made, check to make sure we haven’t made any syntax errors by running the following test.

      • sudo apache2ctl configtest

      You may receive output like the following:

      Output

      AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message Syntax OK

      If you wish to suppress the top line, just add a ServerName directive to your main (global) Apache configuration file at /etc/apache2/apache2.conf. The ServerName can be your server’s domain or IP address. This is just a message, however, and doesn’t affect the functionality of your site. As long as the output contains Syntax OK, you are ready to continue.

      Restart Apache to implement the changes. Make sure to restart now even if you have restarted earlier in this tutorial.

      • sudo systemctl restart apache2

      Next, we will download and set up WordPress itself.

      Step 4 — Downloading WordPress

      Now that our server software is configured, we can download and set up WordPress. For security reasons in particular, it is always recommended to get the latest version of WordPress from their site.

      Change into a writable directory (we recommend a temporary one like /tmp) and download the compressed release.

      • cd /tmp
      • curl -O https://wordpress.org/latest.tar.gz

      Extract the compressed file to create the WordPress directory structure:

      We will be moving these files into our document root momentarily. Before we do, we can add a dummy .htaccess file so that this will be available for WordPress to use later.

      Create the file by typing:

      • touch /tmp/wordpress/.htaccess

      We’ll also copy over the sample configuration file to the filename that WordPress reads:

      • cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php

      We can also create the upgrade directory, so that WordPress won’t run into permissions issues when trying to do this on its own following an update to its software:

      • mkdir /tmp/wordpress/wp-content/upgrade

      Now, we can copy the entire contents of the directory into our document root. We are using a dot at the end of our source directory to indicate that everything within the directory should be copied, including hidden files (like the .htaccess file we created):

      • sudo cp -a /tmp/wordpress/. /var/www/wordpress

      Ensure that you replace the /var/www/wordpress directory with the directory you have set up on your server.

      Step 5 — Configuring the WordPress Directory

      Before we do the web-based WordPress setup, we need to adjust some items in our WordPress directory.

      Adjusting the Ownership and Permissions

      An important step that we need to accomplish is setting up reasonable file permissions and ownership.

      We’ll start by giving ownership of all the files to the www-data user and group. This is the user that the Apache web server runs as, and Apache will need to be able to read and write WordPress files in order to serve the website and perform automatic updates.

      Update the ownership with the chown command which allows you to modify file ownership. Be sure to point to your server’s relevant directory.

      • sudo chown -R www-data:www-data /var/www/wordpress

      Next we’ll run two find commands to set the correct permissions on the WordPress directories and files:

      • sudo find /var/www/wordpress/ -type d -exec chmod 750 {} ;
      • sudo find /var/www/wordpress/ -type f -exec chmod 640 {} ;

      These permissions should get you working effectively with WordPress, but note that some plugins and procedures may require additional tweaks.

      Setting Up the WordPress Configuration File

      Now, we need to make some changes to the main WordPress configuration file.

      When we open the file, our first task will be to adjust some secret keys to provide a level of security for our installation. WordPress provides a secure generator for these values so that you do not have to try to come up with good values on your own. These are only used internally, so it won’t hurt usability to have complex, secure values here.

      To grab secure values from the WordPress secret key generator, type:

      • curl -s https://api.wordpress.org/secret-key/1.1/salt/

      You will get back unique values that resemble output similar to the block below.

      Warning! It is important that you request unique values each time. Do NOT copy the values below!

      Output

      define('AUTH_KEY', '1jl/vqfs<XhdXoAPz9 DO NOT COPY THESE VALUES c_j{iwqD^<+c9.k<J@4H'); define('SECURE_AUTH_KEY', 'E2N-h2]Dcvp+aS/p7X DO NOT COPY THESE VALUES {Ka(f;rv?Pxf})CgLi-3'); define('LOGGED_IN_KEY', 'W(50,{W^,OPB%PB<JF DO NOT COPY THESE VALUES 2;y&,2m%3]R6DUth[;88'); define('NONCE_KEY', 'll,4UC)7ua+8<!4VM+ DO NOT COPY THESE VALUES #`DXF+[$atzM7 o^-C7g'); define('AUTH_SALT', 'koMrurzOA+|L_lG}kf DO NOT COPY THESE VALUES 07VC*Lj*lD&?3w!BT#-'); define('SECURE_AUTH_SALT', 'p32*p,]z%LZ+pAu:VY DO NOT COPY THESE VALUES C-?y+K0DK_+F|0h{!_xY'); define('LOGGED_IN_SALT', 'i^/G2W7!-1H2OQ+t$3 DO NOT COPY THESE VALUES t6**bRVFSD[Hi])-qS`|'); define('NONCE_SALT', 'Q6]U:K?j4L%Z]}h^q7 DO NOT COPY THESE VALUES 1% ^qUswWgn+6&xqHN&%');

      These are configuration lines that we can paste directly in our configuration file to set secure keys. Copy the output you received now.

      Next, open the WordPress configuration file:

      • sudo nano /var/www/wordpress/wp-config.php

      Find the section that contains the example values for those settings.

      /var/www/wordpress/wp-config.php

      . . .
      
      define('AUTH_KEY',         'put your unique phrase here');
      define('SECURE_AUTH_KEY',  'put your unique phrase here');
      define('LOGGED_IN_KEY',    'put your unique phrase here');
      define('NONCE_KEY',        'put your unique phrase here');
      define('AUTH_SALT',        'put your unique phrase here');
      define('SECURE_AUTH_SALT', 'put your unique phrase here');
      define('LOGGED_IN_SALT',   'put your unique phrase here');
      define('NONCE_SALT',       'put your unique phrase here');
      
      . . .
      

      Delete those lines and paste in the values you copied from the command line:

      /var/www/wordpress/wp-config.php

      . . .
      
      define('AUTH_KEY',         'VALUES COPIED FROM THE COMMAND LINE');
      define('SECURE_AUTH_KEY',  'VALUES COPIED FROM THE COMMAND LINE');
      define('LOGGED_IN_KEY',    'VALUES COPIED FROM THE COMMAND LINE');
      define('NONCE_KEY',        'VALUES COPIED FROM THE COMMAND LINE');
      define('AUTH_SALT',        'VALUES COPIED FROM THE COMMAND LINE');
      define('SECURE_AUTH_SALT', 'VALUES COPIED FROM THE COMMAND LINE');
      define('LOGGED_IN_SALT',   'VALUES COPIED FROM THE COMMAND LINE');
      define('NONCE_SALT',       'VALUES COPIED FROM THE COMMAND LINE');
      
      . . .
      

      Next, we are going to modify some of the database connection settings at the beginning of the file. You need to adjust the database name, the database user, and the associated password that you configured within MySQL.

      The other change we need to make is to set the method that WordPress should use to write to the filesystem. Since we’ve given the web server permission to write where it needs to, we can explicitly set the filesystem method to “direct”. Failure to set this with our current settings would result in WordPress prompting for FTP credentials when we perform some actions.

      This setting can be added below the database connection settings, or anywhere else in the file:

      /var/www/wordpress/wp-config.php

      . . .
      
      // ** MySQL settings - You can get this info from your web host ** //
      /** The name of the database for WordPress */
      define( 'DB_NAME', 'wordpress' );
      
      /** MySQL database username */
      define( 'DB_USER', 'wordpressuser' );
      
      /** MySQL database password */
      define( 'DB_PASSWORD', 'password' );
      
      /** MySQL hostname */
      define( 'DB_HOST', 'localhost' );
      
      /** Database Charset to use in creating database tables. */
      define( 'DB_CHARSET', 'utf8' );
      
      /** The Database Collate type. Don't change this if in doubt. */
      define( 'DB_COLLATE', '' );
      
      
      . . .
      
      define('FS_METHOD', 'direct');
      

      Save and close the file when you are finished.

      Step 6 — Completing the Installation Through the Web Interface

      Now that the server configuration is complete, we can complete the installation through the web interface.

      In your web browser, navigate to your server’s domain name or public IP address:

      https://server_domain_or_IP
      

      Select the language you would like to use:

      WordPress language selection

      Next, you will come to the main setup page.

      Select a name for your WordPress site and choose a username. It is recommended to choose something unique and avoid common usernames like “admin” for security purposes. A strong password is generated automatically. Save this password or select an alternative strong password.

      Enter your email address and select whether you want to discourage search engines from indexing your site:

      WordPress setup installation

      When you click ahead, you will be taken to a page that prompts you to log in:

      WordPress login prompt

      Once you log in, you will be taken to the WordPress administration dashboard:

      WordPress login prompt

      At this point, you can begin to design your WordPress website! If this is your first time using WordPress, explore the interface a bit to get acquainted with your new CMS.

      Conclusion

      Congratulations, WordPress is now installed and is ready to be used!

      At this point you may want to start doing the following:

      • Choose your permalinks setting for WordPress posts, which can be found in Settings > Permalinks.
      • Select a new theme in Appearance > Themes.
      • Install new plugins to increase your site’s functionality under Plugins > Add New.
      • If you are going to collaborate with others, you may also wish to add additional users at this time under Users > Add New.

      You can find additional resources for alternate ways to install WordPress, learn how to install WordPress on different server distributions, automate your WordPress installations, and scale your WordPress sites by checking out our WordPress Community tag.



      Source link

      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