209 lines
4.3 KiB
Markdown
209 lines
4.3 KiB
Markdown
|
A
|
# Unit 08 — System Configuration Files
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
Production-ready nginx, dnsmasq, hostapd configs and systemd service units.
|
||
|
|
|
||
|
|
## Files
|
||
|
|
- `configs/nginx.conf`
|
||
|
|
- `configs/dnsmasq.conf`
|
||
|
|
- `configs/hostapd.conf`
|
||
|
|
- `systemd/esim-provisioning.service`
|
||
|
|
- `systemd/captive-portal.service`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## `configs/nginx.conf`
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
# Captive portal + reverse proxy for eSIM provisioning server
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 80 default_server;
|
||
|
|
server_name _;
|
||
|
|
|
||
|
|
# Redirect any request not matching known paths to the activation portal
|
||
|
|
location = / {
|
||
|
|
return 302 http://192.168.4.1/activate;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Serve the captive portal static files
|
||
|
|
location /activate {
|
||
|
|
alias /opt/esim-provisioning/portal/;
|
||
|
|
index index.html;
|
||
|
|
try_files $uri $uri/ /index.html;
|
||
|
|
}
|
||
|
|
|
||
|
|
location /css/ {
|
||
|
|
alias /opt/esim-provisioning/portal/css/;
|
||
|
|
}
|
||
|
|
|
||
|
|
location /js/ {
|
||
|
|
alias /opt/esim-provisioning/portal/js/;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Proxy API calls to Flask backend
|
||
|
|
location /api/ {
|
||
|
|
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_connect_timeout 10s;
|
||
|
|
proxy_read_timeout 30s;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Catch-all: redirect everything else to activate
|
||
|
|
location / {
|
||
|
|
return 302 http://192.168.4.1/activate;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## `configs/dnsmasq.conf`
|
||
|
|
|
||
|
|
```conf
|
||
|
|
# eSIM Provisioning - DNS/DHCP configuration
|
||
|
|
|
||
|
|
# Only listen on WiFi AP interface
|
||
|
|
interface=wlan0
|
||
|
|
bind-interfaces
|
||
|
|
|
||
|
|
# DHCP range
|
||
|
|
dhcp-range=192.168.4.10,192.168.4.250,24h
|
||
|
|
|
||
|
|
# DNS: return WiFi AP IP for ALL domains (captive portal hijacking)
|
||
|
|
address=/#/192.168.4.1
|
||
|
|
|
||
|
|
# Prevent upstream DNS resolution (keep it local)
|
||
|
|
no-resolv
|
||
|
|
|
||
|
|
# DHCP lease file
|
||
|
|
dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||
|
|
|
||
|
|
# Log queries (useful for debugging)
|
||
|
|
log-queries
|
||
|
|
log-dhcp
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## `configs/hostapd.conf`
|
||
|
|
|
||
|
|
```conf
|
||
|
|
# WiFi AP configuration for eSIM provisioning drop node
|
||
|
|
|
||
|
|
interface=wlan0
|
||
|
|
driver=nl80211
|
||
|
|
|
||
|
|
# Network identity
|
||
|
|
ssid=Emergency-5G
|
||
|
|
utf8_ssid=1
|
||
|
|
|
||
|
|
# Radio settings
|
||
|
|
hw_mode=g
|
||
|
|
channel=6
|
||
|
|
ieee80211n=1
|
||
|
|
wmm_enabled=1
|
||
|
|
|
||
|
|
# Open network (no password) — intentional for emergency access
|
||
|
|
auth_algs=1
|
||
|
|
ignore_broadcast_ssid=0
|
||
|
|
|
||
|
|
# Country code — adjust per deployment region
|
||
|
|
country_code=CA
|
||
|
|
|
||
|
|
# Max clients
|
||
|
|
max_num_sta=50
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## `systemd/esim-provisioning.service`
|
||
|
|
|
||
|
|
```ini
|
||
|
|
[Unit]
|
||
|
|
Description=eSIM Provisioning Server
|
||
|
|
After=network.target
|
||
|
|
Wants=network.target
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=simple
|
||
|
|
User=esim
|
||
|
|
Group=esim
|
||
|
|
WorkingDirectory=/opt/esim-provisioning
|
||
|
|
Environment=CONFIG_PATH=/etc/esim-provisioning/config.yaml
|
||
|
|
ExecStart=/opt/esim-provisioning/venv/bin/python -m server.app
|
||
|
|
Restart=always
|
||
|
|
RestartSec=5
|
||
|
|
StandardOutput=journal
|
||
|
|
StandardError=journal
|
||
|
|
SyslogIdentifier=esim-provisioning
|
||
|
|
|
||
|
|
# Security hardening
|
||
|
|
NoNewPrivileges=true
|
||
|
|
PrivateTmp=true
|
||
|
|
ProtectSystem=strict
|
||
|
|
ReadWritePaths=/opt/esim-provisioning/data
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## `systemd/captive-portal.service`
|
||
|
|
|
||
|
|
```ini
|
||
|
|
[Unit]
|
||
|
|
Description=Captive Portal (nginx + dnsmasq)
|
||
|
|
After=network.target hostapd.service
|
||
|
|
Wants=nginx.service dnsmasq.service
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=oneshot
|
||
|
|
RemainAfterExit=yes
|
||
|
|
ExecStart=/bin/systemctl start nginx dnsmasq
|
||
|
|
ExecStop=/bin/systemctl stop nginx dnsmasq
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Deployment Notes
|
||
|
|
|
||
|
|
Install configs:
|
||
|
|
```bash
|
||
|
|
# nginx
|
||
|
|
sudo cp configs/nginx.conf /etc/nginx/sites-available/esim-provisioning
|
||
|
|
sudo ln -sf /etc/nginx/sites-available/esim-provisioning /etc/nginx/sites-enabled/
|
||
|
|
sudo rm -f /etc/nginx/sites-enabled/default
|
||
|
|
sudo nginx -t && sudo systemctl reload nginx
|
||
|
|
|
||
|
|
# dnsmasq
|
||
|
|
sudo cp configs/dnsmasq.conf /etc/dnsmasq.d/esim-provisioning.conf
|
||
|
|
sudo systemctl restart dnsmasq
|
||
|
|
|
||
|
|
# hostapd
|
||
|
|
sudo cp configs/hostapd.conf /etc/hostapd/hostapd.conf
|
||
|
|
sudo systemctl unmask hostapd
|
||
|
|
sudo systemctl enable --now hostapd
|
||
|
|
|
||
|
|
# systemd services
|
||
|
|
sudo cp systemd/esim-provisioning.service /etc/systemd/system/
|
||
|
|
sudo cp systemd/captive-portal.service /etc/systemd/system/
|
||
|
|
sudo systemctl daemon-reload
|
||
|
|
sudo systemctl enable --now esim-provisioning captive-portal
|
||
|
|
```
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
```bash
|
||
|
|
sudo nginx -t # Config syntax check
|
||
|
|
sudo systemctl status esim-provisioning
|
||
|
|
sudo systemctl status captive-portal
|
||
|
|
nslookup google.com 192.168.4.1 # Should return 192.168.4.1
|
||
|
|
curl http://192.168.4.1/api/status # Should return JSON status
|
||
|
|
```
|