← Back to Blog

Deploy a Website With a Single Command — SaltStack

Back in school, we usually worked with a handful of standalone Servers, easy to manage by just logging into the server and installing whatever packages were needed, fixing errors as they came up.

But in a real-world environment, you might have to work with hundreds or thousands of servers at once, making it infeasible to log into each server to install packages or edit config. So somewhere along the way, tools got created that let you run 1 or many commands on many machines at once.

In this post I'll walk through how to use SaltStack to install LAMP (Linux, Apache, MySQL, PHP) and pull code from github to run a complete website on Ubuntu 18.04. Installing SaltStack Master and Minion is fairly simple — you can check it out here. Now let's get to the main event!!!

What can SaltStack do?

  • Remote Execution: Run commands on minion machines (basically slaves) from the master machine.
  • Configuration Management: Manage minion machines' config via state files. This is also commonly called Infrastructure as Code (IaC)
  • File/Git Server: SaltStack can operate as a file server or Git Server for minions to pull files or source code from.
  • ....

There are plenty more features I haven't gotten to explore yet.

Creating a State File to install LAMP + Clone Code

By default SaltStack's root file lives at /srv/salt/ — inside this folder, let's create a state file (.sls) named installLamp.sls. First, before doing anything on Linux I usually run Update + Upgrade — let's add this snippet:

updateSystem:
  cmd.run:
    - name: "apt update && apt upgrade -y"

'updateSystem': is the name of this piece of work — you can name it whatever you want.

'cmd.run': is the directive that runs a fixed command.

'name': the command's content.

Next, install the LampStack with this snippet:

install_LAMP_Packages:
  pkg.installed:
    - pkgs:
      - apache2
      - mysql-server
      - php
      - libapache2-mod-php
      - php-mysql

This snippet installs all the packages needed for a LAMP Stack Server. Once installed, we need to make sure it's running with this snippet:

apache2:
  pkg.installed: []
  service.running:
    - require:
      - pkg: apache2

mysql-server:
  pkg.installed: []
  service.running:
    - require:
      - pkg: mysql-server

Now we have the services needed for the website to sit on — time to clone the code. The idea is to clone the code then copy it into the default webroot at /var/www/html. But sometimes /var/www/html hasn't been created yet, which could cause an error, so let's create this folder first to be safe.

create html_directory:
  file.directory:
    - name: /var/www/html
    - user: www-data
    - group: www-data
    - mode: 735

Clone_git_Repo:
  git.latest:
    - name: https://github.com/MMA17/LapTrinhWeb.git
    - target: /var/www/
    - user: www-data
    - force_clone: True

copy_all_web_files:
  cmd.run:
    - name: "cp -r /var/www/LapTrinhWeb/* /var/www/html/"

Now the web is online — one more thing left, importing the database. To import the database, add a super simple snippet to run pre-saved SQL statements from a file. Check out that file here:

Init_Database:
  cmd.run:
    - name: "mysql < /var/www/LapTrinhWeb/initdb.sql"

To be extra safe you could add a snippet to restart the services, but usually this is enough. Once written, the complete file looks like this:

updateSystem:
  cmd.run:
    - name: "apt update && apt upgrade -y"

install_LAMP_Packages:
  pkg.installed:
    - pkgs:
      - apache2
      - mysql-server
      - php
      - libapache2-mod-php
      - php-mysql

copy_apache_config_file:
  file.managed:
    - name: /etc/apache2/apache2.conf
    - source: salt://lampStack/apache2.conf

apache2:
  pkg.installed: []
  service.running:
    - require:
      - pkg: apache2

mysql-server:
  pkg.installed: []
  service.running:
    - require:
      - pkg: mysql-server

create html_directory:
  file.directory:
    - name: /var/www/html
    - user: www-data
    - group: www-data
    - mode: 735

Clone_git_Repo:
  git.latest:
    - name: https://github.com/MMA17/LapTrinhWeb.git
    - target: /var/www/
    - user: www-data
    - force_clone: True

copy_all_web_files:
  cmd.run:
    - name: "cp -r /var/www/LapTrinhWeb/* /var/www/html/"

Init_Database:
  cmd.run:
    - name: "mysql < /var/www/LapTrinhWeb/initdb.sql"

Running the State File

This is the part that'll get you excited once you've finished writing the State File. To run this State File on a Minion, we use a simple command:

salt '*' state.apply installLamp

to apply it to all minions, or replace * with a minion's name to apply it to a specific server.

Note: the State file's name, when used with state.apply, doesn't include the .sls extension.

Wrapping up

And that's it! Deploy a Website to as many servers as you want with 1 command. I've only scratched the surface myself, so the snippet will definitely have some mistakes or silly bits — if you spot any, feel free to help me fix them in the comments.

Hope you picked up a bit of knowledge. Have a nice day.

If you're running into technical challenges or need help with systems, DevOps tools, I'm confident I can help. Get in touch at hoangviet.io.vn

Have thoughts on this?

I'd love to hear your perspective. Send me a message.

Get in touch