Stream File on Ubuntu
การป้องการไฟล์จากลิ้งตรง ด้วยการ Stream File ไฟล์ใช้เอง มาดูวิธีการ ว่าทำยังไงบ้าง สรุปไว้ด้านล่าง สำหรับกรณีศึกษานะครับ... จะทำการทดสอบกับเว็บไซต์ nunginter.com เนื่องจากระบบจะใช้รวมใน cyberpanel ดังนั้นจะไม่พยามใช้ port ที่ไม่กระทบนะครับ เช่น 8443 ,8080
2024-06-20 12:01:24 - @ratanon
สรุปขั้นตอนการตั้งค่าและการสตรีมไฟล์วิดีโอบน Ubuntu
1.การติดตั้งซอฟต์แวร์ที่จำเป็น:
- ติดตั้ง Nginx เพื่อใช้เป็น reverse proxy
- ติดตั้ง Certbot เพื่อขอใบรับรอง SSL
- ติดตั้ง Flask สำหรับสร้างแอปพลิเคชันสตรีมไฟล์วิดีโอ
2.ตั้งค่า Nginx:
- แก้ไขไฟล์คอนฟิกของ Nginx ให้ใช้พอร์ต 8080 และ 8443 เพื่อหลีกเลี่ยงการชนกับพอร์ตที่ใช้โดย LiteSpeed
- ปิดการใช้งานไฟล์คอนฟิกดีฟอลต์ที่ประกาศฟังพอร์ต 80
3.ขอใบรับรอง SSL จาก Let's Encrypt:
- ใช้ DNS Cloudflare Plugin ของ Certbot เพื่อขอใบรับรอง SSL โดยไม่ต้องเปิดการใช้งานพอร์ต 80 และ 443 โดยตรง
4.ตั้งค่าและทดสอบ Flask app:
- เขียนโค้ดสำหรับแอปพลิเคชัน Flask ที่จะสตรีมไฟล์วิดีโอจาก URL โดยเข้ารหัสชื่อไฟล์เป็น Base64
- เพิ่มการตรวจสอบ HTTP Referer เพื่อให้แน่ใจว่าไฟล์วิดีโอจะเปิดได้เฉพาะเมื่อเข้ามาจากเว็บ nunginter.com
รายละเอียดขั้นตอน การติดตั้งซอฟต์แวร์ที่จำเป็น
# ติดตั้ง Nginx sudo apt-get update sudo apt-get install nginx
# ติดตั้ง Certbot และ DNS Cloudflare Plugin
sudo apt-get install certbot python3-certbot-dns-cloudflare
# ติดตั้ง Flask และ CORS
sudo apt-get install python3-pip pip3 install flask flask-cors requests
ตั้งค่า Nginx
1. สร้างไฟล์คอนฟิก Nginx สำหรับโดเมน `forward.nunginter.com`:
sudo nano /etc/nginx/sites-available/forward
เนื้อหาในไฟล์ `/etc/nginx/sites-available/forward`:
nginx server { listen 8080; server_name forward.nunginter.com; location / { proxy_pass http://127.0.0.1:5000; 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; } } server { listen 8443 ssl; server_name forward.nunginter.com; ssl_certificate /etc/letsencrypt/live/forward.nunginter.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/forward.nunginter.com/privkey.pem; location / { proxy_pass http://127.0.0.1:5000; 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; } }
2. เปิดใช้งานคอนฟิก:
sudo ln -s /etc/nginx/sites-available/forward /etc/nginx/sites-enabled/
3. ปิดการใช้งานคอนฟิกดีฟอลต์:
sudo rm /etc/nginx/sites-enabled/default
4. เปิดพอร์ต 8080 และ 8443 ใน Firewall:
sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 8443 -j ACCEPT sudo netfilter-persistent save sudo netfilter-persistent reload
ขอใบรับรอง SSL จาก Let's Encrypt
1. สร้างไฟล์เก็บ Cloudflare API Token: https://dash.cloudflare.com/profile/api-tokens
sudo nano /root/.cloudflare_credentials
เพิ่มเนื้อหาดังนี้:
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
2. ขอใบรับรอง SSL:
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.cloudflare_credentials -d forward.nunginter.com
ตั้งค่าและทดสอบ Flask app
1. เขียนโค้ดสำหรับแอปพลิเคชัน Flask:
python
from flask import Flask, Response, request, abort from flask_cors import CORS import base64 import requests app = Flask(__name__) CORS(app) ALLOWED_REFERER = "https://nunginter.com" def get_file_from_base64(encoded_filename): encoded_filename = encoded_filename.replace('.mp4', '') decoded_bytes = base64.urlsafe_b64decode(encoded_filename) filename = decoded_bytes.decode('utf-8') return filename @app.route('/') def index(): return "Flask application is running!" @app.route('/<path:encoded_filename>.mp4', methods=['GET']) def stream_file(encoded_filename): referer = request.headers.get('Referer') if not referer or not referer.startswith(ALLOWED_REFERER): return abort(403, description="Forbidden: You don't have permission to access this resource.") try: filename = get_file_from_base64(encoded_filename) url = f'https://ลิ้งตรง/{filename}' headers = {} range_header = request.headers.get('Range', None) if range_header: headers['Range'] = range_header response = requests.get(url, headers=headers, stream=True) def generate(): for chunk in response.iter_content(chunk_size=8192): yield chunk status_code = response.status_code if range_header else 200 response_headers = { 'Content-Type': 'video/mp4', 'Content-Length': response.headers['Content-Length'] } if 'Content-Range' in response.headers: response_headers['Content-Range'] = response.headers['Content-Range'] return Response(generate(), status=status_code, headers=response_headers) except Exception as e: return str(e), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
2. รัน Flask app:
python3 nunginter.py
ตรวจสอบการทำงาน
1. ตรวจสอบว่า Nginx และ Flask ทำงานถูกต้อง:
- เข้าถึง URL: `https://forward.nunginter.com:8443/MzAwLjIwMDYubXA0.mp4`
- ตรวจสอบว่าการเข้าถึงจากโดเมนอื่นถูกบล็อก
- ตรวจสอบว่าการเข้าถึงจากโดเมน `nunginter.com` ทำงานได้ตามที่คาดหวัง
2. ปรับปรุง HTML ของแท็ก `<video>` ในหน้าเว็บให้ถูกต้อง:
<video id="v_player_html5_api" class="vjs-tech" preload="auto" playsinline="playsinline" poster="https://nunginter.com/upload/movie/backdrop/511-backdrop.jpg" data-setup="{}" autoplay controls> <source src="https://forward.nunginter.com:8443/MzAwLjIwMDYubXA0.mp4" type="video/mp4"> Your browser does not support the video tag. </video>
ขั้นตอนการสร้าง Systemd Service สำหรับรัน Flask App
1. สร้างไฟล์ Service สำหรับ Systemd:
- สร้างไฟล์ `nunginter.service` ใน `/etc/systemd/system/`
sudo nano /etc/systemd/system/nunginter.service
2. เพิ่มเนื้อหาดังนี้ลงในไฟล์ `nunginter.service`:
[Unit] Description=Nunginter Flask App After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/home/nunginter.com/python ExecStart=/usr/bin/python3 /home/nunginter.com/python/nunginter.py Restart=always [Install] WantedBy=multi-user.target
- ตรวจสอบให้แน่ใจว่า `User` และ `Group` ตรงกับสิทธิ์ของผู้ใช้ที่เหมาะสม คุณสามารถใช้ `www-data` หรือผู้ใช้ที่คุณต้องการ
3. รีโหลด Systemd daemon:
sudo systemctl daemon-reload
4. เปิดใช้งาน Service ให้เริ่มต้นอัตโนมัติเมื่อระบบเริ่มต้น:
sudo systemctl enable nunginter
5. เริ่มต้น Service:
sudo systemctl start nunginter
6. ตรวจสอบสถานะของ Service:
sudo systemctl status nunginter
เมื่อรันคำสั่ง `sudo systemctl start nunginter` คุณจะได้ผลลัพธ์บางอย่างเช่น:
● nunginter.service - Nunginter Flask App Loaded: loaded (/etc/systemd/system/nunginter.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2024-06-20 07:30:00 UTC; 10s ago Main PID: 12345 (python3) Tasks: 1 (limit: 2212) Memory: 10.0M CPU: 50ms CGroup: /system.slice/nunginter.service └─12345 /usr/bin/python3 /home/nunginter.com/python/nunginter.py
สรุป
1. สร้างไฟล์ `nunginter.service` ใน `/etc/systemd/system/`
2. เพิ่มการตั้งค่าตามที่ระบุในไฟล์
3. รีโหลด Systemd daemon
4. เปิดใช้งานและเริ่มต้น Service
5. ตรวจสอบสถานะของ Service
ด้วยวิธีนี้ `nunginter.py` จะรันเป็นพื้นหลังและรันอัตโนมัติเมื่อระบบเริ่มต้นใหม่ และจะรีสตาร์ทอัตโนมัติหากเกิดข้อผิดพลาด
ลองดูครับหวังว่าคงมีประโยชน์สำหรับคนทีสตรีมมิ่งไว้ใช้งานเอง...
gunicorn สำหรับ prod
เพื่อให้การตั้งค่าเสถียรและมั่นใจว่าแอปพลิเคชันจะรันเป็นพื้นหลังอย่างถูกต้อง เพื่อปรับปรุงการตั้งค่าให้ใช้ Gunicorn เราจะแก้ไขไฟล์ nunginter.service และตั้งค่า Gunicorn ให้ทำงานเป็น WSGI HTTP Server สำหรับ Flask app นี่คือสรุปขั้นตอนที่ทำมาและการตรวจสอบเพิ่มเติม
### การตั้งค่า gunicorn เพื่อรันแอป Flask
1. ติดตั้ง gunicorn:
python3 -m pip install gunicorn
2. แก้ไขไฟล์บริการ Systemd:
สร้างหรือแก้ไขไฟล์ /etc/systemd/system/nunginter.service:
[Unit] Description=Nunginter Flask App After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/home/nunginter.com/python ExecStart=/usr/local/bin/gunicorn --workers 3 --bind 0.0.0.0:5000 nunginter:app Restart=always [Install] WantedBy=multi-user.target
3. รีโหลด Systemd และเริ่มบริการ nunginter:
sudo systemctl daemon-reload sudo systemctl start nunginter sudo systemctl enable nunginter
### การตั้งค่า nginx เพื่อ Proxy ไปยัง gunicorn
4. ตั้งค่า nginx:
ตรวจสอบและแก้ไขไฟล์ /etc/nginx/sites-available/forward:
server { listen 8080; server_name forward.nunginter.com; location / { proxy_pass http://127.0.0.1:5000; 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; } } server { listen 8443 ssl; server_name forward.nunginter.com; ssl_certificate /etc/letsencrypt/live/forward.nunginter.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/forward.nunginter.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://127.0.0.1:5000; 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; } }
5. รีโหลด nginx:
sudo systemctl reload nginx
### การตรวจสอบและทดสอบการทำงาน
6. ตรวจสอบสถานะของ gunicorn:
sudo systemctl status nunginter
7. ตรวจสอบสถานะของ nginx:
sudo systemctl status nginx
8. ทดสอบการเข้าถึงแอปพลิเคชัน:
- ทดสอบการเข้าถึงผ่าน curl:
curl -v https://forward.nunginter.com:8443/
- ตรวจสอบว่าการเข้าถึงผ่านเบราว์เซอร์ทำงานได้ดีที่ URL:
https://forward.nunginter.com:8443/
ส่วน code nunginter.py ที่แก้แล้วสำหรับการใช้งานกับ gunicorn
from flask import Flask, Response, request, abort from flask_cors import CORS import base64 import requests app = Flask(__name__) CORS(app) ALLOWED_REFERER = "https://nunginter.com" def get_file_from_base64(encoded_filename): encoded_filename = encoded_filename.replace('.mp4', '') decoded_bytes = base64.urlsafe_b64decode(encoded_filename) filename = decoded_bytes.decode('utf-8') return filename @app.route('/') def index(): return "nunginter.com application is running!" @app.route('/<path:encoded_filename>.mp4', methods=['GET']) def stream_file(encoded_filename): referer = request.headers.get('Referer') if not referer or not referer.startswith(ALLOWED_REFERER): return abort(403, description="Forbidden: You don't have permission to access this resource.") try: filename = get_file_from_base64(encoded_filename) url = f'MY_S3/{filename}' headers = {} range_header = request.headers.get('Range', None) if range_header: headers['Range'] = range_header response = requests.get(url, headers=headers, stream=True) def generate(): for chunk in response.iter_content(chunk_size=8192): yield chunk status_code = response.status_code if range_header else 200 response_headers = { 'Content-Type': 'video/mp4', 'Content-Length': response.headers['Content-Length'] } if 'Content-Range' in response.headers: response_headers['Content-Range'] = response.headers['Content-Range'] return Response(generate(), status=status_code, headers=response_headers) except Exception as e: return str(e), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
ถ้าทุกอย่างถูกตั้งค่าและตรวจสอบอย่างถูกต้อง จะสามารถเข้าถึงแอปพลิเคชันของคุณผ่าน HTTPS ได้โดยไม่มีปัญหา
และหวังว่าไม่ติดปัญหา 5555