One place for hosting & domains

      Production

      How to Deploy a Symfony 4 Application to Production with LEMP on Ubuntu 18.04


      The author selected Software in the Public Interest Inc to receive a donation as part of the Write for DOnations program.

      Introduction

      Symfony is an open-source PHP framework with an elegant structure and a reputation for being a suitable framework to kick-start any project irrespective of its size. As a set of reusable components, its flexibility, architecture, and high performance make it a top choice for building a highly complex enterprise application.

      In this tutorial, you will deploy an existing, standard Symfony 4 application to production with a LEMP stack (Nginx, MySQL, and PHP) on Ubuntu 18.04, which will help you get started configuring the server and the structure of the framework. Nginx is a popular open-source, high-performance HTTP server with additional features including reverse proxy support. It has a good reputation and hosts some of the largest and highest traffic sites on the internet. If you choose to deploy your own Symfony application instead, you might have to implement extra steps depending on the existing structure of your application.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Creating a User and Database for the Application

      By following the instructions in the Prerequisites, you now have all the basic server dependencies required for the application installation. As every dynamic web application requires a database, you will create a user and properly configure a database for the application in this section.

      To create a MySQL database for our application and a user associated with it, you need to access the MySQL client using the MySQL root account:

      Enter the appropriate password, which should be the same password used when running mysql_secure_installation.

      Next, create the application database with:

      You will see the following output in the console:

      Output

      Query OK, 1 row affected (0.00 sec)

      You have successfully created your application database. You can now create a MySQL user and grant them access to the newly created database.

      Execute the following command to create a MySQL user and password. You can change the username and password to something more secure if you wish:

      • CREATE USER 'blog-admin'@'localhost' IDENTIFIED BY 'password';

      You will see the following output:

      Output

      Query OK, 0 rows affected (0.00 sec)

      Currently, the user blog-admin does not have the right permission over the application database. In fact, even if blog-admin tries to log-in with their password, they will not be able to reach the MySQL shell.

      A user needs the right permission before accessing or carrying out a specific action on a database. Use the following command to allow complete access to the blog database for the blog-admin user:

      • GRANT ALL PRIVILEGES ON blog.* TO 'blog-admin'@'localhost';

      You will see the following output:

      Output

      Query OK, 0 rows affected (0.00 sec)

      The blog-admin now has all privileges on all the tables inside the blog database. To reload the grant tables and apply changes, you need to perform a flush-privilege operation using the flush statement:

      You will see the following output:

      Output

      Query OK, 0 rows affected (0.00 sec)

      You are done creating a new user and granting privileges. To test if you’re on track, exit the MySQL client:

      And log in again, using the credentials of the MySQL user you just created and enter the password when prompted:

      Check that the database can be accessed by the user with:

      You'll see the blog table in the output:

      Output

      +--------------------+ | Database | +--------------------+ | information_schema | | blog | +--------------------+ 2 rows in set (0.00 sec)

      Finally, exit the MySQL client:

      You have successfully created a database, a user for the demo application, and granted the newly created user the right privileges to access the database. You are now ready to set up the demo application.

      Step 2 — Setting Up the Demo Application

      To keep this tutorial simple, you will deploy a blog application built with Symfony. This application will allow an authenticated user to create a blog post and store it in the database. In addition, the application user can view all the posts and details associated with an author.

      The source code of the blog application you will deploy in this tutorial is on GitHub. You will use Git to pull the source code of the application from GitHub and save it in a new directory.

      First, create a directory that will serve as the root directory for your application. So, run the following command from the console to create a new directory named symfony-blog:

      • sudo mkdir -p /var/www/symfony-blog

      In order to work with the project files using a non-root user account, you’ll need to change the folder owner and group by running:

      • sudo chown sammy:sammy /var/www/symfony-blog

      Replace sammy with your sudo non-root username.

      Now, you can change into the parent directory and clone the application on GitHub:

      • cd /var/www
      • git clone https://github.com/yemiwebby/symfony-blog.git symfony-blog

      You'll see the following output:

      Output

      Cloning into 'symfony-blog'... remote: Counting objects: 180, done. remote: Compressing objects: 100% (122/122), done. remote: Total 180 (delta 57), reused 164 (delta 41), pack-reused 0 Receiving objects: 100% (180/180), 167.01 KiB | 11.13 MiB/s, done. Resolving deltas: 100% (57/57), done.

      The demo application is now set. In the next step, you will configure the environment variables and install the required dependencies for the project.

      Step 3 — Configuring your Environment Variables for the Application

      To completely set up the application, you need to install the project dependencies and properly configure the application parameters.

      By default, the Symfony application runs in a development mode, which gives it a very detailed log for the purposes of debugging. This is not applicable to what you are doing in this tutorial, and not good practice for a production environment, as it can slow things down and create very large log files.

      Symfony needs to be aware that you’re running the application in a production environment. You can set this up by either creating a .env file containing variable declarations, or creating environment variables directly. Since you can also use the .env file to configure your database credentials for this application, it makes more sense for you to do this. Change your working directory to the cloned project and create the .env file with:

      • cd symfony-blog
      • sudo nano .env

      Add the following lines to the file to configure the production application environment:

      .env

      APP_ENV=prod
      APP_DEBUG=0
      

      APP_ENV is an environment variable that specifies that the application is in production, while APP_DEBUG is an environment variable that specifies if the application should run in debug mode or not. You have set it to false for now.

      Save the file and exit the editor.

      Next, install a PHP extension that Symfony apps use to handle XML:

      • sudo apt install php7.2-xml

      Next, you need to install the project dependencies, run composer install:

      • cd /var/www/symfony-blog
      • composer install

      You have successfully configured the environment variables and installed the required dependencies for the project. Next, you will set up the database credentials.

      Step 4 — Setting Up Database Credentials

      In order to retrieve data from the application’s database you created earlier, you will need to set up and configure the required database credentials from within the Symfony application.

      Open the .env file again:

      Add the following content to the file, which will allow you to easily connect and interact properly with the database. You can add it right after the APP_DEBUG=0 line within the .env file:

      .env

      ...
      DATABASE_URL=mysql://blog-admin:password@localhost:3306/blog
      

      The Symfony framework uses a third-party library called Doctrine to communicate with databases. Doctrine gives you useful tools to make interactions with databases easy and flexible.

      You can now use Doctrine to update your database with the tables from the cloned Github application. Run this command to do that:

      • php bin/console doctrine:schema:update --force

      You'll see the following output:

      Output

      Updating database schema... 4 queries were executed [OK] Database schema updated successfully!

      After setting up the required credentials and updating the database schema, you can now easily interact with the database. In order to start the application with some data, you will load a set of dummy data into the database in the next section.

      Step 5 — Populating your Database Using Doctrine-Fixtures

      At the moment, the newly created tables are empty. You will populate it using doctrine-fixtures. Using Doctrine-Fixtures is not a prerequisite for Symfony applications, it is only used to provide dummy data for your application.

      Run the following command to automatically load testing data that contains the details of an author and a sample post into the database table created for the blog:

      • php bin/console doctrine:fixtures:load

      You will get a warning about the database getting purged. You can go ahead and type Y:

      Output

      Careful, database will be purged. Do you want to continue y/N ? y > purging database > loading AppDataFixturesORMFixtures

      In the next section you will clear and warm up you cache.

      Step 6 — Clearing and Warming Up your Cache

      To ensure your application loads faster when users make requests, it is good practice to warm the cache during the deployment. Warming up the cache generates pages and stores them for faster responses later rather than building completely new pages. Fortunately, Symfony has a command to clear the cache that also triggers a warm up. Run the following command for that purpose:

      • php bin/console cache:clear

      You will see the following output:

      Output

      Clearing the cache for the prod environment with debug false [OK] Cache for the "prod" environment (debug=false) was successfully cleared.

      You will conclude the set up in a bit. All that remains is to configure the web server. You will do that in the next section.

      Step 7 — Configuring the Web Server and Running the Application

      By now, you have Nginx installed to serve your pages and MySQL to store and manage your data. You will now configure the web server by creating a new application server block, instead of editing the default one.

      Open a new server block with:

      • sudo nano /etc/nginx/sites-available/blog

      Add the following content to the new server block configuration file. Ensure you replace the your_server_ip within the server block with your server IP address:

      /etc/nginx/sites-available/blog

      
      server {
          listen 80;
          listen [::]:80;
      
          server_name blog your_server_ip;
          root /var/www/symfony-blog/public;
          index index.php;
          client_max_body_size 100m;
      
          location / {
              try_files $uri $uri/ /index.php$is_args$args;
          }
      
          location ~ .php {
              try_files $uri /index.php =404;
              fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              fastcgi_param SCRIPT_NAME $fastcgi_script_name;
              fastcgi_split_path_info ^(.+.php)(/.+)$;
              fastcgi_index index.php;
              include fastcgi_params;
            }
      
          location ~ /.(?:ht|git|svn) {
              deny all;
          }
      }
      

      First, we specified the listen directives for Nginx, which is by default on port 80, and then set the server name to match requests for the server’s IP address. Next, we used the root directives to specify the document root for the project. The symfony-blog application is stored in /var/www/symfony-blog, but to comply with best practices, we set the web root to /var/www/symfony-blog/public as only the /public subdirectory should be exposed to the internet. Finally, we configured the location directive to handle PHP processing.

      After adding the content, save the file and exit the editor.

      Note: If you created the file example.com in the prerequisite article How To Install Linux, Nginx, MySQL, PHP (LEMP stack) on Ubuntu 18.04, remove it from the sites-enabled directory with sudo rm /etc/nginx/sites-enabled/example.com so it doesn't conflict with this new file.

      To enable the newly created server block, we need to create a symbolic link from the new server block configuration file located in /etc/nginx/sites-available directory to the /etc/nginx/sites-enabled by using the following command:

      • sudo ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/

      Check the new configuration file for any syntax errors by running:

      This command will print errors to the console if there are any. Once there are no errors run this command to reload Nginx:

      • sudo systemctl reload nginx

      You just concluded the last step required to successfully deploy the Symfony 4 application. You configured the web server by creating a server block and properly set the web root in order to make the web application accessible.

      Finally, you can now run and test out the application. Visit http://your_server_ip in your favorite browser:

      The following image is the screenshot of the Symfony blog application that you should see at your server's IP address:

      Alt screenshot of the Symfony blog application

      Conclusion

      Symfony is a feature-rich PHP framework with an architecture that makes web development fun for the developer who builds software using it. Symfony is a feature-rich web development framework that provides developers powerful tools to build web applications. It's often considered a good choice for enterprise applications due to its flexibility. The steps to deploy a typical Symfony application vary—depending on the setup, complexity, and the requirements of the application.

      In this tutorial, you manually deployed a Symfony 4 application to production on an Ubuntu 18.04 server running LEMP. You can now apply this knowledge to deploying your own Symfony applications.



      Source link

      How To Set Up a Node.js Application for Production on Debian 9


      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 the applications 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 Debian 9 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.

      To install the NodeSource PPA and access its contents, you will first need to update your package index and install curl:

      • sudo apt update
      • sudo apt install curl

      Make sure you’re in your home directory, and then use curl to retrieve the installation script for the Node.js 8.x archives:

      • cd ~
      • curl -sL https://deb.nodesource.com/setup_8.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

      v8.11.4

      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

      5.6.0

      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 see 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 see the following output, the application is working properly and listening on the correct address and port:

      Output

      Hello World!

      If you do not see 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 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. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤ │ hello │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ sammy │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app

      As you can see, 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 to set PM2 to start on boot:

      Output

      [PM2] Init System found: systemd [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

      Check the status of the systemd unit:

      • systemctl status pm2-sammy

      For a detailed overview of systemd, see 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 a Debian 9 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