Get Started
MADMIN runs on Ubuntu 24.04 LTS. The automated installer handles everything: system packages, PostgreSQL, Python virtualenv, Nginx reverse proxy, iptables/ipset rules, and the systemd service.
Requirements
- Ubuntu 24.04 LTS (fresh install recommended)
- Root / sudo access
- Internet connectivity (for apt and pip packages)
Installation
- Clone the repository:
git clone https://github.com/EdoardoFiore/madmin.git - Enter the directory:
cd madmin - Run the setup script with your chosen admin username and password:
sudo bash scripts/setup-madmin.sh -u <username> -p '<password>'
Post-install access
| Item | Value |
|---|---|
| URL | https://<server-ip>:7443 |
| Username | as specified during install (-u flag) |
| Password | as specified during install (-p flag) |
| TLS | Self-signed cert — accept browser warning on first visit |
Security checklist (post-install)
- Change the default admin password
- Enable TOTP 2FA for all admin accounts
- Confirm
DEBUG=falsein/opt/madmin/backend/.env - Review
default_rules.jsonfirewall rules - Replace the self-signed TLS cert in the Nginx config if needed
- Set up a remote backup destination in Settings → Backup
Useful commands
systemctl status madmin # check service status systemctl restart madmin # restart after config changes journalctl -u madmin -f # follow live logs
1. Access
The portal is reachable via browser at the server address on port 7443 (HTTPS). The certificate is self-signed: the browser will show a security warning that can be dismissed by accepting the risk.
Login
Enter your username and password on the login screen and click Sign in. Credentials are set during installation.
Two-factor authentication (2FA)
If the account has 2FA enabled (or it is enforced globally), a second field appears after credentials where you enter the 6-digit code generated by your authenticator app (Google Authenticator, Authy, or similar).
2. Dashboard
The dashboard is the main screen and shows a real-time overview of system status.
| Widget | Description |
|---|---|
| CPU | Processor usage percentage |
| RAM | Memory usage with total and free values |
| Disk | Used and available storage |
| Uptime | How long the system has been running |
| Network traffic | Bytes sent and received per interface |
| Module widgets | Each active module can publish its own widgets (e.g. connected VPN clients, active DHCP leases) |
The traffic chart updates automatically. Historical data is retained for the last 24 hours.
3. User Management
Accessible from the sidebar. Split into two parts: your own profile and management of other users (admin-only).
My Profile
Every user can update their own security settings regardless of permissions.
Change password
- Enter current password, new password, and confirm.
- Click Save Password.
Configure 2FA
- Click Configure 2FA to open the wizard.
- Scan the QR code with your authenticator app or enter the secret manually.
- Enter the 6-digit code from the app to verify.
- Save the provided backup codes in a safe place — they allow access if you lose your device.
- To disable 2FA, click Remove 2FA and confirm.
User Management (admins only)
The table shows all users with status, creation date, and assigned permissions.
Create a new user
- Click New User.
- Fill in: Username (3–50 chars, letters/numbers/hyphens/underscores), Email (optional), Password, Active, Superuser, Force 2FA.
- Select the permissions to assign.
- Click Save.
Core permissions
| Permission | Access granted |
|---|---|
| users.view | View user list |
| users.manage | Create, edit, delete users |
| firewall.view | View firewall rules |
| firewall.manage | Add / edit / delete rules |
| network.view | View network interfaces |
| network.manage | Configure network interfaces |
| services.view | View service status |
| services.manage | Start / stop / restart services |
| settings.view / manage | View or modify system settings |
| backup.view / manage | Download, create, restore or schedule backups |
| cron.view / manage | View or manage scheduled tasks |
| audit.view | View audit logs |
| modules.view / manage | View or enable / disable modules |
Each module adds its own permissions (e.g. wireguard.view, dhcp.manage).
4. Firewall
The firewall manages the machine's iptables rules, organised by table and chain.
Tables and Chains
| Table | Available chains | Typical use |
|---|---|---|
| Filter | INPUT, OUTPUT, FORWARD | Block or allow traffic |
| NAT | PREROUTING, POSTROUTING | DNAT (port forwarding), SNAT, Masquerade |
| Mangle | INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING | Advanced packet modification |
| Raw | PREROUTING, OUTPUT | Exclude traffic from connection tracking |
Adding a Rule
- Select table and chain.
- Click Add Rule.
- Fill in the relevant fields (irrelevant ones can be left empty).
Common fields
| Field | Description | Example |
|---|---|---|
| Protocol | tcp, udp, icmp, all | tcp |
| Source | IP or network (CIDR) | 192.168.1.0/24 |
| Destination | IP or network (CIDR) | 10.0.0.1 |
| Port | Single or range | 80 or 8000:9000 |
| Comment | Internal note | Allow HTTP from LAN |
Additional fields — Filter
| Field | Description |
|---|---|
| State | NEW, ESTABLISHED, RELATED, INVALID |
| In / Out Interface | Ingress or egress interface (e.g. eth1) |
| Action | ACCEPT, DROP, REJECT, LOG |
Additional fields — NAT
| Field | Description | Use |
|---|---|---|
| To Destination | IP:Port of destination (DNAT) | Inbound port forwarding |
| To Source | Source IP to use (SNAT) | Force egress with specific IP |
| To Ports | Destination port to remap | Change port during NAT |
| Action | DNAT, SNAT, MASQUERADE, REDIRECT | — |
Rule ordering
Rules are evaluated top to bottom: the first match determines the outcome. Drag rows to reorder — order is saved automatically.
iptables preview
The Preview panel shows the exact iptables command that will be executed for the selected rule.
Import / Export
Chain rules can be exported to JSON and re-imported on another system using the dedicated buttons.
5. Network Interfaces
Shows all physical interfaces with real-time statistics: status, speed, configuration type (DHCP or Static), primary / secondary IPs, IPv6, MAC, MTU, traffic counters and error counts.
WAN interface (eth0)
The WAN interface is read-only — it cannot be configured from the portal.
Configure an interface (non-WAN)
- Click the gear icon on the interface card.
- Choose DHCP (automatic) or Static (enter IP CIDR, gateway, DNS).
- Optionally set a custom MTU.
- Click Save, then Apply Netplan.
/etc/netplan/ but not activated until you click "Apply Netplan". This operation may briefly interrupt connectivity.6. Modules
Modules are optional components that extend MADMIN. They must first be activated from the Modules section, after which they appear in the sidebar menu.
Activate / Deactivate a Module
- Go to Modules in the sidebar.
- Click Activate — the system installs dependencies and initialises the database.
- Click Deactivate to disable it and remove its data.
6.1 WireGuard VPN
Modern, high-performance VPN based on public-key cryptography.
Core concepts
- Instance: a WireGuard server (interface
wg0,wg1, …) - Client: a device that connects to the server
- Full Tunnel: all traffic routes through the VPN
- Split Tunnel: only traffic to specific networks routes through the VPN
Create an Instance
- Click New Instance.
- Fill in: Name, UDP Port (default 51820), Subnet (e.g.
10.10.0.0/24), Tunnel mode (Full / Split). - Click Create.
Manage Clients
| Action | Description |
|---|---|
| Add Client | Generates key pair and assigns IP in the VPN subnet |
| QR Code | Scan with the WireGuard mobile app |
| Download Config | .conf file to import in the desktop client |
| Send config | Sends a download link by email |
| Enable / Disable | Disabled clients cannot connect |
| Delete | Removes the client and its configuration |
Firewall (Firewall tab in the instance)
Based on groups: clients are assigned to groups, and specific rules are applied per group.
- Default policy: ACCEPT (all allowed, rules used to block exceptions) or DROP (all blocked, rules used to open exceptions).
- Groups: listed in the left panel, draggable to change priority.
- Group rules: Action (ACCEPT/DROP), Protocol, Destination CIDR, Port, Description. Evaluated top to bottom.
6.2 OpenVPN
Traditional certificate-based VPN compatible with a wide range of devices.
- Supports both UDP and TCP (useful when UDP is blocked)
- Uses an internal PKI (certificate authority)
- Slightly slower but more compatible with restrictive environments
Create an Instance
- Click New Instance.
- Fill in: Name, Port (default 1194), Protocol (UDP/TCP), Subnet, Public endpoint, Tunnel mode, advanced options (cipher, cert lifetime).
Client management and the firewall are structurally identical to WireGuard: same group logic, same per-instance default policy. Revoked clients cannot be added to groups.
6.3 DHCP Server
Manages automatic IP address assignment to devices on the local network.
Create a Subnet
- Click New Subnet.
- Fill in: Name, Interface, Network CIDR (e.g.
192.168.1.0/24), IP Range (start → end), Gateway, DNS, Domain (optional), Lease time (default 86400s = 24h).
Static Reservations (fixed IPs per MAC)
- Open the Reservations tab inside the subnet.
- Click Add Reservation, enter MAC address and IP to always assign.
Active Leases
The Leases tab shows connected devices with IP, MAC, hostname and expiry.
Apply Configuration
After any change click Apply Configuration — the DHCP service is restarted with the new settings.
6.4 DNS Server
Internal DNS server powered by BIND9, useful for resolving internal names or acting as a resolver for the local network.
| Mode | Description |
|---|---|
| Recursive | Resolves any domain by querying root servers |
| Forwarder only | Forwards queries to configured upstream DNS (e.g. 8.8.8.8) |
| Non-recursive | Only answers configured local zones |
Create a Zone
- Zones → New Zone.
- Choose: Master (authoritative zone, for internal domains) or Forward (delegate queries to specific DNS).
- Enter zone name (e.g.
company.local) and description.
DNS Record Types
| Type | Use |
|---|---|
| A | Name → IPv4 |
| AAAA | Name → IPv6 |
| CNAME | Alias (e.g. www → server.company.local) |
| MX | Mail server for the domain |
| TXT | Text record (SPF, DKIM, …) |
| PTR | Reverse lookup (IP → Name) |
| NS | Authoritative name server |
| SRV | Service location |
DNS Test
The Test tab lets you query the local DNS server by entering a name and selecting the record type.
6.5 IPsec VPN (StrongSwan)
VPN designed for stable site-to-site connections between two sites/routers. High interoperability standard (compatible with Cisco, Fortinet, MikroTik, etc.).
Create a Tunnel
- Click New Tunnel.
- Fill in: Name, Local network (e.g.
192.168.1.0/24), Remote network, Remote gateway, IKE version (IKEv2 recommended), Authentication (PSK or Certificate), Cipher suite.
Status and Management
The tunnel can be started/stopped manually. The SA section shows active security associations and traffic statistics.
Firewall (Firewall section in tunnel detail)
IPsec firewall operates per Child SA (phase 2, local/remote subnet pair). Each Child SA has two independent sections:
- Outbound rules (local → remote)
- Inbound rules (remote → local)
Each has its own default policy (ACCEPT or DROP) independent of the other.
| Field | Options | Notes |
|---|---|---|
| Direction | Outbound / Inbound / Both | Which direction to apply the rule |
| Action | ACCEPT / DROP | Allow or block |
| Protocol | All / TCP / UDP / ICMP | — |
| Port | e.g. 80 or 8000-8100 | TCP/UDP only; range with hyphen |
| Source / Destination | CIDR | Empty = use the tunnel subnet |
| Description | Free text | Internal note |
6.6 Reverse Proxy
Manages nginx as a reverse proxy to expose internal services with automatic SSL/TLS (Let's Encrypt), HTTP authentication, and IP-based access control.
| Term | Description |
|---|---|
| Proxy Host | Proxy rule: one or more source domains → one backend |
| Backend | Internal service the traffic is forwarded to (IP:port) |
| Access List | Reusable policy combining authentication and/or IP rules |
| Certificate | Let's Encrypt TLS certificate associated with a Proxy Host |
Proxy Hosts — Create a Host
- Click New Host.
- Details tab: source domains, scheme (http/https towards backend), backend host/IP, backend port, access list, options (HTTP/2, Block exploits, WebSocket, Cache).
- SSL tab: click Request Let's Encrypt certificate to get TLS automatically. After issuance you can enable Force HTTPS.
- Advanced tab: custom nginx snippet appended at the end of the
location /block. - Click Save.
Host actions
| Action | Description |
|---|---|
| Edit | Opens the edit form |
| Enable / Disable | Activates or removes the vhost from nginx without deleting it |
| Request / Renew cert | Issues or renews the Let's Encrypt certificate |
| Revoke cert | Revokes the certificate and removes it from the host |
| Delete | Removes the host and nginx vhost (cert is revoked if present) |
Access Lists
Reusable policies combining HTTP Basic authentication and IP allow/deny rules. Assignable to multiple Proxy Hosts.
- Click New List.
- Details tab: Name, Satisfy Any (authentication or IP rule is sufficient — nginx
satisfy any), Pass auth to backend. - Authorisations tab: username/password pairs for HTTP Basic Auth.
- Rules tab: IP rules (allow/deny + CIDR + order). If IP rules exist, nginx automatically appends
deny all.
SSL/TLS Certificates
The Certificates tab lists all issued certs with domains, provider, issue/expiry dates and status (Valid / Expiring / Expired). Available actions: Renew and Revoke.
/etc/letsencrypt/renewal-hooks/deploy/. Manual renewal is not necessary as long as the domain is reachable from the internet on port 80.How it works internally
- nginx is configured with files in
/etc/nginx/madmin-revproxy/. - Each Proxy Host generates
madmin-proxy-{id}.confinsites-available/with a symlink insites-enabled/. - A catch-all vhost (
madmin-acme.conf) serves ACME HTTP-01 challenges on port 80. - After each change nginx is reloaded automatically (
systemctl reload nginx).
7. Crontab (Scheduled Tasks)
Schedule automatic execution of commands at regular intervals.
Add a Task
- Click New Task.
- Define the schedule via Preset (predefined list) or Manual (5 cron fields: Minute Hour Day Month Weekday).
- Enter the Command to run (absolute path recommended).
- Enable or disable the task with the toggle.
- Click Save.
Cron expression examples
0 2 * * * → every day at 02:00 */15 * * * * → every 15 minutes 0 0 1 * * → first day of every month at midnight
8. Logs & Audit
Audit Log
Records every operation performed through the portal (who did what and when).
| Column | Description |
|---|---|
| Timestamp | Date and time of the operation |
| User | Account that performed the action |
| Operation | HTTP method + API path |
| Response code | Green = success, red = error |
| Duration | In milliseconds |
| Client IP | Source address |
Available filters: Category (Writes / All / Reads), User, keyword search, Date range. Click a row to view the request payload. Export CSV downloads filtered logs as a spreadsheet.
System Log
Shows MADMIN service logs in real time (equivalent to journalctl). Options: line count, text filter, Hide AUDIT.
- Red: critical errors
- Orange: warnings
- Cyan: audit log entries
- Dark grey: HTTP access log entries
9. Settings
Customisation
- Company name: text in the menu and header (default: MADMIN)
- Primary colour: colour picker, propagated via CSS variable
- Theme: light or dark
Backup
- Export backup: archive with system configuration
- Import backup: restore from a previous backup file
- Scheduled backups: daily, weekly, or monthly to a local or remote destination (S3, FTP)
Security
- Enforce 2FA globally: all users must configure 2FA
- Token lifetime: session validity in minutes (default 720 = 12h)
Audit
- Log retention: days to keep audit logs (older entries are automatically pruned)
10. Common Configurations
Practical examples using the portal firewall.
10.1 DNAT — Port Forwarding (inbound traffic)
Scenario: connections to the public IP on port 8080 → internal server 192.168.1.10 port 80.
Where: Table NAT → Chain PREROUTING
| Field | Value |
|---|---|
| Protocol | tcp |
| Port | 8080 |
| Action | DNAT |
| To Destination | 192.168.1.10:80 |
192.168.1.10:80.10.2 SNAT — Change the outbound source IP
Scenario A — specific IP for an internal machine: traffic from 192.168.1.50 exits with secondary IP 1.2.3.4.
Where: Table NAT → Chain POSTROUTING
| Field | Value |
|---|---|
| Source | 192.168.1.50 |
| Out Interface | eth0 |
| Action | SNAT |
| To Source | 1.2.3.4 |
Scenario B — specific IP for a VPN: traffic from interface wg0 exits with secondary IP 1.2.3.4.
| Field | Value |
|---|---|
| In Interface | wg0 |
| Out Interface | eth0 |
| Action | SNAT |
| To Source | 1.2.3.4 |
10.3 Masquerade — Dynamic NAT for LAN
Scenario: devices on 192.168.1.0/24 exit to the internet using the server's public IP (dynamic IP).
Where: Table NAT → Chain POSTROUTING
| Field | Value |
|---|---|
| Source | 192.168.1.0/24 |
| Out Interface | eth0 |
| Action | MASQUERADE |
10.4 Block an IP or Network
Where: Table Filter → Chain INPUT
| Field | Value |
|---|---|
| Source | 1.2.3.4 |
| Action | DROP |
10.5 Allow only specific inbound ports
Scenario: allow only SSH (22) and HTTPS (443), drop everything else.
Where: Table Filter → Chain INPUT
| Rule | State / Protocol / Port | Action |
|---|---|---|
| 1 | State: ESTABLISHED,RELATED | ACCEPT |
| 2 | TCP port 22 | ACCEPT |
| 3 | TCP port 443 | ACCEPT |
| 4 | (no filter) | DROP |