If you like my work and appreciate my commitment, you can buy me a coffee.
If you want to customize this template to your own needs, please contact me! ( mix@proask.pl ) I offer professional help in customizing solutions that perfectly match your requirements. Write what you need, and together we will create something exceptional! 🚀
A Captive Portal allows you to force authentication or redirect to a clickable page to access the network. This is commonly used in hotspot networks, but is also widely used in corporate networks or small local area networks (e.g. shopping malls, restaurants, hotels, airports, etc.) as an additional layer of security for wireless or internet access.
OPNsense’s unique template manager makes setting up your own login page an easy task. At the same time it offers additional functionalities, such as:
- URL redirection
- Option for your own Pop-up
- Custom Splash page
To read more about the captive portal, I suggest you have a look here: OPNsense Captive Portal
- Current and future versions of the template (v2.2.0 and above) are free for non-commercial use only.
- A commercial version will be released soon, including additional features and available for use in commercial projects.
- Features available in the free version remain compliant with the non-commercial use policy, and any premium features present in the commercial version will not be included in the GPL/free version.
The captive portal templates that I have seen so far most often lack multilingual support. I've always wondered why it should only be in English or only in one language at all? Well, let's look below. This template supports multilingualism, checks your preferred browser language, saves a cookie with information about which language was read or which language you chose using the selector. Uses language translations saved in the xx.json file. So, according to the layout, you can prepare your own translation, which you later have to declare in the settings.json file in the config directory.
The first (and probably most important) "default_lang" key specifies what language will be loaded by default when the Captive Portal client's web browser's preferred language is different from the languages supported by the platform.
"default_lang": "en"
In the current release, the settings key defines the default language that will be loaded in case the client browser language is not available in our available languages configuration:
"langs": {
"en":"English",
"pl":"Polski",
"sk": "Slovenčina",
"fr": "Français",
"de": "Deutsch",
"nl": "Nederlands",
"no": "Norsk",
"sv": "Svenska",
"fi": "Suomi",
"es": "Español",
"ja": "日本語",
"zh": "中文",
"pt": "Português",
"it": "Italiano",
"da": "Dansk",
"cs": "Čeština",
"lt": "Lietuvių",
"lv": "Latviešu",
"et": "Eesti",
"el": "Ελληνικά",
"bg": "Български",
"ro": "Română",
"hr": "Hrvatski",
"ga": "Gaeilge",
"mt": "Malti",
"sl": "Slovenščina",
"hu": "Magyar",
"is": "Íslenska",
"sr": "Srpski",
"bs": "Bosanski",
"me": "Crnogorski",
"mk": "Македонски",
"sq": "Shqip",
"ka": "ქართული",
"hy": "Հայերեն",
"tr": "Türkçe",
"uk": "Українська",
"af": "Afrikaans",
"am": "አማርኛ",
"ar": "العربية",
"az": "Azərbaycanca",
"bn": "বাংলা",
"cy": "Cymraeg",
"eu": "Euskara",
"fa": "فارسی",
"fil": "Filipino",
"gl": "Galego",
"gu": "ગુજરાતી",
"he": "עברית",
"hi": "हिन्दी",
"id": "Bahasa Indonesia",
"mn": "Монгол",
"ms": "Bahasa Melayu",
"nb": "Norsk bokmål",
"ne": "नेपाली",
"si": "සිංහල",
"sw": "Kiswahili",
"th": "ไทย",
"uz": "Oʻzbek",
"ur": "اُردُو",
"vi": "Tiếng Việt",
"zu": "Zulu",
"ky": "Кыргызча"
};
The langs_iso parameter, which was previously included in the configuration, has been removed from the manual settings. In the new template version, ISO values for languages are automatically generated based on the keys defined in the "langs" section.
Based on the keys of the langs variable object, the template will automatically determine whether it should display the LTR or RTL content.
If only one translation language is defined in the "langs" group, then the language switcher will not be included in the layout. The language translation will be based on the language defined in the "default_lang" key.
The base64 logo is set in the settings.json file. Due to the universal application, the frame of the image of the logo must keep the proportions of a square.
A mechanism that allows a specified number of failed login attempts. After exceeding the allowed number of attempts, the ability to log in will be blocked for a specified period of time.
Of course, this is not a perfect protection against an attempt to force credentials, but the Captive Portal in OPNsense does not yet have a similar protection.
"login": {
"control": false,
"attempts": 3,
"delay": 10
},
control
- false: disabled, true: enabledattempts
- Allowed number of login attemptsdelay
- Time in minutes that must elapse before the next login
Enables or disables the required consent to the provisions contained in the ISP provider's Regulations.
Redirection url address. If the value is not set or the set value is not a valid url address, the redirection functionality to the specified address will not be implemented.
"layout": {
"enable_rules": true,
"redirect_url": ""
},
The appearance of the language selector can be changed by setting values in the layout section.
"layout": {
"lang_layout": "select",
"lang_flags_dir": "4x3",
},
Available modes lang_layout
:
flags-select
– a drop-down selector with language names and flagsflags-only-select
– a drop-down selector with flags only (no text)flags-list
– a list of flags displayed side by side (no text)select
– a classic drop-down selector with language names (no flags)
Flag directory lang_flags_dir
:
4x3
– a 4:3 flag aspect ratio (standard rectangular)1x1
– a square flag aspect ratio
Accessibility options:
"layout": {
"a11y": true|false,
"a11y_contrast": true|false,
"a11y_keyboard": true|false,
"a11y_highlight": true|false,
"a11y_mono": true|false,
"a11y_helper": true|false,
"a11y_helper_breakpoint": 1200,
"a11y_factor": 0.5,
"a11y_treshhold": 0.5,
},
-
a11y
– global accessibility toggle - when false, other options are ignored -
a11y_contrast
– automatically adjusts the color contrast of modals and UI elements to make them easier to read, this is based on thea11y_factor
anda11y_treshhold
parameters -
a11y_keyboard
– enables keyboard shortcut support:- ⇧ Shift (left) + ⌥ Alt (left) + U - focus on the Username field
- ⇧ Shift (left) + ⌥ Alt (left) + P - focus on the Password field
- ⇧ Shift (left) + ⌥ Alt (left) + A - check/uncheck the "I accept the terms and conditions" checkbox
- ⇧ Shift (left) + ⌥ Alt (left) + R - opens a modal window with the terms and conditions
- ⇧ Shift (left) + ⌥ Alt (left) + I - click the active login button
- ⇧ Shift (left) + ⌥ Alt (left) + O - log out
- ⇧ Shift (left) + ⌥ Alt (left) + L - click the language switcher trigger
Language shortcuts (⇧ Shift + two letters)
Hold ⇧ Shift and press two letters of the language code (ISO 639-1) at once or one after the otherExamples:
- ⇧ Shift + P + L → switches to Polish (pl)
- ⇧ Shift + E + N → switches to English (en)
- ⇧ Shift + D + E → switches to Deutsch (de)
- ⇧ Shift + F + R → switches to Français (fr)
- ⇧ Shift + E + S → switches to Español (es)
- ⇧ Shift + I + T → switches to Italiano (it)
-
a11y_highlight
– highlights the currently focused element (e.g., input, button) to facilitate keyboard navigation -
a11y_mono
– monochrome mode reduces the colors in the interface to visually simplify the UI (optional) -
a11y_helper
– interactive Accessibility Tour Guide:- Provides a step-by-step, WCAG-compliant tour of the portal
- Highlights and explains all key elements, including username/password fields, login/logout buttons, the "accept rules" checkbox, and language selector
- Fully keyboard-navigable: use arrow keys to move between steps, Enter/Space to confirm, Esc to exit
- Dynamically adapts to the selected portal language
- Adds visual focus indicators to help users see which element is currently highlighted
-
a11y_helper_breakpoint
- specifies the minimum viewport width (in pixels) at which the Accessibility Tour Guide trigger is displayed. On smaller screens (e.g., smartphones), the trigger is automatically hidden to avoid UI clutter -
a11y_factor
– contrast adjustment factor fora11y_contrast
- higher values = greater contrast increase -
a11y_treshhold
– contrast threshold – specifies the minimum contrast required between the background and text colors. If the current contrast is below this value, it is automatically adjusted.
"css_params": {
"bg_section": "#252828", ← 1 → Background color of the entire section "bg_image": "", ← 2 → Illustration as background (used regardless of the color set in bg_section) "bg_repeat": "no-repeat", ← 3 → Set the repeatability of the background illustration (if set in bg_image) "bg_position": "center center", ← 4 → Set the position of the background illustration (if set in bg_image) "bg_size": "cover", ← 5 → Coverage of the background illustration surface (if set in bg_image) "bg_attachment": "", ← 6 → Sets the scrolling of the background image (if set in bg_image) "bg_left_side": "url('/images/bg_left_side.png')", ← 7 → Illustration as background of the left side of the login portal "bg_left_side_repeat": "no-repeat", ← 8 → Set the repeatability of the background illustration of the left side of the login portal "bg_left_side_position": "top left", ← 9 → Position of the left side background image of the login portal "bg_left_side_size": "cover", ← 10 → Coverage of the left side of the login portal background illustration surface "bg_left_side_attachment": "", ← 11 → Setting the scrolling background image of the left side of the login portal "bg_left_side_blend": "linear-gradient(180deg, #005f6b4d 0%, #005f6bbf 83.85%)", ← 12 → Setting the background blend of the left side of the login portal - in this case it allows you to cover the background illustration of the left side of the login portal with a linear gradient "bg_right_side": "rgba(249, 253, 255, 1)", ← 13 → Illustration as background of the right side of the login portal "bg_right_side_repeat": "no-repeat", ← 14 → Set the repeatability of the background illustration of the right side of the login portal "bg_right_side_position": "top left", ← 15 → Position of the right side background image of the login portal "bg_right_side_size": "cover", ← 16 → Coverage of the right side of the login portal background illustration surface "bg_right_side_attachment": "", ← 17 → Setting the scrolling background image of the right side of the login portal "bg_right_side_blend": "", ← 18 → Setting the background blend of the right side of the login portal - in this case it allows you to cover the background illustration of the left side of the login portal with a linear gradient "left_side_shadow": "0 0 40px 0 rgba(0, 0, 0, .35)", ← 19 → Shadow under left side of login portal "right_side_shadow": "0 0 40px 0 rgba(0, 0, 0, .35)", ← 20 → Shadow under right side of login portal "bg_alternate": "#818a91", ← 21 → Alternate background color - used in buttons as the background color and text fields as the border color "color_primary": "#7a7a7a", ← 22 → Main text color "color_secondary": "#ffffff", ← 23 → Text secondary color "color_alternate": "#373a3c", ← 24 → Text alternate color "link": "#348893", ← 25 → Link color "link_hover": "#f12184", ← 26 → Link hover color "input_field_color": "#e8e8e8", ← 27 → Input field text color "input_field_bg": "#ffffff", ← 28 → Input field background color "input_field_border": "rgba(145, 156, 167, .27)", ← 29 → Input field border color "input_field_placeholder_color": "#4ca1af", ← 30 → Input field placeholder color "button_bg": "#00b5cb", ← 31 → Button background color "button_hover_bg": "#f12184", ← 32 → Button hover background color "button_color": "#ffffff", ← 33 → Button text color "button_hover_color": "#ffffff", ← 34 → Button hover text color "lang_switcher": "#00b5cb", ← 35 → Language selector switch "lang_switcher_trigger": "#009db1", ← 36 → Language selector switch trigger "lang_switcher_link": "#ffffff", ← 37 → Language selector switch link color "lang_switcher_link_hover": "#ffffff", ← 38 → Language selector switch link hover color "lang_switcher_hover": "#f12184", ← 39 → Language selector switch link background hover color "lang_switcher_dropdown": "#216f7a", ← 40 → Language selector switch dropdown background color "lang_switcher_dropdown_hover": "#f12184", ← 41 → Language selector switch dropdown background hover color "fadein": "0.5s", ← 42 → Duration fading to opaque the layout once it's fully loaded "block_padding": "50px", ← 43 → Padding used on left and right column "block_radius": "15px" ← 44 → Left and right column content wrapper border radius "helper_bg_color": "#00b5cb" ← 45 → Background color of the TourGuide trigger button "helper_color": "#ffffff" ← 46 → Text color of the TourGuide trigger button "helper_size": "78px" ← 47 → Size (width and height) of the TourGuide trigger button };
"animate": {
"effect": "globe", Selected animation (available: birds, cells, fog, globe, halo, net, rings, waves) "params": { Common parameters for all effects "el": "#animate-js", CSS id where the animation will be embedded "bg_position": "center center", Set the position of the background "mouseControls": true, Controlling animation by mouse movement "touchControls": true, Controlling animation by swiping on the touch screen "gyroControls": false, Controlling animations with the gyrocompass of mobile devices "minHeight": 200.00, "minWidth": 200.00 }, "preset": { Animation presets ... Other configuration keys - here I refer to the Vanta.js online configurator https://www.vantajs.com/ } };
- Further work on the development of the template is planned, hence the bootstrap 5.3.3 and jquery 3.7.1 libraries have been included, at the same time libraries provided natively by OPNsense will not be used
- Some functions have been separated from the API, their notation has been changed
- A method for dynamically loading scripts into the template has been added - in the current version it is used by vanta.js dependencies, eventually it will be used more widely
- The layout has been changed, which was modeled on the Login Screen Design prepared by Ankur Tripathi
- CSS declarations have been improved, rtl support has been improved
- Particles.js has been abandoned, Vanta.js has been implemented in its place - thanks and respect to @tengbao - great job! The following effects are available: birds, cells, fog, globe, halo, net, rings and waves, which can be configured in a simplified way in settings.json in the animate key as the preferred effect, its params and the preset of the declared effect.
- Slovak translation included - thanks to @Gouster4.
- Optimizing the code of javascript functions.
- Splitting CSS into smaller portions, nesting CSS selectors.
- Blocking the ability to log into the system for a specified period of time, after a specified number of possible attempts.
- Logo update for OPNsense v25 - many thanks for the update and vigilance to @OctoCharm.
- Language selector layout modified.
- New translations generated using AI for multiple languages.
- Expanded digital accessibility support (WCAG).
- Introduced a new interactive Accessibility Tour Guide (TourGuide) compliant with WCAG 2.1 AA.
- Implement a method for embedding (or dynamically generating) the layout and its dependencies