https://github.com/Thomas-Shephard/ubuntu-ansible-setup.git
This project provides a set of Ansible playbooks to automate the setup and configuration of a secure Ubuntu server, ready to host web applications in Docker containers.
sudo privileges on the server for the initial setup run.This project uses a two-playbook workflow: setup.yml for initial server configuration, and deploy.yml for deploying applications.
This playbook performs the initial, one-time server setup. It hardens the server, installs necessary services (Nginx, WireGuard, etc.), and creates a new administrative user with sudo privileges.
inventory in the root of this project with the IP address of your server. You must connect as root or a user with sudo privileges for this first step.
[servers]
your_server_ip ansible_user=your_initial_user
Open initial_setup/vars/secrets.yml and set:
new_user_password: The password for this user.webhook_secret: A secret string for securing the GitHub webhook.github_pat: (Optional) A GitHub Personal Access Token.new_user_ssh_key: Your public SSH key.initial_setup/vars/main.yml and configure:
new_user: The username for your new, non-root administrative user.ssh_port: The port for SSH (defaults to 22).vpn_port: The UDP port for WireGuard (defaults to 51820).setup.yml playbook.
ansible-playbook -i inventory setup.yml --ask-pass --ask-become-pass
Initial setup is complete. The new user new_user has been created with sudo privileges.
inventory file to connect as the new administrative user. Ensure you specify your SSH private key file and the correct SSH port.
[servers]
your_server_ip ansible_user=new_user ansible_ssh_private_key_file=/path/to/your/private_key ansible_port=your_ssh_port
After the initial setup is complete, you can deploy one or more applications by running the deploy.yml playbook.
app_deployment/vars/main.yml and configure your application's settings:
app_repo: The Git repository URL of your application (e.g., https://github.com/user/my-cool-app.git).app_branch: The branch to deploy (defaults to main).app_domain_name: The domain name that will point to your application.certbot_email: Email address for Let's Encrypt expiration notifications.app_deployment_context: (Optional) The context label for GitHub status updates (e.g., deployment/production). Defaults to deployment/production.app_ports: A list of environment variable names that your docker-compose.yml expects for port mappings. APP_PORT is mandatory as it is used by the Nginx reverse proxy.@ (or your subdomain) -> your_server_ipwebhook -> your_server_ip (required for automatic deployments)dig or nslookup before running the playbook. If propagation is incomplete, the SSL certificate request will fail.
deploy.yml playbook.
ansible-playbook -i inventory deploy.yml --ask-become-pass
If your application's repository contains a .env.example file, Ansible will prompt you to enter values for each variable.
git push:
https://webhook.<your_app_domain>/webhookapplication/jsonwebhook_secret from initial_setup/vars/main.yml.add_client.yml)
This playbook adds a new client to the WireGuard VPN.
wireguard_add_client/vars/main.yml and set:
client_name: A unique name for your device.client_public_key: The public key of your WireGuard client.ansible-playbook -i inventory add_client.yml --ask-become-pass
This will generate a <client_name>.conf file in the project root.
<client_name>.conf file, replace YOUR_CLIENT_PRIVATE_KEY with your client's private key, and then import the configuration into your WireGuard client application.
> Note: The generated configuration uses Split Tunneling. Only traffic to the internal network (10.0.0.0/24) is routed through the VPN. Your normal internet traffic remains direct.
---
### Troubleshooting & Operations
#### Viewing Application Logs
Each application runs as a systemd user service. To view the logs for a specific application:
# Replace <app_user> with the user created for your app (usually the repo name)
# Get the User ID (UID) first:
id -u <app_user>
# Then view logs using the UID:
journalctl _UID=<UID> _SYSTEMD_USER_UNIT=app.service -f
#### Backups & Recovery
Automatic backups of application configurations (.env, docker-compose.yml) and backups/ directories run nightly.
/var/backups/apps/apps_backup_YYYY-MM-DD.tar.gztar -xzf /var/backups/apps/apps_backup_<DATE>.tar.gz/home/<app_user>/app/.env.example that require input), the system will reject the update to prevent crashing the app.
Fix: Run the Ansible deployment playbook manually to interactively provide the new values:
ansible-playbook -i inventory deploy.yml --ask-become-pass
#### Checking Webhook Service
If webhooks are not triggering updates:
systemctl status webhookjournalctl -u webhook -f200 or 202 response.new_user's home directory, and rootless Docker is used to run the application's containers. This provides strong security and isolation between your applications.
#### Secret Management
If your application repository contains a .env.example file, the deploy.yml playbook will automatically detect it and interactively prompt you for each variable. This creates a .env file in the application directory, which is used by Docker Compose. This ensures your sensitive application secrets are not hardcoded.
Note: If new keys are added to .env.example, a webhook-triggered deployment will fail. You must manually run ansible-playbook -i inventory deploy.yml to be prompted for the new secret values.
#### Service Status Webpage
A simple status page is created that lists all deployed services and provides clickable links to access them. This page is accessible via VPN only at http://status.internal.