Saga Migrării de WordPress – Ghid pas cu pas pentru Ubuntu 18.04

8 min read
De pe Le blog de Laurel

Iată a treia postare, și ultima, din Saga Migrării de WordPress, o serie care prezintă migrarea unui website WordPress deja existent pe un alt host, în Docker.

În această postare vom vedea pas cu pas cum se poate face migrarea unui website WordPress spre Docker pe Linux.

Pentru a te familiariza puțin cu mediul de lucru în Docker și Docker Compose, citește prima dată partea a doua, Acomodarea cu Docker.

Configurarea structurii directorului website-ului

Pentru a păstra datele în noul container Docker, va trebui să stocăm datele într-un volum director pe care îl vom monta pe container-ul nostru Docker.

Prima dată, dacă nu avem deja fișierul zip, să comprimăm site-ul nostru WordPress într-un fișier de tip zip numitsite.zip, pe calculatorul local. Se poate folosi utilitarul zip în interiorul directorului, pentru a înlătura directorul părinte din fișierul zip final.

cd local/site1.com; zip -r ../site.zip *

În continuare, pe Linode vom crea un director pentru site-ul nostru, și vom copia datele de pe calculatorul nostru pe host-ul Linode. Ia aminte că 192.0.2.0 este un IP de test, schimbă-l cu IP-ul server-ului tău.

# on the Linode instance, create the folder and its parents, if they don't exist
mkdir -pv /var/www/site1.com/src
mkdir -pv /var/www/site1.com/database/data
mkdir -pv /var/www/site1.com/database/initdb.d
# from the local computer, copy the zip file and database.sql to the Linode instance
scp local/site1.com/database.sql your_username@192.0.2.0:/var/www/site1.com/database/initdb.d
scp local/site1.com/site.zip your_username@192.0.2.0:/var/www/site1.com
# on the Linode instance, decompress the file
cd /var/www/site1.com/
apt-install unzip
unzip site.zip -d src/
rm site.zip

Directorul nostru ar trebui să aibă următoarea structură:

.
 └── site1.com
     ├── .env
     ├── database
     │   ├── data
     │   └── initdb.d
     │       └── database.sql
     ├── docker-compose.yml
     └── src
         ├── …
         ├── wp-admin
         ├── …
         └── xmlrpc.php

Acum că am decis care va fi structura directorului nostru, creăm un fișier atașat .env care va păstra datele de identitate. Poți folosi vim pentru a crea fișierele, sau editorul tău favorit.

De obicei scriu fișierele în VSCode, apăs Ctrl+C, apoi merg în linia de comandă, vim cu numele fișierului, gg+dG să șterg tot conținutul, i să trec pe modul de inserare, Shift+Ctrl+V să lipesc conținutul din VSCode, ESC și :wq! să ies din fișier și să se scrie schimbările. O altă opțiune ar fi să setez acces remote la server din VSCode.

DB_ROOT_PASSWORD=my_secret_passwd
DB_NAME=my_secret_name
DB_USER=my_secret_user
DB_PASSWORD=my_secret_passwd2

Optional, pentru că fișierul .env conține informații sensibile, poți să-l incluzi în fișierele .gitignore și .dockerignore ale proiectului, fapt care le va spune lui Git and Docker ce fișiere să nu copieze în depozitele Git și respectiv în imaginile Docker (dacă vom dori versionare).

.env
.git
docker-compose.yml
.dockerignore

Acum, să creăm fișierul docker-compose.yml.

version: '3.7'

networks:
    wp-back-myblog:

services:
    mysql_myblog:
        container_name: wp_myblog_db
        image: mysql:5.7
        volumes:
            - ./database/data:/var/lib/mysql
            - ./database/initdb.d:/docker-entrypoint-initdb.d
        restart: always
        env_file: .env
        environment:
            MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
            MYSQL_DATABASE: $DB_NAME
            MYSQL_USER: $DB_USER
            MYSQL_PASSWORD: $DB_PASSWORD
        networks:
            - wp-back-myblog
        command: 
            --default-authentication-plugin=mysql_native_password

    wp_myblog:
        container_name: wp_myblog
        depends_on:
            - mysql_myblog
        image: WordPress
        volumes:
            - ./src:/var/www/html
        ports:
            - 1234:80
        networks:
            - wp-back-myblog
        restart: always
        env_file: .env
        environment:
            WordPress_DB_HOST: mysql_myblog:3306
            WordPress_DB_NAME: $DB_NAME
            WordPress_DB_USER: $DB_USER
            WordPress_DB_PASSWORD: $DB_PASSWORD

Aici definim:

  • versiunea de fișier pentru Compose
  • două servicii, unul pentru baza de date, altul pentru aplicația WordPress
  • image îi spune lui Compose ce imagine să aducă să creeze containerul
  • container_name specifică un nume pentru container
  • restart definește politica de restart a container-ului
  • env_file îi spune lui Compose că am dori să adăugăm variabile de environment dintrun fișier numit .env, situat în contextul nostru de build
  • environment ne permite să adăugăm variabile de environment adiționale, pe lângă cele definite în fișierul nostru .env
  • volumes montează bind mounts:
    • directorul local ./database/data , montat pe directorul /var/lib/mysql pe container, este directorul standard de date pentru MySQL pe majoritatea distribuțiilor
    • directorul local ./database/initdb.d, montat pe directorul /docker-entrypoint-initdb.dpe container, va fi folosit pentru prepopularea bazei de date
    • montat pe directorul ./src , montat pe directorul /var/www/html pe container, va fi casa website-ului nostru
  • networks specifică rețeaua care va fi împărțită de aplicațiile noastre
  • depends_on se asigură că containerele noastre vor porni în ordinea dependențelor, cu containerul wp_myblog pornind după containerul mysql_myblog
  • ports este o opțiune care expune port-ul 1234, vrem ca WordPress să fie accessibil prin intermediul port-ului 1234 pe host-ul nostru
  • command MySQL 8.0 a schimbat plugin-ul implicit de autentificare, și clienții mai vechi s-ar putea să nu se poată conecta, trebuie adăugat --default-authentication-plugin=mysql_native_password (src)

Când containerul mysql_myblog este pornit pentru prima dată, o nouă bază de date cu numele specificat va fi creată și inițializată cu variabilele oferite în configurație. Mai mult, va executa fișierele cu extensii.sh, .sql și .sql.gz care se găsesc în /docker-entrypoint-initdb.d. Vom popula serviciul nostru mysql prin montarea exportului SQL în acest director, iar fișierele SQL vor fi importate în mod implicit în baza de date specificată de variabila MYSQL_DATABASE. (src)

În timp ce bind mounts sunt dependente de structura directorului pe mașina de host, volumes sunt administrate în întregime de către Docker. (src)

Acum, crează containerele cu docker-compose up și indicatorul -d, care va rula containerele mysql_myblog și wp_myblog pe fundal, și verifică starea serviciilor.

# check status
docker-compose ps
# see logs
docker-compose logs
# follow specific log for testing
docker logs -f a80

Dacă starea serviciilor este up, ar trebui să poți accesa 192.0.2.0:1234 și să vezi website-ul tău WordPress. În continuare, vom folosi NGINX să corelăm https://site1.com cu aplicația noastră situată la 192.0.2.0:1234.

Folosirea NGINX ca Reverse Proxy pentru containerele noastre Docker

Vrem ca website-ul nostru să fie securizat, așa că vom activa HTTPS atât în fișierul wp-config.php file cât și în fișierul de configurare pentru nginx, ca să evităm probleme de genul ‘The page isn’t redirecting properly‘. Să adăugăm următoarele constante în wp-config.php

$_SERVER['HTTPS'] = 'on';
define('FORCE_SSL_ADMIN',   true);
define('FORCE_SSL_LOGIN',   true);
define('FORCE_SSL_CONTENT', true);

Înainte de a obține efectiv un certificat Let’s Encrypt trebuie instalat Certbot. Certbot este clientul oficial pentru Let’s Encrypt și totodată cea mai ușoară cale de a obține un certificat. Se poate rula certbot cu opțiunea --staging pentru a-ți testa setările, apoi se poate schimba această opțiune cu --force-renewalpentru a obține certificatele finale. Sunt stabilite limitări de frecvență care asigură că oamenii nu abuzează de serviciu, ai grijă să folosești mediul de staging cât timp testezi.

# stop nginx, certbot conflicts with nginx on port 80
sudo service nginx stop
# install certbot
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
# create the certificate
certbot certonly --standalone --preferred-challenges http --email admin@site1.com --noninteractive --quiet --agree-tos -d site1.com -d www.site1.com  --expand
# list the certificates
sudo certbot certificates
# test the renewal script
sudo certbot renew --dry run
# start nginx
sudo service nginx start 

Crează un fișier de configurare pentru nginx numit site1.com.conf în /etc/nginx/conf.d. Acest fișier îi va permite lui nginx să facă redirecționările potrivite de la HTTP la HTTPS, și proxy către aplicația WordPress.

server {
    listen 80;
    listen [::]:80;

    server_name site1.com www.site1.com;
    rewrite ^ https://$server_name$request_uri? permanent;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name site1.com www.site1.com;

    root /var/www/site1.com;
    index index.php;

    ssl_certificate /etc/letsencrypt/live/site1.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/site1.com/privkey.pem;

    gzip on;
    gzip_comp_level 3;
    gzip_types text/css image/jpg image/jpeg image/png image/svg;

    location / {
        proxy_pass http://0.0.0.0:1234;
        proxy_set_header Accept-Encoding "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

În fișierul de mai sus, avem următoarele opțiuni:

  • listen îi spune lui NGINX să asculte port-ul 80, respectiv 443
  • server_name definește numele server-ului nostru și blocul de server care ar trebui folosit pentru cereri către serverul nostru
  • rewrite este folosit pentru redirecționarea traficului total de la HTTP la HTTPS
  • index definește fișierele care vor fi folosite ca indexe în timpul procesării cererilor către serverul tău
  • root numește directorul rădăcină pentru cererile către server-ul nostru
  • location / este blocul în care directive specifice vor face proxy la cererile către aplicația WordPress

Și… Voilà! Dacă rulăm nginx reload ar trebui să putem accesa website-ul nostru la https://site1.com 🤗

Pentru debugging, putem folosi netstat -nlp să verificăm port-urile care ascultă, docker ps -a și docker logs -f wp_myblog pentru a urmări logurile, nginx -t pentru erorile din nginx. Pentru a face copii de rezervă putem folosi mysqldump și ceva serviciu de cron cu scp pentru blog (sau versionare).

# test connection to the database
docker exec -it wp_myblog_db mysql -u$DB_USER --password=$DB_PASSWORD $DB_NAME
# backup
docker exec wp_blogmap_db /usr/bin/mysqldump -u root --password=$DB_PASSWORD $DB_NAME > backup.sql
# restore
cat backup.sql | docker exec -i wp_blogmap_db /usr/bin/mysql -u$DB_USER --password=$DB_PASSWORD $DB_NAME

Pentru a migra website-uri WordPress multiple pe același host, este nevoie doar să adaugi structura directorului pentru fiecare dintre ele, să adaugi fișiere de configurare nginx pentru fiecare, și să schimbi port-ul din 1234 în alte port-uri libere.

Mai sunt multe alte aspecte de care nu mă voi atinge în postarea aceasta, cum ar fi creșterea securității, rularea containerelor ca și user-ul curent, folosirea lui nginx proxy și certbot ca imagini Docker, rularea unui serviciu crontab pentru actualizarea certificatelor de la certbot, CI/CD.. Cum să scapi de WordPress și să faci o aplicație Node.js. Cum să te asiguri că ai montat volumele corect și nu-ți pierzi datele.. Ansible cine? 😅

De asemenea, sunt multe lucruri pe care le descoper despre Docker chiar acum, ăsta-i doar vârful iceberg-ului. Nu ezitați să mă contactați dacă vedeți informații eronate, sau parolele mele de la server afișate liber. 😅 Sper doar că această postare a fost de ajutor pentru cei care sunt la început cu Docker și vor să învețe mai multe despre el. 🌱🌱🌞

Mă bucur și că am aflat de Le blog de Laurel, face niște ilustrații extraordinare. Bine.. fiecare zi e o Sărbătoare 😍

De pe Le blog de Laurel

Extra Junk

Examplu de structură de directoare pentru mai multe bloguri și nginx instalat pe host:

.
 ├── site1.com
 │   ├── .env
 │   ├── database
 │   │   ├── data
 │   │   └── initdb.d
 │   │       └── database.sql
 │   ├── docker-compose.yml
 │   └── src
 │       ├── …
 │       ├── wp-admin
 │       ├── …
 │       └── xmlrpc.php
 └── site2.com
     ├── .env
     ├── database
     │   ├── data
     │   └── initdb.d
     │       └── database.sql
     ├── docker-compose.yml
     └── src
         ├── …
         ├── wp-admin
         ├── …
         └── xmlrpc.php

Examplu de structură de directoare pentru folosirea imaginii jwilder/nginx-proxy (după asta )

.
 ├── site1.com
 │   ├── .dockerignore
 │   ├── .env
 │   ├── .gitignore
 │   ├── database
 │   ├── docker-compose.yml
 │   └── src
 ├── site2.com
 │   ├── .dockerignore
 │   ├── .env
 │   ├── .gitignore
 │   ├── database
 │   ├── docker-compose.yml
 │   └── src
 └── nginx
     └── docker-compose.yml
version: '3'

services:
  nginx:
    image: jwilder/nginx-proxy:alpine
    container_name: nginx
    restart: always
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: 'true'
    ports:
      - 80:80
      - 443:443
    volumes:
      - /srv/nginx/data/certs:/etc/nginx/certs:ro
      - /srv/nginx/data/conf.d:/etc/nginx/conf.d
      - /srv/nginx/data/vhost.d:/etc/nginx/vhost.d
      - /srv/nginx/data/html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - proxy
      
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt
    volumes:
      - /srv/nginx/data/vhost.d:/etc/nginx/vhost.d
      - /srv/nginx/data/certs:/etc/nginx/certs:rw
      - /srv/nginx/data/html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
    depends_on:
      - nginx
    networks:
      - proxy
    
networks:
  proxy:
    driver: bridge
    jwilder/nginx-proxy 
DB_CONTAINER=my_container

DB_ROOT_PASSWORD=my_passwd
DB_NAME=my_user
DB_PASSWORD=my_passwd2

WP_CONTAINER=my_container2

VIRTUAL_HOST=site1.com,www.site1.com

LETSENCRYPT_EMAIL=admin@site1.com
version: '3'

services:

  db:
    container_name: $DB_CONTAINER
    image: mysql:5.7
    restart: always
    env_file: .env
    volumes:
      - ./database/data:/var/lib/mysql
      - ./database/initdb.d:/docker-entrypoint-initdb.d
    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: $DB_ROOT_PASSWORD
      MYSQL_DATABASE: $DB_NAME
      MYSQL_USER: $DB_USER
      MYSQL_PASSWORD: $DB_PASSWORD
    command: 
      --default-authentication-plugin=mysql_native_password

  wp:
    container_name: $WP_CONTAINER
    depends_on:
      - db
    image: WordPress
    restart: always
    ports:
      - "1234:80"
    volumes:
      - ./src:/var/www/html
    env_file: .env
    environment:
      WordPress_DB_HOST: ${DB_CONTAINER}:3306
      WordPress_DB_NAME: $DB_NAME
      WordPress_DB_USER: $DB_USER
      WordPress_DB_PASSWORD: $DB_PASSWORD
      VIRTUAL_HOST: $VIRTUAL_HOST
      LETSENCRYPT_HOST: $VIRTUAL_HOST
      LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL
      LETSENCRYPT_TEST: 'true'

networks:
  default:
    external:
      name: nginx_proxy

Examplu de structură de directoare pentru un singur website si nginx-proxy si certbot drept imagini Docker (după asta)

└── site1.com
     ├── .dockerignore
     ├── .env
     ├── .gitignore
     ├── database
     │   ├── data
     │   └── initdb.d
     ├── docker-compose.yml
     ├── nginx-conf
     │   ├── nginx.conf
     │   └── options-ssl-nginx.conf
     └── src
         ├── …
         ├── wp-admin
         └── xmlrpc.php
version: '3'

services:
    db:
        image: mysql:8.0
        container_name: db
        restart: unless-stopped
        env_file: .env
        environment:
            - MYSQL_ROOT_PASSWORD=$DB_ROOT_PASSWORD
            - MYSQL_DATABASE=$DB_NAME
            - MYSQL_USER=$DB_USER
            - MYSQL_PASSWORD=$DB_PASSWORD
        volumes: 
            - ./database/data:/var/lib/mysql
            - ./database/initdb.d:/docker-entrypoint-initdb.d
        command: '--default-authentication-plugin=mysql_native_password'
        networks:
            - app-network
    WordPress:
        depends_on: 
            - db
        image: WordPress:5.1.1-fpm-alpine
        container_name: WordPress
        restart: unless-stopped
        env_file: .env
        environment:
            - WordPress_DB_HOST=db:3306
            - WordPress_DB_USER=$DB_USER
            - WordPress_DB_PASSWORD=$DB_PASSWORD
            - WordPress_DB_NAME=$DB_NAME
        volumes:
            - ./src:/var/www/html
        networks:
            - app-network
    webserver:
        depends_on:
            - WordPress
        image: nginx:1.15.12-alpine
        container_name: webserver
        restart: unless-stopped
        ports:
            - "80:80"
            - "443:443"
        volumes:
            - ./src:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
        networks:
            - app-network
    certbot:
        depends_on:
            - webserver
        image: certbot/certbot
        container_name: certbot
        volumes:
            - certbot-etc:/etc/letsencrypt
            - ./src:/var/www/html
        command: certonly --webroot --webroot-path=/var/www/html --email admin@site1.com --agree-tos --no-eff-email --force-renewal -d site1.com -d www.site1.com
volumes:
    certbot-etc:
networks:
    app-network:
        driver: bridge 

Referințe

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *