Laradock Production Setup

Been bothering me for a long time that there are no great blog posts on setting up Laravel for Production. There are plenty of blogs out there on development setups, but hardly any on production setups.  Last November Faizan Basheer did write a decent Laravel on Docker tutorial on Digital Ocean. Only issue was that is was not a whole setup like I tend to need and it was fully custom and not using Laradock.

So based on his tutorial and stuff I learned and found elsewhere I will be writing my own Laradock Production setup. One showing you how you can setup Laravel on Docker with Laradock using Nginx, MariaDB, PHP-FPM, PHP Worker, Workspace, Horizon.

Digital Ocean Docker One Click App

Digital Ocean Docker One-Click App can be used as well and in that case the Ubuntu provisioning and Docker / Docker Compose setup here below can be skipped entirely. Just pick it as a one click app, choose your droplet size/ram, network and ssh options and get started.

Docker One Click App.png

Personally I prefer to know what I am running and have that in version control as well. In the case of a one click app you do not. And in the case of this one click app an additional sudo user with docker privileges has not been set up. Not the last time around I tried this image anyways.

Digital Ocean Server Provisioning

For a hoster we will use Digital Ocean, not AWS as so many DevOps out there tend to use. I love Digital Ocean and now that they support Kubernetes there is no need for me to move onto another hosting provider.

For setting up an Ubuntu 18.04 server (18.10 not supported yet at the time of this writing) with a sudo user for web related stuff:

Ubuntu 18.0.4.png

we can just run the Digital Ocean Bash script during a Droplet setup using their GUI. by checking user data:

Droplet User Data.png

you can run a bash script doing some basics. So we use their Bash script with a small tweak (username adjusted):

#!/bin/bash
set -euo pipefail

########################
### SCRIPT VARIABLES ###
########################

# Name of the user to create and grant sudo privileges
USERNAME=web

# Whether to copy over the root user's `authorized_keys` file to the new sudo
# user.
COPY_AUTHORIZED_KEYS_FROM_ROOT=true

# Additional public keys to add to the new sudo user
# OTHER_PUBLIC_KEYS_TO_ADD=(
#     "ssh-rsa AAAAB..."
#     "ssh-rsa AAAAB..."
# )
OTHER_PUBLIC_KEYS_TO_ADD=(
)

####################
### SCRIPT LOGIC ###
####################

# Add sudo user and grant privileges
useradd --create-home --shell "/bin/bash" --groups sudo "${USERNAME}"

# Check whether the root account has a real password set
encrypted_root_pw="$(grep root /etc/shadow | cut --delimiter=: --fields=2)"

if [ "${encrypted_root_pw}" != "*" ]; then
    # Transfer auto-generated root password to user if present
    # and lock the root account to password-based access
    echo "${USERNAME}:${encrypted_root_pw}" | chpasswd --encrypted
    passwd --lock root
else
    # Delete invalid password for user if using keys so that a new password
    # can be set without providing a previous value
    passwd --delete "${USERNAME}"
fi

# Expire the sudo user's password immediately to force a change
chage --lastday 0 "${USERNAME}"

# Create SSH directory for sudo user
home_directory="$(eval echo ~${USERNAME})"
mkdir --parents "${home_directory}/.ssh"

# Copy `authorized_keys` file from root if requested
if [ "${COPY_AUTHORIZED_KEYS_FROM_ROOT}" = true ]; then
    cp /root/.ssh/authorized_keys "${home_directory}/.ssh"
fi

# Add additional provided public keys
for pub_key in "${OTHER_PUBLIC_KEYS_TO_ADD[@]}"; do
    echo "${pub_key}" >> "${home_directory}/.ssh/authorized_keys"
done

# Adjust SSH configuration ownership and permissions
chmod 0700 "${home_directory}/.ssh"
chmod 0600 "${home_directory}/.ssh/authorized_keys"
chown --recursive "${USERNAME}":"${USERNAME}" "${home_directory}/.ssh"

# Disable root SSH login with password
sed --in-place 's/^PermitRootLogin.*/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config
if sshd -t -q; then
    systemctl restart sshd
fi

# Add exception for SSH and then enable UFW firewall
ufw allow OpenSSH
ufw --force enable

NB Raw script from our fork here.

NBB We might add MariaDB and or Redis ports to ports available here or for a while. We might not tweak ufw and use the Digital Ocean Firewall instead.

Sudo User

Do not forget to check your ssh key(s) to be used with root. Once done first log in as root and change to the sudo user. Once logged out again you can ssh in as the sudo user and you will be asked to add a sudo password. Once that is done you are logged off. You can then ssh passwordless into the server again to work on the rest of the installation.

Docker Setup

The above does the basics, but does however not setup Docker and Docker Compose which we obviously need as well. We will do this with the sudo user created. Which in this case will be web, not sammy as Digital Ocean uses in their tutorials. With that user you can run the following:

su web
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt update
apt-cache policy docker-ce
sudo apt install docker-ce
sudo systemctl status docker
sudo usermod -aG docker ${USER}
su - ${USER}
id -nG

et voila, Docker will be installed and your user will be able to run Docker commands without using sudo.

NB We could use the Docker script to install all as well, but they do not recommend this for production

Docker Compose Setup

To set up Docker Compose you can do the following as user web:

sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Laravel Setup and Deployer

On your server create a directory app inside your web user’s home folder:

mkdir ~/app && cd app

User and group will be web and Laradock will load the app data from this folder.

NB As data will be loaded from ~/app/current via symlink we will need to adjust the Nginx configuration for that later on setting up the Nginx container.

Deployer Installation

You do need Deployer installed locally. I know you could do it in a container as well, but we use it for non Docker purposes as well and outside of a container is just easy. We do this with composer and globally as we use composer for Laravel of course and as we use deployer in many projects:

composer global require deployer/deployer

We also have this inside ~/.bash_profile

export PATH="$PATH:$HOME/.composer/vendor/bin"

so we can simply run dep x without the path to the binary.

Deploy Script

To instruct deployer what to do add deploy.php inside your app with the following content:

<?php namespace Deployer; 
require 'recipe/laravel.php'; 

// Configuration 
set('repository', 'git@github.com:jasperf/awesome-app.git'); 
set('default_stage', 'production'); 
set('git_tty', true); 

// [Optional] Allocate tty for git on first deployment 
set('ssh_type', 'native'); 
set('keep_releases', 10); 

// Make sure uploads & published aren't overwritten by deploying 
set('shared_dirs', [     
    'public/uploads',
    'public/published',     
     'storage/tls/sites.d' 
]); 
set('shared_files', [
     '.env', 
]); 
set('writable_dirs', [     
    'public/uploads',     
    'public/published',     
    'storage/framework/cache/data',     
    'storage/tls' 
]); 

// SMART CUSTOM DEPLOY COMMANDS 
task('db:migrate', function () {     
run("cd {{release_path}} && php artisan migrate"); 
}); 
task('horizon:terminate', function () {     
run("cd {{release_path}} && php artisan horizon:terminate"); 
}); 

// Hosts 
// dep deploy production 
// dep deploy staging    
host('staging')    
    ->hostname('staging.domain.com')
   ->user('web')
   ->forwardAgent()
   ->stage('staging')
   ->set('deploy_path', '/home/web/app');

host('production')
   ->hostname('domain.com')
   ->user('web')
   ->forwardAgent()
   ->stage('production')
   ->set('deploy_path', '/home/web/app');


// Run database migrations
after('deploy:symlink', 'db:migrate');

Actual Deployment

You will need your repository setup. We set up x on Github. Make sure you adjust the script here above to reflect that! Deployment command from local box to start the deployment from the local application root where you added deploy.php would be:

dep deploy production

Laradock Initial Setup

Now we want to add our Laravel app to the production server. Locally I normally have Laravel in one directory and the Laradock in another. Both are in the same project root directory. As on the server we will only run one Laravel app and one Laradock package we could install it in the home directory as the DO tutorial suggests:

cd ~ && git clone git@github.com:laradock/laradock.git laradocker

Laradock Environment Setup

Then enter laradock and copy env-example to .env

cd ~/laradock
cp env-example .env

Then edit the file to change the path to your app:

nano .env
APP_CODE_PATH_HOST=../app/
# control x

You should of course also tweak the config data for all the containers you are going to be using. This we can do a little later after we made our production docker-compose file.

Docker Composer File

Set up your own docker-compose yaml file if you like and add the containers you need:

nano ~/laradock/prod-docker-compose.yml

Then add this this content (based on base docker-compose.yml) to only work with certain containers of our choice:

version: '3'

networks:
  frontend:
    driver: ${NETWORKS_DRIVER}
  backend:
    driver: ${NETWORKS_DRIVER}

volumes:
  redis:
    driver: ${VOLUMES_DRIVER}
  mariadb:
    driver: ${VOLUMES_DRIVER}

services:

### Workspace Utilities ##################################
    workspace:
      build:
        context: ./workspace
        args:
          - LARADOCK_PHP_VERSION=${PHP_VERSION}
          - LARADOCK_PHALCON_VERSION=${PHALCON_VERSION}
          - INSTALL_SUBVERSION=${WORKSPACE_INSTALL_SUBVERSION}
          - INSTALL_XDEBUG=${WORKSPACE_INSTALL_XDEBUG}
          - INSTALL_PHPDBG=${WORKSPACE_INSTALL_PHPDBG}
          - INSTALL_BLACKFIRE=${INSTALL_BLACKFIRE}
          - INSTALL_SSH2=${WORKSPACE_INSTALL_SSH2}
          - INSTALL_GMP=${WORKSPACE_INSTALL_GMP}
          - INSTALL_SOAP=${WORKSPACE_INSTALL_SOAP}
          - INSTALL_LDAP=${WORKSPACE_INSTALL_LDAP}
          - INSTALL_IMAP=${WORKSPACE_INSTALL_IMAP}
          - INSTALL_MONGO=${WORKSPACE_INSTALL_MONGO}
          - INSTALL_AMQP=${WORKSPACE_INSTALL_AMQP}
          - INSTALL_PHPREDIS=${WORKSPACE_INSTALL_PHPREDIS}
          - INSTALL_MSSQL=${WORKSPACE_INSTALL_MSSQL}
          - INSTALL_NODE=${WORKSPACE_INSTALL_NODE}
          - NPM_REGISTRY=${WORKSPACE_NPM_REGISTRY}
          - INSTALL_YARN=${WORKSPACE_INSTALL_YARN}
          - INSTALL_NPM_GULP=${WORKSPACE_INSTALL_NPM_GULP}
          - INSTALL_NPM_BOWER=${WORKSPACE_INSTALL_NPM_BOWER}
          - INSTALL_NPM_VUE_CLI=${WORKSPACE_INSTALL_NPM_VUE_CLI}
          - INSTALL_DRUSH=${WORKSPACE_INSTALL_DRUSH}
          - INSTALL_DRUPAL_CONSOLE=${WORKSPACE_INSTALL_DRUPAL_CONSOLE}
          - INSTALL_AEROSPIKE=${WORKSPACE_INSTALL_AEROSPIKE}
          - AEROSPIKE_PHP_REPOSITORY=${AEROSPIKE_PHP_REPOSITORY}
          - INSTALL_V8JS=${WORKSPACE_INSTALL_V8JS}
          - COMPOSER_GLOBAL_INSTALL=${WORKSPACE_COMPOSER_GLOBAL_INSTALL}
          - COMPOSER_REPO_PACKAGIST=${WORKSPACE_COMPOSER_REPO_PACKAGIST}
          - INSTALL_WORKSPACE_SSH=${WORKSPACE_INSTALL_WORKSPACE_SSH}
          - INSTALL_LARAVEL_ENVOY=${WORKSPACE_INSTALL_LARAVEL_ENVOY}
          - INSTALL_LARAVEL_INSTALLER=${WORKSPACE_INSTALL_LARAVEL_INSTALLER}
          - INSTALL_DEPLOYER=${WORKSPACE_INSTALL_DEPLOYER}
          - INSTALL_PRESTISSIMO=${WORKSPACE_INSTALL_PRESTISSIMO}
          - INSTALL_LINUXBREW=${WORKSPACE_INSTALL_LINUXBREW}
          - INSTALL_MC=${WORKSPACE_INSTALL_MC}
          - INSTALL_SYMFONY=${WORKSPACE_INSTALL_SYMFONY}
          - INSTALL_PYTHON=${WORKSPACE_INSTALL_PYTHON}
          - INSTALL_IMAGE_OPTIMIZERS=${WORKSPACE_INSTALL_IMAGE_OPTIMIZERS}
          - INSTALL_IMAGEMAGICK=${WORKSPACE_INSTALL_IMAGEMAGICK}
          - INSTALL_TERRAFORM=${WORKSPACE_INSTALL_TERRAFORM}
          - INSTALL_DUSK_DEPS=${WORKSPACE_INSTALL_DUSK_DEPS}
          - INSTALL_PG_CLIENT=${WORKSPACE_INSTALL_PG_CLIENT}
          - INSTALL_PHALCON=${WORKSPACE_INSTALL_PHALCON}
          - INSTALL_SWOOLE=${WORKSPACE_INSTALL_SWOOLE}
          - INSTALL_LIBPNG=${WORKSPACE_INSTALL_LIBPNG}
          - INSTALL_IONCUBE=${WORKSPACE_INSTALL_IONCUBE}
          - INSTALL_MYSQL_CLIENT=${WORKSPACE_INSTALL_MYSQL_CLIENT}
          - PUID=${WORKSPACE_PUID}
          - PGID=${WORKSPACE_PGID}
          - CHROME_DRIVER_VERSION=${WORKSPACE_CHROME_DRIVER_VERSION}
          - NODE_VERSION=${WORKSPACE_NODE_VERSION}
          - YARN_VERSION=${WORKSPACE_YARN_VERSION}
          - DRUSH_VERSION=${WORKSPACE_DRUSH_VERSION}
          - TZ=${WORKSPACE_TIMEZONE}
          - BLACKFIRE_CLIENT_ID=${BLACKFIRE_CLIENT_ID}
          - BLACKFIRE_CLIENT_TOKEN=${BLACKFIRE_CLIENT_TOKEN}
      volumes:
        - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}
      extra_hosts:
        - "dockerhost:${DOCKER_HOST_IP}"
      ports:
        - "${WORKSPACE_SSH_PORT}:22"
      tty: true
      environment:
        - PHP_IDE_CONFIG=${PHP_IDE_CONFIG}
      networks:
        - frontend
        - backend

### PHP-FPM ##############################################
    php-fpm:
      build:
        context: ./php-fpm
        args:
          - LARADOCK_PHP_VERSION=${PHP_VERSION}
          - LARADOCK_PHALCON_VERSION=${PHALCON_VERSION}
          - INSTALL_XDEBUG=${PHP_FPM_INSTALL_XDEBUG}
          - INSTALL_PHPDBG=${PHP_FPM_INSTALL_PHPDBG}
          - INSTALL_BLACKFIRE=${INSTALL_BLACKFIRE}
          - INSTALL_SSH2=${PHP_FPM_INSTALL_SSH2}
          - INSTALL_SOAP=${PHP_FPM_INSTALL_SOAP}
          - INSTALL_IMAP=${PHP_FPM_INSTALL_IMAP}
          - INSTALL_MONGO=${PHP_FPM_INSTALL_MONGO}
          - INSTALL_AMQP=${PHP_FPM_INSTALL_AMQP}
          - INSTALL_MSSQL=${PHP_FPM_INSTALL_MSSQL}
          - INSTALL_ZIP_ARCHIVE=${PHP_FPM_INSTALL_ZIP_ARCHIVE}
          - INSTALL_BCMATH=${PHP_FPM_INSTALL_BCMATH}
          - INSTALL_GMP=${PHP_FPM_INSTALL_GMP}
          - INSTALL_PHPREDIS=${PHP_FPM_INSTALL_PHPREDIS}
          - INSTALL_MEMCACHED=${PHP_FPM_INSTALL_MEMCACHED}
          - INSTALL_OPCACHE=${PHP_FPM_INSTALL_OPCACHE}
          - INSTALL_EXIF=${PHP_FPM_INSTALL_EXIF}
          - INSTALL_AEROSPIKE=${PHP_FPM_INSTALL_AEROSPIKE}
          - AEROSPIKE_PHP_REPOSITORY=${AEROSPIKE_PHP_REPOSITORY}
          - INSTALL_MYSQLI=${PHP_FPM_INSTALL_MYSQLI}
          - INSTALL_PGSQL=${PHP_FPM_INSTALL_PGSQL}
          - INSTALL_PG_CLIENT=${PHP_FPM_INSTALL_PG_CLIENT}
          - INSTALL_INTL=${PHP_FPM_INSTALL_INTL}
          - INSTALL_GHOSTSCRIPT=${PHP_FPM_INSTALL_GHOSTSCRIPT}
          - INSTALL_LDAP=${PHP_FPM_INSTALL_LDAP}
          - INSTALL_PHALCON=${PHP_FPM_INSTALL_PHALCON}
          - INSTALL_SWOOLE=${PHP_FPM_INSTALL_SWOOLE}
          - INSTALL_IMAGE_OPTIMIZERS=${PHP_FPM_INSTALL_IMAGE_OPTIMIZERS}
          - INSTALL_IMAGEMAGICK=${PHP_FPM_INSTALL_IMAGEMAGICK}
          - INSTALL_CALENDAR=${PHP_FPM_INSTALL_CALENDAR}
          - INSTALL_FAKETIME=${PHP_FPM_INSTALL_FAKETIME}
          - INSTALL_IONCUBE=${PHP_FPM_INSTALL_IONCUBE}
          - INSTALL_YAML=${PHP_FPM_INSTALL_YAML}
      volumes:
        - ./php-fpm/php${PHP_VERSION}.ini:/usr/local/etc/php/php.ini
        - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}
      expose:
        - "9000"
      extra_hosts:
        - "dockerhost:${DOCKER_HOST_IP}"
      environment:
        - PHP_IDE_CONFIG=${PHP_IDE_CONFIG}
        # - DOCKER_HOST=tcp://docker-in-docker:2375
        - FAKETIME=${PHP_FPM_FAKETIME}
      restart: unless-stopped
      depends_on:
        - workspace
      networks:
        - backend
      # links:
      #   - docker-in-docker

### PHP Worker ############################################
    php-worker:
      build:
        context: ./php-worker
        args:
          - PHP_VERSION=${PHP_VERSION}
          - INSTALL_PGSQL=${PHP_WORKER_INSTALL_PGSQL}
          - INSTALL_BCMATH=${PHP_WORKER_INSTALL_BCMATH}
          - INSTALL_SOAP=${PHP_WORKER_INSTALL_SOAP}
          - INSTALL_ZIP_ARCHIVE=${PHP_WORKER_INSTALL_ZIP_ARCHIVE}
      volumes:
        - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}
        - ./php-worker/supervisord.d:/etc/supervisord.d
      restart: unless-stopped
      depends_on:
        - workspace
      extra_hosts:
        - "dockerhost:${DOCKER_HOST_IP}"
      networks:
        - backend

### NGINX Server #########################################
    nginx:
      build:
        context: ./nginx
        args:
          - PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER}
          - PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT}
          - CHANGE_SOURCE=${CHANGE_SOURCE}
      volumes:
        - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}
        - ${NGINX_HOST_LOG_PATH}:/var/log/nginx
        - ${NGINX_SITES_PATH}:/etc/nginx/sites-available
        - ${NGINX_SSL_PATH}:/etc/nginx/ssl
      ports:
        - "${NGINX_HOST_HTTP_PORT}:80"
        - "${NGINX_HOST_HTTPS_PORT}:443"
      restart: unless-stopped
      depends_on:
        - php-fpm
      networks:
        - frontend
        - backend

### MariaDB ##############################################
    mariadb:
      build: ./mariadb
      volumes:
        - ${DATA_PATH_HOST}/mariadb:/var/lib/mysql
        - ${MARIADB_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d
      # https://github.com/laradock/laradock/issues/571#issuecomment-280874407
      # https://github.com/laradock/laradock/pull/339/commits/ec3ebb9701de24d9c64d567c786a1601a5626f2d
      ports:
        - "${MARIADB_PORT}:3306"
      restart: unless-stopped
      environment:
        - MYSQL_DATABASE=${MARIADB_DATABASE}
        - MYSQL_USER=${MARIADB_USER}
        - MYSQL_PASSWORD=${MARIADB_PASSWORD}
        - MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
      networks:
        - backend

### Redis ################################################
    redis:
      build: ./redis
      volumes:
        - ${DATA_PATH_HOST}/redis:/data
      ports:
        - "${REDIS_PORT}:6379"
      restart: unless-stopped
      networks:
        - backend

### Certbot #########################################
    certbot:
      build:
        context: ./certbot
      volumes:
        - ./data/certbot/certs/:/var/certs
        - ./certbot/letsencrypt/:/var/www/letsencrypt
      environment:
        - CN="fake.domain.com"
        - EMAIL="fake.email@gmail.com"
      networks:
        - frontend

Some elements are commented out as we won’t be using them here but you want to at a later stage.

NB Ports are still open for database services. This can be a security risk. You could set up the database and then close the Redis and MariaDB ports.

Horizon & Laravel Workers

To start Horizon (not added as a separate container here) I added

[program:horizon]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan horizon
autostart=true
autorestart=true
numprocs=1
redirect_stderr=true

to php-worker/supervisord.d/horizon.conf . Horizon in the Laravel app I have installed with the PHP Composer package.

I also have a general Laravel worker:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan queue:work --sleep=3 --tries=3 --daemon
autostart=true
autorestart=true
numprocs=4
redirect_stderr=true

at php-worker/supervisord.d/laravel-worker.conf

Redis Tweaks

For Redis I have added redis/redis.conf from Redis itself. For Redis 4 you get get it here . Really good to add this for security purposes. If you do want it to work you need to have

 bind 0.0.0.0

otherwise the Laravel app cannot use its services.

Nginx Tweaks

Default configuration will be added right away and is

server {

    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    # For https
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server ipv6only=on;
    # ssl_certificate /etc/nginx/ssl/default.crt;
    # ssl_certificate_key /etc/nginx/ssl/default.key;

    server_name localhost;
    root /var/www/public;
    index index.php index.html index.htm;

    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }
}

There are also some other config files. You just pick one or copy default and remove it. As you see we will need to uncomment SSL and make sure the paths are correct. We should also add some stuff for browser caching such as..

Certbot and Nginx

As you can see SSL is not on by default though. Also Certbot is not connected to it. This is because run-certbot.sh uses

cp /etc/letsencrypt/archive/"$CN"/cert1.pem /var/certs/cert1.pem
cp /etc/letsencrypt/archive/"$CN"/privkey1.pem /var/certs/privkey1.pem

to copy thins over to /var/certs/ . And the server configs look at

# ssl_certificate /etc/nginx/ssl/default.crt; 
# ssl_certificate_key /etc/nginx/ssl/default.key;

So either adjust the default.conf, or remove it and use a new one that does load the certs and from the proper location OR adjust the certbot .sh file.

Container Jumpstart

You can now start the containers using

docker-compose -f prod-docker-compose.yml up -d

Database Import

You will either need to run a basic migration or import the database as you have already. Most of the time we do have a database setup already so I fire up Sequel Pro and import the database. As stated you could remove the ports once done and rebuild the database container for security purposes.

Laravel Setup

We now need to go into workspace and install the Laravel app properly:

docker-compose -f prod-docker-compose.yml exec --user=laradock bash

Do the following commands:

 composer install
npm install
Tagged in : Tagged in :
Jasper Frumau

Jasper has been working with web frameworks and applications such as Laravel, Magento and his favorite CMS WordPress including Roots Trellis and Sage for more than a decade. He helps customers with web design and online marketing. Services provided are web design, ecommerce, SEO, content marketing. When Jasper is not coding, marketing a website, reading about the web or dreaming the internet of things he plays with his son, travels or run a few blocks.