Hi there! I'm Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.
Your website is cool. But is it private?
Whether you're protecting a staging server, a Nomad dashboard, or a developer tool—Basic Auth via .htpasswd
is your first line of defense.
Here's how to do it the Ansible way, with reusable roles, templated config, and one command deploys.
Quick Setup: What You'll Build
- NGINX config auto-synced with Ansible
-
.htpasswd
file created with secure credentials - Basic Auth enforced on protected domains
- All configs dropped into
/etc/nginx/
viarsync
- Symlinks created in
/etc/nginx/sites-enabled/
- SSL ready for Certbot if needed
Project Structure
Start by generating the role:
ansible-galaxy init roles/nginx-conf-sync --offline
Your structure should look like:
ansible/
├─ nginx-conf-sync-playbook.yml
├─ roles/
│ ├─ nginx-conf-sync/
│ │ ├─ files/
│ │ │ ├─ answer.dev.to
│ │ │ ├─ budi.dev.to
│ │ ├─ templates/
│ │ │ ├─ nginx.conf.j2
│ │ │ └─ options-ssl-nginx.conf.j2
│ │ ├─ tasks/
│ │ │ ├─ main.yml
│ │ │ ├─ create-nginx-confs.yml
│ │ │ ├─ certbot-setup-playbook.yml
│ │ │ └─ restart-nginx.yml
...
Creating the .htpasswd
File with Ansible
Inside roles/nginx-conf-sync/tasks/main.yml
, ensure this task exists:
- name: Create .htpasswd file for basic auth
command: htpasswd -bc /etc/nginx/.htpasswd hexmos v@6U6NYFVJ9CSk
args:
creates: /etc/nginx/.htpasswd
This ensures the file is created once unless manually deleted. Want to regenerate it each time? Remove args.creates
.
To clean up stale passwords before that:
- name: Remove .htpasswd file if it exists
file:
path: /etc/nginx/.htpasswd
state: absent
Add Auth to Your NGINX Config
In your nginx.conf.j2
or domain-specific confs (files/answer.dev.to
, etc.), add:
server {
server_name nomad.apps.hexmos.com;
location / {
auth_basic "Administrator’s Area";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://localhost:4646; # or whatever your app is
}
}
Ansible will rsync
this into /etc/nginx/sites-available/
and symlink it.
Full Task Flow (Summary)
Your main.yml
calls:
- import_tasks: create-nginx-confs.yml
- import_tasks: install-cron.yml
- import_tasks: certbot-setup-playbook.yml
- import_tasks: restart-nginx.yml
Inside create-nginx-confs.yml
, make sure you have:
- name: Ensure NGINX config directory exists
file:
path: "/etc/nginx/sites-available"
state: directory
- name: Deploy main nginx.conf from template
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
- name: Sync all nginx domain configs using rsync
synchronize:
src: "{{ role_path }}/files/"
dest: "/etc/nginx/sites-available/"
recursive: yes
delete: yes
- name: Create symlinks in bulk
ansible.builtin.shell: |
for site in {{ nginx_conf_domains | join(' ') }}; do
ln -sf "/etc/nginx/sites-available/$site" "/etc/nginx/sites-enabled/$site"
done
Test It
- Run your playbook:
ansible-playbook -i hosts.ini nginx-conf-sync-playbook.yml
Access the site in your browser.
You’ll be prompted for a username (hexmos
) and password (v@6U6NYFVJ9CSk
).To reset the password:
ansible-playbook -i hosts.ini nginx-conf-sync-playbook.yml
Just let the .htpasswd
file get regenerated.
Pro Tips
- Use
htpasswd -B
instead of-m
to use bcrypt instead of MD5 for stronger hashing. - Store the username/password as Ansible Vault secrets if you're pushing this to CI.
- Protect specific locations (like
/admin
) if you don’t want to auth the whole site.
That’s a Wrap
A single .htpasswd
file + NGINX + Ansible = locked down and audit-friendly.
Whether you’re shipping staging sites, internal dashboards, or legacy admin panels — drop in a password wall without writing a line of shell.
Fast. Reproducible. Scriptable. Done.
LiveAPI helps you get all your backend APIs documented in a few minutes.
With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.
If you're tired of updating Swagger manually or syncing Postman collections, give it a shot.
Top comments (0)