راهنمای به‌روزرسانی SSL برای BigBlueButton + HAProxy

راهنمای به‌روزرسانی SSL برای BigBlueButton + HAProxy

=====================================================

دامنه:

site.com


معماری SSL این سرور

===================

در این سرور SSL روی HAProxy terminate می‌شود، نه روی Nginx.

Certificate جدید Let's Encrypt:

/etc/letsencrypt/live/site.com/fullchain.pem

Private Key:

/etc/letsencrypt/live/site.com/privkey.pem

Certificate مورد استفاده HAProxy:

/etc/haproxy/certbundle.pem

کانفیگ HAProxy:

/etc/haproxy/haproxy.cfg

کانفیگ Nginx مربوط به BigBlueButton:

/etc/nginx/sites-enabled/bigbluebutton

HAProxy روی پورت 443 فعال است.

Nginx روی پورت‌های داخلی 81 و 82 کار می‌کند.


=====================================================

بررسی Certificate

=====================================================

بررسی Certificate جدید Let's Encrypt:

sudo openssl x509 -in /etc/letsencrypt/live/site.com/fullchain.pem -noout -subject -issuer -dates


بررسی Certificate فعلی HAProxy:

sudo openssl x509 -in /etc/haproxy/certbundle.pem -noout -subject -issuer -dates


اگر Certificate داخل certbundle.pem قدیمی یا منقضی بود، مراحل زیر را انجام بده.


=====================================================

مرحله 1 - Backup

=====================================================

قبل از هر تغییری از Certificate فعلی HAProxy بکاپ بگیر:

sudo cp -a /etc/haproxy/certbundle.pem /etc/haproxy/certbundle.pem.backup-$(date +%Y%m%d-%H%M%S)


=====================================================

مرحله 2 - ساخت Bundle جدید

=====================================================

HAProxy به یک فایل PEM نیاز دارد که شامل Private Key و Certificate Chain باشد.

دستور:

sudo sh -c 'cat /etc/letsencrypt/live/site.com/privkey.pem /etc/letsencrypt/live/site.com/fullchain.pem > /etc/haproxy/certbundle.pem'


=====================================================

مرحله 3 - تنظیم Permission

=====================================================

sudo chown root:root /etc/haproxy/certbundle.pem

sudo chmod 600 /etc/haproxy/certbundle.pem


=====================================================

مرحله 4 - بررسی Certificate جدید

=====================================================

sudo openssl x509 -in /etc/haproxy/certbundle.pem -noout -subject -issuer -dates

تاریخ notAfter باید تاریخ انقضای Certificate جدید باشد.


=====================================================

مرحله 5 - تست کانفیگ HAProxy

=====================================================

قبل از Reload حتماً کانفیگ را تست کن:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

اگر Configuration معتبر بود، ادامه بده.

اگر خطا داد، HAProxy را Reload نکن.


=====================================================

مرحله 6 - Reload کردن HAProxy

=====================================================

sudo systemctl reload haproxy


سپس وضعیت را بررسی کن:

sudo systemctl status haproxy --no-pager

باید ببینی:

Active: active (running)


=====================================================

مرحله 7 - تست Certificate واقعی سایت

=====================================================

این مهم‌ترین تست نهایی است:

echo | openssl s_client -connect site.com:443 -servername site.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates

تاریخ notAfter باید مربوط به Certificate جدید باشد.


=====================================================

اگر سایت بعد از Reload بالا نیامد

=====================================================

وضعیت HAProxy:

sudo systemctl status haproxy --no-pager


لاگ HAProxy:

sudo journalctl -u haproxy -n 100 --no-pager


تست کانفیگ:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg


بررسی پورت‌ها:

sudo ss -lntp | grep -E ':443|:81|:82'


بررسی Nginx:

curl -v http://127.0.0.1:81/


=====================================================

نکته مهم برای تمدیدهای آینده

=====================================================

در این سرور، تمدید Certificate در Let's Encrypt به‌تنهایی کافی نیست.

Let's Encrypt Certificate را در این مسیر قرار می‌دهد:

/etc/letsencrypt/live/site.com/


اما HAProxy از این فایل استفاده می‌کند:

/etc/haproxy/certbundle.pem


بنابراین بعد از هر تمدید Certificate باید:

1. certbundle.pem را با Certificate جدید بسازی.

2. Permission را تنظیم کنی.

3. کانفیگ HAProxy را تست کنی.

4. HAProxy را Reload کنی.

5. Certificate واقعی سایت را تست کنی.


=====================================================

دستورهای اصلی برای دفعات بعد

=====================================================

Backup:

sudo cp -a /etc/haproxy/certbundle.pem /etc/haproxy/certbundle.pem.backup-$(date +%Y%m%d-%H%M%S)


ساخت Bundle:

sudo sh -c 'cat /etc/letsencrypt/live/site.com/privkey.pem /etc/letsencrypt/live/site.com/fullchain.pem > /etc/haproxy/certbundle.pem'


Permission:

sudo chown root:root /etc/haproxy/certbundle.pem

sudo chmod 600 /etc/haproxy/certbundle.pem


تست:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg


Reload:

sudo systemctl reload haproxy


تست نهایی:

echo | openssl s_client -connect site.com:443 -servername site.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates


=====================================================

پیشنهاد برای آینده

=====================================================

بهتر است این فرآیند را با Certbot deploy-hook خودکار کنیم.

در آن حالت هر بار Certificate با موفقیت تمدید شود، سیستم به‌صورت خودکار:

- certbundle.pem را به‌روز می‌کند

- Permission را تنظیم می‌کند

- کانفیگ HAProxy را تست می‌کند

- HAProxy را Reload می‌کند

با این کار دیگر لازم نیست هر 6 ماه این کارها را دستی انجام بدهی.

راهنمای کامل نصب MySQL + Nginx + phpMyAdmin روی Ubuntu 24.04

# راهنمای کامل نصب MySQL + Nginx + phpMyAdmin روی Ubuntu 24.04

## مشخصات سیستم

- Ubuntu 24.04.1 LTS
- MySQL 8
- Nginx
- PHP 8.3
- phpMyAdmin

---

# 1) تنظیم مخازن Ubuntu روی Mirror آروان

فایل سورس:

```bash
nano /etc/apt/sources.list

محتوا:

deb http://mirror.arvancloud.ir/ubuntu noble main restricted universe multiverse
deb http://mirror.arvancloud.ir/ubuntu noble-updates main restricted universe multiverse
deb http://mirror.arvancloud.ir/ubuntu noble-backports main restricted universe multiverse
deb http://mirror.arvancloud.ir/ubuntu noble-security main restricted universe multiverse

آپدیت:

apt clean
apt update

بررسی سورس‌های اضافی:

grep -R "ubuntu.com" /etc/apt/

در صورت وجود فایل اضافی:

mv /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak

2) نصب MySQL

apt install mysql-server -y

بررسی وضعیت:

systemctl status mysql

بررسی نسخه:

mysql --version

3) تنظیم رمز برای root در MySQL

ورود:

mysql

تنظیم پسورد:

ALTER USER 'root'@'localhost'
IDENTIFIED WITH caching_sha2_password
BY 'YourStrongPassword!';

FLUSH PRIVILEGES;
EXIT;

تست ورود:

mysql -u root -p

4) نصب Nginx

apt install nginx -y

فعال‌سازی:

systemctl enable nginx
systemctl restart nginx

بررسی:

systemctl status nginx

5) نصب PHP و افزونه‌ها

apt install php-fpm php-mysql php-cli php-mbstring php-zip php-gd php-json php-curl unzip -y

بررسی نسخه:

php -v

6) نصب phpMyAdmin

apt install phpmyadmin -y

هنگام نصب:

  • web server → چیزی انتخاب نشود

  • dbconfig-common → Yes

7) تنظیم phpMyAdmin روی Nginx

ساخت فایل:

nano /etc/nginx/conf.d/phpmyadmin.conf

محتوا:

server {
    listen 80;
    server_name pma.example.com;

    root /usr/share/phpmyadmin;
    index index.php;

    location / {

        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.pma_pass;

        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

تست nginx:

nginx -t

ریلود:

systemctl reload nginx

8) فعال‌سازی Basic Auth برای phpMyAdmin

نصب ابزار:

apt install apache2-utils -y

ساخت یوزر:

htpasswd -c /etc/nginx/.pma_pass admin

رمز عبور وارد کنید.

9) اتصال دامنه

DNS:

A Record

مثال:

pma.example.com -> YOUR_SERVER_IP

10) نصب SSL رایگان Let's Encrypt

apt install certbot python3-certbot-nginx -y

دریافت SSL:

certbot --nginx -d pma.example.com

11) رفع خطای phpMyAdmin controluser

خطا:

mysqli::real_connect():
Access denied for user 'phpmyadmin'@'localhost'

ویرایش فایل:

nano /etc/phpmyadmin/config.inc.php

پیدا کردن:

$dbuser='phpmyadmin';
$dbpass='...';

$cfg['Servers'][$i]['controluser'] = $dbuser;
$cfg['Servers'][$i]['controlpass'] = $dbpass;

کامنت کردن:

// $dbuser='phpmyadmin';
// $dbpass='...';

// $cfg['Servers'][$i]['controluser'] = $dbuser;
// $cfg['Servers'][$i]['controlpass'] = $dbpass;

ریستارت سرویس‌ها:

systemctl restart php8.3-fpm
systemctl restart nginx

12) دستورات مفید

ریستارت nginx:

systemctl restart nginx

ریستارت PHP:

systemctl restart php8.3-fpm

ریستارت MySQL:

systemctl restart mysql

تست nginx:

nginx -t

بررسی پورت‌ها:

ss -tulpn

نرم‌افزارهای نصب شده

  • MySQL 8

  • Nginx

  • PHP 8.3

  • phpMyAdmin

  • Certbot

  • Basic Auth

 

برای اینکه کابل را کلاً جدا کنی و از طریق شبکه کد بزنی برای فلاتر، این مراحل را برو

۱. پیدا کردن IP گوشی

  • در گوشی به مسیر Settings > About Phone > Status برو (یا در تنظیمات وای‌فای روی شبکه کلیک کن).
  • عددی مثل 192.168.1.5 را یادداشت کن.

۲. فعال‌سازی حالت بی‌سیم (فقط برای بار اول)

  • یک بار گوشی را با کابل وصل کن.
  • در CMD سیستم تایپ کن: adb tcpip 5555.
  • حالا کابل را جدا کن.

۳. اتصال نهایی

  • در CMD تایپ کن (بجای IP، عدد گوشی خودت را بزن):
    adb connect 192.168.1.5:5555
  • اگر پیام connected را دیدی، یعنی تمام!

۴. اجرای Scrcpy

  • حالا کافیست تایپ کنی scrcpy تا تصویر بدون کابل بالا بیاید.
  • در VSCode هم گوشی به عنوان یک Device بی‌سیم شناخته می‌شود.

💡 نکته طلایی برای سرعت بیشتر:
چون وای‌فای ممکن است کمی تاخیر (Lag) داشته باشد، اگر حس کردی تصویر کند است، Scrcpy را با این دستور باز کن تا پهنای باند کمتری مصرف کند:
scrcpy --bit-rate 2M --max-fps 30

چک‌لیست کاملاً امن و استاندارد برای پاکسازی فضای سرور اوبونتو

در ادامه یک چک‌لیست کاملاً امن و استاندارد برای پاکسازی فضای سرور اوبونتو و همچنین مشاهده حجم پوشه‌ها می‌دهم. تمام دستورات بی‌خطر هستند و چیزی را بدون اجازه شما حذف نمی‌کنند.


1) دیدن حجم پوشه‌ها (پیدا کردن محل پرشدن دیسک)

برای یافتن پوشه‌های حجیم:

 

content_copy text

sudo du -h --max-depth=1 /

برای بررسی یک مسیر خاص (مثلاً /var):

 

content_copy text

sudo du -h --max-depth=1 /var

برای نمایش فقط ۱۰ پوشه/فایل پرحجم کل سیستم:

 

content_copy text

sudo du -ah / | sort -hr | head -n 10

برای وضعیت کلی فضای دیسک:

 

content_copy text

df -h


2) پاکسازی امن (بدون اختلال در سرویس‌ها)

پاکسازی apt cache (کاملاً امن)

 

content_copy text

sudo apt autoremove sudo apt clean sudo apt autoclean


پاکسازی لاگ‌های سنگین در /var/log

(لاگ‌ها را حذف نمی‌کنیم، بلکه خالی می‌کنیم تا سرویس‌ها آسیب نبینند)

دیدن حجم لاگ‌ها:

 

content_copy text

sudo du -sh /var/log/*

خالی کردن فایل‌های لاگ بزرگ:

 

content_copy text

sudo truncate -s 0 /var/log/*.log

اگر داخل پوشه‌ها لاگ باشد:

 

content_copy text

sudo find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;

کاملاً امن است.


پاکسازی فایل‌های موقت

 

content_copy text

sudo rm -rf /tmp/* sudo rm -rf /var/tmp/*

(بی‌خطر)


چک کردن journal logs (گاهی خیلی حجیم می‌شوند)

دیدن حجم:

 

content_copy text

journalctl --disk-usage

محدود کردن حجم به مثلا 200MB:

 

content_copy text

sudo journalctl --vacuum-size=200M


پاکسازی هسته‌های قدیمی (Kernel)

اوبونتو معمولاً هسته‌های قدیمی را نگه می‌دارد. حذفشان امن است:

 

content_copy text

sudo apt autoremove --purge


پاکسازی Snap (اگر استفاده نمی‌کنید خیلی فضا می‌گیرد)

دیدن نسخه‌های قدیمی:

 

content_copy text

snap list --all

حذف نسخه‌های disabled:

 

content_copy text

sudo snap remove --revision

برای حذف خودکار نسخه‌های قدیمی:

 

content_copy text

sudo snap set system refresh.retain=2

python-win32com excel com model started generating errors

32

Over the last few days, I have been working on automating the generation of some pivot tables for a number of reports.

Boiled down to the minimum, the following code was working without issue:

import win32com.client objExcelApp = win32com.client.gencache.EnsureDispatch('Excel.Application') objExcelApp.Visible = 1

Explain

This would pop-up an instance of excel and I could continue working in Python. But suddenly, today my scripts are failing with the following:

module 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9' has no attribute 'CLSIDToClassMap'


I had the same issue and I resolved it by following the instructions here: https://mail.python.org/pipermail/python-win32/2007-August/006147.html

Deleting the gen_py output directory and re-running makepy SUCCEEDS and subsequently the test application runs OK again.

So the symptom is resolved, but any clues as to how this could have happened. This is a VERY long running application (think 24x7 for years) and I'm concerned that whatever caused this might occur again.

To find the output directory, run this in your python console / python session:

import win32com print(win32com.__gen_path__)

Explain

or, even better, a one-liner in the command line:

python -c "import win32com; print(win32com.__gen_path__)"

Explain

Based on the exception message in your post, the directory you need to remove will be titled '00020813-0000-0000-C000-000000000046x0x1x9'. So delete this directory and re-run the code. And if you're nervous about deleting it (like I was) just cut the directory and paste it somewhere else.

💡Note that this directory is usually in your "TEMP" directory (copy-paste %TEMP%/gen_py in Windows File Explorer and you will arrive there directly).

I have no idea why this happens nor do I know how to prevent it from happening again, but the directions in the link I provided seemed to work for me.

https://stackoverflow.com/a/54422675

Policy restrictions on running scripts in Windows

vue --version
+ ~~~
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess

Open PowerShell with administrator privileges:

Search for "PowerShell" in the Windows search bar
Right-click on "Windows PowerShell" and select "Run as administrator"
Run the following command in PowerShell to change the script execution policy:
𝑃PowerShell
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

After running this command, you can try running the vue --version command again and you should be able to see the installed version of the Vue CLI.

If the issue persists even after this, you can try using a different shell environment, such as Git Bash or Windows Terminal, to run the Vue CLI commands.

change permissions for a folder and its subfolders/files

The other answers are correct, in that chmod -R 755 will set these permissions to all files and subfolders in the tree. But why on earth would you want to? It might make sense for the directories, but why set the execute bit on all the files?

I suspect what you really want to do is set the directories to 755 and either leave the files alone or set them to 644. For this, you can use the find command. For example:

To change all the directories to 755 (drwxr-xr-x):

find /opt/lampp/htdocs -type d -exec chmod 755 {} \;

To change all the files to 644 (-rw-r--r--):

find /opt/lampp/htdocs -type f -exec chmod 644 {} \;

Some splainin': (thanks @tobbez)

  • chmod 755 {} specifies the command that will be executed by find for each directory
  • chmod 644 {} specifies the command that will be executed by find for each file
  • {} is replaced by the path
  • ; the semicolon tells find that this is the end of the command it's supposed to execute
  • \; the semicolon is escaped, otherwise it would be interpreted by the shell instead of find

https://stackoverflow.com/a/11512211

Different ways to send an email with Golang

In this blog, we’ll look at different methods to send an email with Go, First we will explore inbuilt smtp package, then we will move to use a popular package Gomail and finally we will send HTML emails using custom templates.

Before You Get Started

This tutorial assumes you have:

  • A basic understanding of Go Language
  • Latest GoLang version installed on your system
  • A few minutes of your time.

In this blog, we’ll look at different methods to send an email with Go, First, we will explore inbuilt smtp package, then we will move to use a popular package Gomail and finally, we will send HTML emails using custom templates.

Package smtp

smtp is an inbuilt package provided with Golang. It implements the Simple Mail Transfer Protocol and has multiple functionalities related to it. Here to send the email we will be using only two functions PlainAuth and SendMail from the package.

Note: Click here for an overview on Go Functions

  • PlainAuth: It uses the given username and password to authenticate to host and return an identity
  • SendMail: It connects to the server at address, switches to TLS if possible, authenticates with the optional mechanism an if possible, and then sends an email to the sender.

Below is the complete code to send a plain text email with smtp package in golang.

package main

import (
  "fmt"
  "net/smtp"
)

func main() {

  // Sender data.
  from := "from@gmail.com"
  password := ""

  // Receiver email address.
  to := []string{
    "sender@example.com",
  }

  // smtp server configuration.
  smtpHost := "smtp.gmail.com"
  smtpPort := "587"

  // Message.
  message := []byte("This is a test email message.")
  
  // Authentication.
  auth := smtp.PlainAuth("", from, password, smtpHost)
  
  // Sending email.
  err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, message)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("Email Sent Successfully!")
}

In the above code example we have used smtp details of a Gmail account, you should update the smtp detail according to your email provider.

Just to explain things easily, In the above snippet, we have written all the smtp and email credentials in the main function, Though in a production app you should always use env variables for configurations. You can check Viper to manage configurations in production apps.

Package Gomail

Below is the complete code to send a plain text email with Gomail package in golang.

package main

import (
  "crypto/tls"
  "fmt"

  gomail "gopkg.in/mail.v2"
)

func main() {
  m := gomail.NewMessage()

  // Set E-Mail sender
  m.SetHeader("From", "from@gmail.com")

  // Set E-Mail receivers
  m.SetHeader("To", "to@example.com")

  // Set E-Mail subject
  m.SetHeader("Subject", "Gomail test subject")

  // Set E-Mail body. You can set plain text or html with text/html
  m.SetBody("text/plain", "This is Gomail test body")

  // Settings for SMTP server
  d := gomail.NewDialer("smtp.gmail.com", 587, "from@gmail.com", "")

  // This is only needed when SSL/TLS certificate is not valid on server.
  // In production this should be set to false.
  d.TLSConfig = &tls.Config{InsecureSkipVerify: true}

  // Now send E-Mail
  if err := d.DialAndSend(m); err != nil {
    fmt.Println(err)
    panic(err)
  }

  return
}

Custom HTML Templates

Now, let's send an HTML email with smtp package, for this, we need to create two files in the root folder.

  • main.go: go code to parse HTML template and send it in email
  • template.html : HTML template for emails



    

Name:

{{.Name}}

Email:

{{.Message}}

We are using text/template package to parse HTML files and use it in smtp SendMail function.

package main

import (
  "bytes"
  "fmt"
  "net/smtp"
  "text/template"
)

func main() {

  // Sender data.
  from := "from@gmail.com"
  password := ""

  // Receiver email address.
  to := []string{
    "sender@example.com",
  }

  // smtp server configuration.
  smtpHost := "smtp.gmail.com"
  smtpPort := "587"

  // Authentication.
  auth := smtp.PlainAuth("", from, password, smtpHost)

  t, _ := template.ParseFiles("template.html")

  var body bytes.Buffer

  mimeHeaders := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
  body.Write([]byte(fmt.Sprintf("Subject: This is a test subject \n%s\n\n", mimeHeaders)))

  t.Execute(&body, struct {
    Name    string
    Message string
  }{
    Name:    "Puneet Singh",
    Message: "This is a test message in a HTML template",
  })

  // Sending email.
  err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, body.Bytes())
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("Email Sent!")
}

Once done you need to run below command to send the emails

go run main.go

If you don't want to create your custom HTML emails, Hermes is a package that generates clean, responsive HTML e-mails for sending transactional e-mails.

Now you can send beautiful emails to the customer by your golang application, You can found the complete code used in this blog on our Github Repo

How to build signed apk from Android Studio for Flutter

You can build the Apk/AppBundle using IDE and command line.

  • Building APK/AppBundle through IDE:

    Step-1

    In Android Studio's tab bar, click on Tools and then Flutter and then Open Android module in Android Studio:

    enter image description here

    Step-2

    Open Project it in New Window:

    enter image description here

    Step-3

    Having opened the project, click on Build and then Generate Signed Bundle / APK ...

    enter image description here


  • Building APK/AppBundle through command:

    Step-1:

    Modify your build.gradle(app) file and include your key information there:

    android {
        compileSdkVersion 31
        signingConfigs {
            release {
                storeFile file("")
                storePassword "********"
                keyAlias ""
                keyPassword "********"
            }
        }
        buildTypes {
            release {
                signingConfig signingConfigs.release
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    

    Step-2:

    Build AppBundle:

    flutter build appbundle --target-platform android-arm,android-arm64,android-x64 --obfuscate --split-debug-info=/
    

    Build APK:

    flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi --
    obfuscate --split-debug-info=/
    

https://stackoverflow.com/a/55549073

File Upload in WebView

File Upload in WebView

https://stackoverflow.com/a/59505878