The branded "accept the terms and connect" page every guest expects — and every hotel owner asks us for. This is the MikroTik hotspot done properly: a login page you can put a logo on, voucher codes at reception, optional RADIUS, a walled garden so the login itself always loads, per-guest bandwidth, and the HTTPS-redirect reality nobody warns you about.
A captive portal is a small, well-worn trick: the router runs a tiny web server, and until a device authenticates, every HTTP request it makes is redirected to the login page. Accept the terms (or enter a voucher), the router flips that device's MAC to "authorised," and traffic flows normally. Phones recognise the pattern and pop the page automatically — that's the "Sign in to Wi-Fi" sheet every guest has seen.
On MikroTik this is the hotspot feature, and it's genuinely good — a five-minute wizard gets you a working portal, and the login page is just editable HTML you can brand. This post takes it from that wizard to something you'd actually hand a hotel: a terms-acceptance page, voucher codes printed at reception via User Manager, an optional RADIUS backend, the walled garden that keeps the portal itself reachable, and per-guest speed limits. It's the guest-facing front door to the segmented network from the hotel lab.
01
The setup command wires the whole thing — an IP pool, DHCP, a NAT rule, the portal server, and a default profile — onto one interface. Run it on the guest interface, never the WAN.
# Point it at the guest interface (a VLAN interface or a guest bridge). # The wizard asks a handful of questions — accept the sensible defaults. [admin@GW] > /ip hotspot setup hotspot interface: vlan20-guest local address of network: 10.10.20.1/24 (auto) masquerade network: yes address pool: 10.10.20.10-10.10.20.254 select certificate: none ip address of smtp server: 0.0.0.0 dns servers: 10.10.20.1 dns name: wifi.hotel.local name of local user: (skip — we use vouchers) # What it created, in one place: [admin@GW] > /ip hotspot print 0 name="hotspot1" interface=vlan20-guest address-pool=hs-pool-guest profile=hsprof1 idle-timeout=5m keepalive-timeout=none
.local-ish
The dns name (here wifi.hotel.local) is the hostname the portal answers on — guests are redirected to http://wifi.hotel.local/login. Pick something that clearly isn't a real public domain, and never use your actual website's name (the portal would shadow it for every connected guest). It also must resolve only inside the hotspot — the wizard's built-in DNS handles that. If you later add HTTPS to the portal, this name must match the certificate (see the HTTPS gotcha in section 06).
02
The simplest hotel portal isn't a username box — it's a logo, a "I accept the terms" checkbox, and a Connect button. That's a two-line change to the login profile plus a branded HTML file.
# "trial" login lets a guest on for a set time with no credentials — # perfect for accept-and-connect. Give everyone the same shared voucher-free access. [admin@GW] > /ip hotspot user profile set [find name=default] \ shared-users=1 rate-limit=10M/40M session-timeout=1d idle-timeout=15m [admin@GW] > /ip hotspot profile set [find name=hsprof1] \ login-by=cookie,http-chap trial-uptime-limit=1d trial-uptime-reset=1d # cookie login remembers a returning guest's device for the day so they # don't re-accept on every reconnect (the MAC-cookie in section 06).
The portal's HTML lives on the router's flash, in the hotspot/ directory — login.html, alogin.html (the "you're connected" page), logout.html, and a few includes. Pull them off with WinBox's Files browser or SFTP, edit them, and drop them back. For an accept-and-connect page you keep MikroTik's login form but replace the username/password inputs with a single checkbox and a hidden trial submit:
<img src="logo.png" alt="Hotel">
<h1>Welcome — free guest Wi-Fi</h1>
<form name="login" action="$(link-login-only)" method="post">
<input type="hidden" name="dst" value="$(link-orig)">
<input type="hidden" name="popup" value="true">
<label><input type="checkbox" required>
I accept the <a href="/terms.html">terms of use</a></label>
<!-- "trial" hands out the free timed session; no username needed -->
<input type="submit" name="" value="Connect">
</form>
<!-- MikroTik replaces $(...) macros server-side before serving the page -->
The guest isn't online yet when they see this page, so every asset it references must be on the router: the logo, CSS, fonts, any image. Link a Google Font or a CDN logo and it renders broken, because the guest can't reach the internet until after they submit. Put logo.png and a small style.css in the same hotspot/ folder and reference them relatively. This is the single most common reason a "custom portal" looks broken on the guest's phone.
03
When "free for everyone" isn't the model — paid Wi-Fi, per-room codes, a code printed on the checkout receipt — you need vouchers. User Manager is MikroTik's built-in RADIUS server that generates and tracks them.
# RouterOS 7 ships User Manager v5 as a package — enable it once. [admin@GW] > /user-manager set enabled=yes # Register the router itself as a RADIUS client of its own User Manager [admin@GW] > /user-manager router add name=local address=127.0.0.1 shared-secret=hotspot-secret # Tell the hotspot to authenticate against RADIUS instead of local users [admin@GW] > /ip hotspot profile set [find name=hsprof1] use-radius=yes [admin@GW] > /radius add service=hotspot address=127.0.0.1 secret=hotspot-secret # A profile that shapes every voucher user, then a batch of 50 codes [admin@GW] > /user-manager profile add name=guest-1day validity=1d [admin@GW] > /user-manager user create-and-activate-profile=guest-1day \ count=50 name-length=6 shared-users=1 # Print the batch to hand to reception: [admin@GW] > /user-manager user print where profile=guest-1day # NAME PASSWORD PROFILE 0 a7f3k9 a7f3k9 guest-1day 1 m2x8qp m2x8qp guest-1day …
A common panic: "I made 50 one-day codes last month, are they all expired?" No — with User Manager v5, a voucher's validity countdown begins the moment it's first used, not when it's generated. So a stack of unused codes at reception stays good indefinitely; only handed-out ones burn down. Confirm the intended behaviour with a test code before a busy weekend — the difference between "validity" and "session-timeout" trips up everyone the first time, and getting it wrong means either codes that die on the shelf or codes that never expire.
04
Some traffic must pass before login: the portal's own assets, a payment provider if you sell access, captive-portal detection URLs so phones auto-pop the page. That allow-list is the walled garden.
# Payment gateway (if guests pay by card for access) [admin@GW] > /ip hotspot walled-garden add dst-host=*.stripe.com action=allow # Captive-portal detection endpoints — so iOS/Android reliably auto-open # the login sheet instead of silently deciding "no internet" [admin@GW] > /ip hotspot walled-garden add dst-host=captive.apple.com action=allow [admin@GW] > /ip hotspot walled-garden add dst-host=connectivitycheck.gstatic.com action=allow [admin@GW] > /ip hotspot walled-garden add dst-host=www.msftconnecttest.com action=allow # For raw IPs / non-HTTP, use the IP walled garden instead [admin@GW] > /ip hotspot walled-garden ip add dst-address=1.1.1.1 action=accept
Every walled-garden entry is free, unauthenticated internet for anyone in Wi-Fi range — so keep it to detection URLs and (if used) the payment host. We've audited "free Wi-Fi" hotspots whose walled garden had grown to include social media and streaming "so guests could preview" — which is just open Wi-Fi with extra steps, and on a metered or capped line, a bill. The garden is a short list; if it's long, something's wrong with the model.
05
The hotspot has its own rate-limit that composes with — and should defer to — the PCQ fairness from the QoS post. Set a per-session cap here; let PCQ share the pool.
# rate-limit on the user profile: rx/tx from the GUEST's perspective. # 10M down / 5M up per device is plenty for a hotel guest. [admin@GW] > /ip hotspot user profile set [find name=default] rate-limit=5M/10M # Advanced rate-limit syntax also supports burst — generous for a few # seconds (snappy page loads) then settles to the sustained cap: # rate-limit=5M/10M 8M/16M 6M/12M 8 8 8 (rx/tx burst threshold time) # Then let PCQ (from the QoS post) share the total guest pool fairly on # top of the per-device cap — the two layers stack: [admin@GW] > /queue simple add name=guest-pool target=10.10.20.0/24 \ max-limit=300M/300M queue=pcq-up/pcq-down
The same trap as the firewall post: if a FastTrack rule matches guest traffic, the hotspot's shaping (and your PCQ queues) never see the packets, and every "limit" silently does nothing. On a box running a guest hotspot, scope FastTrack to exclude the guest subnet, or don't FastTrack at all. Symptom: you set 10M per guest, one guest pulls 400M, and the queue counters read zero. The packets are being fast-pathed around the shaper.
06
Captive portals were designed for a plaintext-HTTP web. The modern all-HTTPS web breaks the classic "redirect any page" trick — here's what actually happens on a guest's phone, and how to make it smooth.
A hotspot works by intercepting an HTTP request and answering with a redirect. But browsers now default to HTTPS, and the router cannot transparently intercept an HTTPS request — doing so would be a certificate error, which is exactly what HTTPS exists to prevent. So if a guest's first action is opening https://…, they get a connection failure, not your portal.
What saves you is captive-portal detection: every modern phone, on joining Wi-Fi, quietly fetches a known plaintext URL (Apple's captive.apple.com, Android's connectivitycheck.gstatic.com). If it gets your redirect instead of the expected response, it pops the login sheet automatically. So the fix isn't fighting HTTPS — it's making sure those detection URLs are handled and not accidentally allowed through the walled garden (allow them to the portal, don't let them bypass it).
| Symptom in the field | Cause & fix |
|---|---|
| "No internet" but no login page | Detection URL blocked or mis-handled — ensure the walled garden allows the detection hosts to the portal, not around it. |
| Login page loads broken / no logo | Portal assets referenced from a CDN — put logo/CSS on the router (section 02). |
| Guest re-accepts on every reconnect | Enable login-by=cookie so the device MAC is remembered for the session (section 02). |
| Portal throws a cert warning | You enabled HTTPS login without a cert whose CN matches the dns name. Either use plain HTTP for the portal (fine on an isolated guest VLAN) or install a matching cert. |
| Some devices never see the portal | They opened an HTTPS page first and cached it. Toggle Wi-Fi off/on, or open http://neverssl.com — the reception-desk trick. |
For most small properties: an accept-and-connect portal on plain HTTP (the guest VLAN is already isolated, so there's no credential to steal), cookie login so returning guests skip the page, a two-line walled garden, and a per-guest cap under PCQ. Vouchers only where the owner wants paid or per-room access. We keep the portal's HTML in the config backup so a reflash restores the branding too — the logo on that page is often the only thing the owner personally checks after we hand over.
07
Cisco's equivalent lives on the wireless controller, not the router — worth knowing if a site is mixed.
| MikroTik / RouterOS | Cisco |
|---|---|
| /ip hotspot (built into the router) | WLC guest anchor + web-auth policy (on the controller) |
| Editable login.html on flash | Custom web-auth bundle uploaded to the WLC |
| User Manager vouchers | ISE guest sponsor portal / local web-auth accounts |
| Walled garden | Pre-auth ACL on the guest WLAN |
| use-radius=yes → User Manager | RADIUS to ISE / a NAC |
| rate-limit on the user profile | QoS profile / rate limit per WLAN |
Takeaways
/ip hotspot setup builds the whole stack on one guest interface.I build captive portals with your branding, whatever terms or voucher flow you need, kept fully isolated from your real network, and tuned to stay fair even when the property is fully booked — tested on an actual phone, not just a laptop on the bench.
Book a Discovery Call →