Separate JSON API backend (vm_api.py) + React+TanStack frontend scaffold
- vm_api.py: pure FastAPI JSON API on :8098 with CORS - vm-api.service: systemd unit for API (replaces inline HTML vm_web.py for frontend) - vm_web.py: kept intact as fallback; Apache now proxies /api/ -> :8098 - frontend/: Vite + React + TanStack Query scaffold - Apache vhost updated: DocumentRoot -> frontend/dist, /api/ proxy, SPA fallback - All original HTML pages still functional via :8099 during transition
This commit is contained in:
@ -1,54 +1,66 @@
|
||||
<VirtualHost 51.68.212.39:80 [2001:41d0:801:2000::2245]:80>
|
||||
ServerName vm.txt3.net
|
||||
ErrorLog /var/log/virtualmin/vm.txt3.net_error_log
|
||||
CustomLog /var/log/virtualmin/vm.txt3.net_access_log combined
|
||||
ServerName vm.txt3.net
|
||||
ErrorLog /var/log/virtualmin/vm.txt3.net_error_log
|
||||
CustomLog /var/log/virtualmin/vm.txt3.net_access_log combined
|
||||
|
||||
# Let certbot answer HTTP-01 challenges from the webroot
|
||||
Alias /.well-known/acme-challenge/ /home/txt3/domains/vm.txt3.net/public_html/.well-known/acme-challenge/
|
||||
<Directory /home/txt3/domains/vm.txt3.net/public_html/.well-known/acme-challenge>
|
||||
Require all granted
|
||||
Options -Indexes
|
||||
</Directory>
|
||||
ProxyPass /.well-known !
|
||||
Alias /.well-known/acme-challenge/ /home/txt3/domains/vm.txt3.net/public_html/.well-known/acme-challenge/
|
||||
<Directory /home/txt3/domains/vm.txt3.net/public_html/.well-known/acme-challenge>
|
||||
Require all granted
|
||||
Options -Indexes
|
||||
</Directory>
|
||||
ProxyPass /.well-known !
|
||||
|
||||
# Everything else goes to HTTPS
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^/(?!\.well-known)(.*)$ https://vm.txt3.net/$1 [R=301,L]
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^/(?!\.well-known)(.*)$ https://vm.txt3.net/$1 [R=301,L]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost 51.68.212.39:443 [2001:41d0:801:2000::2245]:443>
|
||||
ServerName vm.txt3.net
|
||||
ErrorLog /var/log/virtualmin/vm.txt3.net_error_log
|
||||
CustomLog /var/log/virtualmin/vm.txt3.net_access_log combined
|
||||
ServerName vm.txt3.net
|
||||
ErrorLog /var/log/virtualmin/vm.txt3.net_error_log
|
||||
CustomLog /var/log/virtualmin/vm.txt3.net_access_log combined
|
||||
|
||||
SSLEngine on
|
||||
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
|
||||
# Replaced by certbot with the vm.txt3.net cert once issued.
|
||||
SSLCertificateFile /etc/letsencrypt/live/vm.txt3.net/fullchain.pem
|
||||
SSLCertificateKeyFile /etc/letsencrypt/live/vm.txt3.net/privkey.pem
|
||||
SSLEngine on
|
||||
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
|
||||
SSLCertificateFile /etc/letsencrypt/live/vm.txt3.net/fullchain.pem
|
||||
SSLCertificateKeyFile /etc/letsencrypt/live/vm.txt3.net/privkey.pem
|
||||
|
||||
# --- security headers -------------------------------------------------
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
Header always set X-Frame-Options "DENY"
|
||||
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header always set Strict-Transport-Security "max-age=15768000"
|
||||
# The app uses only inline <style>, no external or inline JS.
|
||||
Header always set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; media-src 'self'; img-src 'self' data:; script-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'"
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
Header always set X-Frame-Options "DENY"
|
||||
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header always set Strict-Transport-Security "max-age=15768000"
|
||||
Header always set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; media-src 'self'; connect-src 'self' http://127.0.0.1:8098; script-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'none'"
|
||||
|
||||
# --- reverse proxy to the voicemail portal ----------------------------
|
||||
ProxyPreserveHost On
|
||||
ProxyRequests Off
|
||||
# Recordings can be a few MB; give uploads/streams room.
|
||||
ProxyTimeout 120
|
||||
# --- API -> JSON backend ----------------------------------------
|
||||
ProxyPreserveHost On
|
||||
ProxyRequests Off
|
||||
ProxyTimeout 120
|
||||
|
||||
ProxyPass /.well-known !
|
||||
ProxyPass / http://127.0.0.1:8099/ retry=0
|
||||
ProxyPassReverse / http://127.0.0.1:8099/
|
||||
ProxyPass /.well-known !
|
||||
ProxyPass /api/ http://127.0.0.1:8098/api/ retry=0
|
||||
ProxyPassReverse /api/ http://127.0.0.1:8098/api/
|
||||
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
# --- audio files -> old portal ----------------------------------
|
||||
ProxyPass /audio/ http://127.0.0.1:8099/audio/ retry=0
|
||||
ProxyPassReverse /audio/ http://127.0.0.1:8099/audio/
|
||||
|
||||
<Location />
|
||||
Require all granted
|
||||
</Location>
|
||||
# --- React frontend (static build) ------------------------------
|
||||
DocumentRoot /home/jp/Work/voicemail-ui/dist
|
||||
<Directory /home/jp/Work/voicemail-ui/dist>
|
||||
Require all granted
|
||||
Options -Indexes
|
||||
</Directory>
|
||||
|
||||
# SPA fallback: serve index.html for any non-file, non-api, non-audio path
|
||||
RewriteEngine on
|
||||
RewriteCond %{REQUEST_URI} !^/api/
|
||||
RewriteCond %{REQUEST_URI} !^/audio/
|
||||
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ /index.html [L]
|
||||
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
|
||||
<Location />
|
||||
Require all granted
|
||||
</Location>
|
||||
</VirtualHost>
|
||||
|
||||
Reference in New Issue
Block a user