This repository contains Ansible playbooks for setting up Ubuntu servers with nginx, PostgreSQL, and SSL certificates.
├── playbooks/ad
│ ├── 01-server-setup.yml # Initial server setup and security
│ ├── 02-nginx.yml # Nginx installation and configuration
│ ├── 03-postgresql.yml # PostgreSQL installation and configuration
│ ├── 04-ssl-certbot.yml # SSL certificate setup with Let's Encrypt
│ └── 05-docker.yml # Docker and Docker Compose installation
├── inventory/
│ └── hosts.yml # Server inventory (add your servers here)
├── templates/
│ ├── nginx.conf.j2 # Nginx main configuration
│ ├── temp-site.conf.j2 # Temporary site for SSL verification
│ └── ssl-site.conf.j2 # SSL-enabled site configuration
└── ansible.cfg # Ansible configuration
Since you're starting with root access, here's how to set up SSH keys and create a secure user:
# Generate SSH key pair on your local machine
ssh-keygen -t rsa -b 4096 -f ~/.ssh/server_key
# Copy public key to your server (using root initially)
ssh-copy-id -i ~/.ssh/server_key.pub root@YOUR_SERVER_IP
# Test root connection
ssh -i ~/.ssh/server_key root@YOUR_SERVER_IPRun these commands on your server (as root):
# Create new user (replace 'deploy' with your preferred username)
adduser deploy
# Add user to sudo group
usermod -aG sudo deploy
# Create SSH directory for the new user
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
# Copy your SSH public key to the new user
cp /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
# Fix ownership and permissions for entire user directory structure
chown deploy:deploy /home/deploy
chmod 755 /home/deploy
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
# Configure SSH daemon to allow key authentication
nano /etc/ssh/sshd_config
# Find and uncomment/modify these lines (remove the # at the beginning):
LoginGraceTime 2m
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
PasswordAuthentication yes
# Restart SSH service to apply changes
systemctl restart sshd
# Test new user connection from your local machine
ssh -i ~/.ssh/server_key deploy@YOUR_SERVER_IPIf you get "Permission denied" or "LoginGraceTime" errors, run these debugging steps:
# Check SSH logs for specific errors
tail -f /var/log/auth.log
# Test connection with verbose output to see what's failing
ssh -v -i ~/.ssh/server_key deploy@YOUR_SERVER_IP
# If you see "Could not open authorized keys" errors, fix permissions:
chown deploy:deploy /home/deploy
chmod 755 /home/deploy
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
# If SELinux is enabled, restore security context:
restorecon -R /home/deploy/.ssh/Once you've verified the new user works, disable root login:
# Edit SSH configuration
nano /etc/ssh/sshd_config
# Find and change these lines (uncomment and set to no):
PermitRootLogin no
PasswordAuthentication no
# Restart SSH service
systemctl restart sshdIf you prefer to generate the key on the server:
# On your server (as root), generate the key
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
# Display the private key (copy this to your local machine)
cat ~/.ssh/id_rsa
# The public key is automatically added to authorized_keys during generationThen on your local machine:
# Create the key file and paste the private key content
nano ~/.ssh/server_key
chmod 600 ~/.ssh/server_key
# Test connection
ssh -i ~/.ssh/server_key root@YOUR_SERVER_IPEdit inventory/hosts.yml and add your servers:
all:
vars:
ansible_user: deploy # Use your new non-root user
ansible_ssh_private_key_file: ~/.ssh/server_key
ansible_host_key_checking: false
webservers:
hosts:
your-server:
ansible_host: YOUR_SERVER_IP
postgres_admin_password: "your_secure_password"
ssl_domain: "yourdomain.com"
ssl_email: "your-email@example.com"# 1. Initial server setup (updates, security, firewall)
ansible-playbook playbooks/01-server-setup.yml --ask-become-pass
# 2. Install and configure nginx
ansible-playbook playbooks/02-nginx.yml --ask-become-pass
# 3. Install and configure PostgreSQL (replace with your secure password)
ansible-playbook playbooks/03-postgresql.yml -e postgres_admin_password="MySecurePassword123!" --ask-become-pass
# 4. Setup SSL with Let's Encrypt (replace with your domain and email)
ansible-playbook playbooks/04-ssl-certbot.yml -e ssl_domain="yourdomain.com" -e ssl_email="admin@yourdomain.com" --ask-become-pass
# 5. Install Docker and Docker Compose
ansible-playbook playbooks/05-docker.yml --ask-become-pass
# 6. Create PostgreSQL database (replace with your database details)
ansible-playbook playbooks/06-create-database.yml -e database_name="myapp_db" -e database_user="myapp_user" -e database_password="SecureDbPassword123!" --ask-become-pass# Complete server setup with all components
ansible-playbook playbooks/01-server-setup.yml --ask-become-pass && \
ansible-playbook playbooks/02-nginx.yml --ask-become-pass && \
ansible-playbook playbooks/03-postgresql.yml -e postgres_admin_password="MySecurePassword123!" --ask-become-pass && \
ansible-playbook playbooks/04-ssl-certbot.yml -e ssl_domain="yourdomain.com" -e ssl_email="admin@yourdomain.com" --ask-become-pass && \
ansible-playbook playbooks/05-docker.yml --ask-become-pass && \
ansible-playbook playbooks/06-create-database.yml -e database_name="myapp_db" -e database_user="myapp_user" -e database_password="SecureDbPassword123!" --ask-become-pass# Run on specific server (if you have multiple servers in inventory)
ansible-playbook playbooks/01-server-setup.yml --limit server1 --ask-become-pass
# Run on all servers (default behavior)
ansible-playbook playbooks/01-server-setup.yml --ask-become-passTo avoid entering sudo password every time, configure passwordless sudo on your server:
# SSH as root to your server
ssh -i ~/.ssh/server_key root@YOUR_SERVER_IP
# Add passwordless sudo for your user
echo "deploy ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/deploy
chmod 440 /etc/sudoers.d/deploy
# Test it works
su - deploy
sudo whoami # Should return "root" without asking for passwordAfter setting up passwordless sudo, you can run playbooks without --ask-become-pass:
# Example without password prompt
ansible-playbook playbooks/01-server-setup.yml# Test connection to all servers
ansible all -m ping
# Test connection to specific server
ansible server1 -m pingssl_domain: Your domain name for SSL certificatessl_email: Email for Let's Encrypt registrationpostgres_admin_password: Password for PostgreSQL admin user
ansible_user: SSH user (default: deploy)ansible_ssh_private_key_file: Path to SSH private key
- Updates all packages
- Installs essential packages (curl, wget, vim, etc.)
- Configures UFW firewall
- Sets up fail2ban for security
- Installs nginx
- Configures optimized nginx.conf
- Opens HTTP/HTTPS ports in firewall
- Removes default site
- Installs PostgreSQL
- Sets admin password (passed as parameter)
- Configures PostgreSQL to listen on all addresses
- Enables MD5 authentication for Docker internal network (172.17.0.0/16)
- Starts PostgreSQL service
- Installs certbot via snap
- Creates temporary nginx site for domain verification
- Obtains SSL certificate from Let's Encrypt
- Configures SSL-enabled nginx site with security headers
- Sets up automatic certificate renewal
- Installs Docker CE from official repository
- Installs Docker Compose
- Adds user to docker group
- Starts and enables Docker service
- Verifies installation
- Creates a new PostgreSQL database
- Creates a database user with password
- Grants all privileges to the user
- Tests database connection
- Displays connection string
- Ansible installed on control machine
- SSH access to target servers
- Domain name pointing to your server (for SSL)
- Ubuntu 20.04+ target servers
- PostgreSQL is configured to allow MD5 authentication on Docker internal network
- UFW firewall is enabled with only necessary ports open
- fail2ban is installed for intrusion prevention
- SSL certificates include security headers and HSTS