Deploy a laravel 7.x application using deployer and docker
OBS
(s) Servidor
(l) Local
- Connect to the server:
(l) $ ssh root@SERVER_IP
- The root user must not be used on the server, so it is necessary to create a new user:
(s) $ sudo adduser deployer
- After the new user is created, he must be added to sudoers in order for him to have sudo privileges:
(s) $ sudo usermod -aG sudo deployer
- Set up an ssh key so that the user can access the server without having to enter the password:
- To create the RSA key pair, he first asks where he wants to save the key (.ssh / id_rsa) and immediately asks to enter the password twice to open the key:
(l) $ ssh-keygen -t rsa
- Send the created key to the server:
(l) $ ssh-copy-id -i ~/.ssh/id_rsa.pub deployer@SERVER-IP
- Finally, to test that everything is correct:
(l) $ ssh deployer@SERVER-IP
- To create the RSA key pair, he first asks where he wants to save the key (.ssh / id_rsa) and immediately asks to enter the password twice to open the key:
- Install Docker and docker-compose on the server:
- Docker:
(s) $ curl -fsSL https://get.docker.com -o get-docker.sh
(s) $ sudo sh get-docker.sh
(s) $ sudo usermod -aG docker deployer
- docker-compose:
(s) $ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
(s) $ sudo chmod +x /usr/local/bin/docker-compose
- Docker:
- Install nginx on the server, a container for nginx will not be used; therefore, there is no need to create and configure a new nginx to define which application should be redirected:
(s) $ sudo apt-get update
(s) $ sudo apt-get install nginx -y
- It is necessary to add the user created to the www-data group to allow read and write access to /var/www:
- Add user to www-data:
(s) $ sudo adduser $USER www-data
- Change the owner of the files, allowing user access:
(s) $ sudo chown $USER:www-data -R /www
- Change file permissions by providing read, write and execute permissions:
(s) $ sudo chmod u=rwX,g=srX,o=rX -R /var/www
- Add user to www-data:
- Allow the user to run nginx with sudo and without a password:
(s) $ sudo visudo
- Add these lines to the open file:
# Commands to run as sudo without password deployer ALL=(ALL) NOPASSWD:/usr/sbin/nginx
- Add these lines to the open file:
- Create a branch for production:
- Go to branch master:
(l) $ git ckeckout master
- Create a new branch:
(l) $ git ckeckout -b production
- Go to branch master:
- Install Deployer, the implementer must be installed inside the application container:
(l) $ docker-compose exec app composer require deployer/dist –dev
- After installing Deployer, generate the configuration file for the deployment:
(l) $ docker-compose exec app vendor/bin/dep init -t Laravel
- In an editor, open the deploy.php file, to configure it:
- Example of deploy.php
- Allow access to the server via ssh through the container:
- Create a folder named .ssh within the project and copy your private key:
(l)$ cp ~/.ssh/id_rsa .ssh/
- Ignore the .ssh folder in the project:
(l)$ git update-index --assume-unchanged .ssh/
- Added the .ssh folder in gitignore
- Create a folder named .ssh within the project and copy your private key:
- Allow the server to clone the project that is on github.com:
(s)$ ssh-keygen -t rsa
- Copy the key and on github.com, in settings, Deploy keys and then add deploy key add the public key:
(s)$ cat ~/.ssh/id_rsa.pub
- Test access to github
(s)$ ssh -T git@github.com
- Copy the key and on github.com, in settings, Deploy keys and then add deploy key add the public key:
- In the project folder, create the folders for the deployment:
- In this folder, you will find the Dockerfile and docker-compose files
(l)$ mkdir -p deploy/production (l)$ cd deploy/production
- Dockerfile:
(l)$ wget https://gist.githubusercontent.com/dmarczal/a0800aae0111f152fd69024f2ab13d77/raw/6f3ab5ae3ae01729b30de029101686583212f67b/Dockerfile
- Open the Dockerfile file, and just under procps \ add rsync. Rsync is used to copy and synchronize files and directories remotely.
Instead of, RUN ln -sf ${VENDOR_PATH} ${APP}/current/vendor change to, RUN ln -sf ${VENDOR_PATH} ${APP}/shared/vendor
- docker-compose:
(l)$ wget https://gist.githubusercontent.com/dmarczal/585343b16c62f7f061e8d6964639ec4d/raw/063c941f8e7a0be1c9b75e482a15c112c007c2db/docker-compose.yml
- Open the docker-compose.yml file, and change the lines:
Instead of, - ./current/php/local.ini:/usr/local/etc/php/conf.d/local.ini change to, - ./shared/php/server.ini:/usr/local/etc/php/conf.d/server.ini
Instead of, - ./current/mysql/my.cnf:/etc/mysql/my.cnf change to, - ./shared/mysql/my.cnf:/etc/mysql/my.cnf
- Create a folder to store the php file:
(l)$ mkdir -p deploy/php (l)$ cd deploy/php (l)$ nano server.ini
Content:
upload_max_filesize=40M post_max_size=40M memory_limit=4G
- Create a folder to store the mysql file:
(l)$ mkdir -p deploy/mysql (l)$ cd deploy/mysql (l)$ nano my.cnf
Content:
[mysqld] general_log = 1 general_log_file = /var/lib/mysql/general.log
- In this folder, you will find the Dockerfile and docker-compose files
- Add files created in the production branch, so that the server has access to these files when cloned:
(l)$ git add . (l)$ git commit -m “commit deploy-production” (l)$ git push origin production
- Prepare the deployment, the deploy: prepare command verifies that the releases, shared folders and .dep have been created on the server, if they do not exist, deploy: prepare will create them:
(l)$ docker-compose exec app php vendor/bin/dep deploy:prepare production -vvv
OBS: deploy_path is the application path, this path is added to the deploy.php file; In the shared folder, shared files are stored in all versions; The releases folder contains the releases, which would be different versions of the application; In .dep, they are metadata used by Deployer.
- The deploy: setup command is responsible for creating and starting the application containers:
(l)$ docker-compose exec app php vendor/bin/dep deploy:setup:docker production -vvv
- On the server, go to the /var/www/APP_NAME/shared folder and create an .env file:
(s) $ nano .env
Content:
APP_NAME=SM-SEMEC APP_ENV=production APP_KEY= APP_DEBUG=false APP_URL=http://semec.tsi.pro.br DB_CONNECTION=mysql DB_HOST=db-semec DB_PORT=3306 DB_DATABASE=name_database DB_USERNAME=user-database DB_PASSWORD=password-database
- Generate application key:
(l) $ docker-compose exec app php vendor/bin/dep deploy:artisan:key:generate production -vvv
- After everything is set up, just run the command to deploy the application to the server:
(l)$ docker-compose exec app php vendor/bin/dep deploy production -vvv
- On the server, create the configuration file, APP_NAME (e.g. sm-semec) in the /etc/nginx/sites-available folder:
- Create file:
(s)$ sudo vim /etc/nginx/sites-available/sm-semec
Content:
upstream app-semec { server 0.0.0.0:9001; } server { listen 80; server_name dominio.com; error_log /var/www/sm-semec/shared/logs/nginx-error.log; access_log /var/www/sm-semec/shared/logs/nginx-access.log; root /var/www/sm-semec/current/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index index.html index.htm index.php; charset utf-8; location ~\.php$ { try_files $uri = 404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app-semec; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ /\.(?!well-known).* { deny all; } client_max_body_size 5M; client_body_buffer_size 16k; }
- Create file:
- Activate the site by adding a symbolic link to the file created on the activated sites:
(s)$ sudo ln -sf /etc/nginx/sites-available/sm-semec /etc/nginx/sites-enabled/sm-semec
- Check that everything is correct in the settings made and reload nginx:
(s)$ sudo nginx -t
(s)$ sudo nginx -s reload
- Configure SSL (https), it is a type of digital security that allows encrypted communication between a website and a browser:
Based on How To Secure Nginx with Let’s Encrypt, it provides an easy way to install and obtain free SSL certificates, thus allowing encrypted HTTPS on servers.
- Install Certbot, with it you can generate certificates issued by Let’s Encrypt:
(s)$ sudo add-apt-repository ppa:certbot/certbot
(s)$ sudo apt-get update
(s)$ sudo apt-get install python-certbot-nginx
- The Nginx plug-in will take care of reconfiguring Nginx and reloading the configuration whenever necessary, it does this by running certbot –nginx, and to specify the name for which the certificate is valid, use -d, when it is the first time it will ask you to add your email:
(s)$ sudo certbot --nginx -d semec.tsi.pro.br
- The certbot adds a script that runs twice a day where it automatically renews any certificate, to test the renewal process just run:
(s)$ sudo certbot renew –dry-run
- Install Certbot, with it you can generate certificates issued by Let’s Encrypt:
- In the /var/www/APP_NAME/shared/.env file, change http to https:
(s)$ docker-compose exec app php vendor/bin/dep deploy:config:cache production -vvv
- Access the application https://semec.tsi.pro.br: