# Configuration ## 1. Configure the firewall at the VPS host | Public IP | | :------------: | | 217.154.51.242 | | Action | Allowed IP | Protocol | Port(s) | Description | | :-----: | :--------: | :------: | ----------: | :------------ | | Allow | Any | TCP | 80 | HTTP | | Allow | Any | TCP | 443 | HTTPS | | Allow | Any | TCP | 2222 | Git SSH | | Allow | Any | TCP | 2885 | VPS SSH | | Allow | Any | UDP | 3478 | STUN/TURN | | Allow | Any | TCP | 5349 | TURN/TLS | | Allow | Any | TCP | 7881 | LiveKit TCP | | Allow | Any | UDP | 50000-60000 | LiveKit Media | ## 2. Configure the DNS settings at domain registrar | Host (avaaz.ai) | Type | Value | | :-------------: | :---: | :------------: | | @ | A | 217.154.51.242 | | www | CNAME | avaaz.ai | | app | A | 217.154.51.242 | | api | A | 217.154.51.242 | | rtc | A | 217.154.51.242 | | git | A | 217.154.51.242 | ## 3. Change the SSH port from 22 to 2885 1. Connect to the server. ```bash ssh username@avaaz.ai ``` 2. Edit the SSH configuration file. ```bash sudo nano /etc/ssh/sshd_config ``` 3. Add port 2885 to the file and comment out port 22. ```text #Port 22 Port 2885 ``` 4. Save the file and exit the editor. - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. 5. Restart the SSH service. ```bash sudo systemctl daemon-reload && sudo systemctl restart ssh.socket && sudo systemctl restart ssh.service ``` 6. **Before closing the current session**, open a new terminal window and connect to the server to verify the changes work correctly. ```bash ssh username@avaaz.ai # ssh: connect to host avaaz.ai port 22: Connection timed out ssh username@avaaz.ai -p 2885 ``` 7. Once the connection is successful, close the original session safely. ## 4. Build and deploy the infrastructure 1. Check with `dig git.avaaz.ai +short` wether the DNS settings have been propagated. 2. SSH into the VPS to install Docker & docker compose. ```bash ssh username@avaaz.ai -p 2885 ``` 3. Update system packages. ```bash sudo apt update && sudo apt upgrade -y ``` 4. Install dependencies for Docker’s official repo ```bash sudo apt install -y \ ca-certificates \ curl \ gnupg \ lsb-release ``` 5. Add Docker’s official APT repo. ```bash sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) \ signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update ``` 6. Install Docker Engine + compose plugin. ```bash sudo apt install -y \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin ``` 7. Verify the installation. ```bash sudo docker --version sudo docker compose version ``` 8. Create the `/etc/docker/daemon.json` file to avoid issues with overusing disk for log data. ```bash sudo nano /etc/docker/daemon.json ``` 9. Paste the following. ```json { "log-driver": "local", "log-opts": { "max-size": "10m", "max-file": "3" } } ``` 10. Save the file and exit the editor. - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. 11. Restart the docker service to apply changes. ```bash sudo systemctl daemon-reload sudo systemctl restart docker ``` 12. Create directory for infra stack in `/srv/infra`. ```bash sudo mkdir -p /srv/infra sudo chown -R $USER:$USER /srv/infra cd /srv/infra ``` 13. Create directories for Gitea (repos, config, etc.) and Runner persistent data. Gitea runs as UID/GID 1000 by default. ```bash mkdir -p gitea-data gitea-runner-data ``` 14. Create the `/srv/infra/docker-compose.yml` (Caddy + Gitea + Runner) file. ```bash nano docker-compose.yml ``` 15. Paste the following. ```yaml services: caddy: # Use the latest official Caddy image image: caddy:latest # Docker Compose automatically generates container names: __ container_name: caddy # Fixed name used by Docker engine # Automatically restart unless manually stopped restart: unless-stopped ports: # Expose HTTP (ACME + redirect) - "80:80" # Expose HTTPS/WSS (frontend, backend, LiveKit) - "443:443" volumes: # Mount the Caddy config file read-only - ./Caddyfile:/etc/caddy/Caddyfile:ro # Caddy TLS certs (persistent Docker volume) - caddy_data:/data # Internal Caddy state/config - caddy_config:/config networks: # Attach to the shared "proxy" network - proxy gitea: # Official Gitea image with built-in Actions image: gitea/gitea:latest container_name: gitea # Fixed name used by Docker engine # Auto-restart service restart: unless-stopped environment: # Run Gitea as host user 1000 (prevents permission issues) - USER_UID=1000 # Same for group - USER_GID=1000 # Use SQLite (stored inside /data) - GITEA__database__DB_TYPE=sqlite3 # Location of the SQLite DB - GITEA__database__PATH=/data/gitea/gitea.db # Custom config directory - GITEA_CUSTOM=/data/gitea volumes: # Bind mount instead of Docker volume because: # - We want repos, configs, SSH keys, and SQLite DB **visible and editable** on host # - Easy backups (just copy `./gitea-data`) # - Easy migration # - Avoids losing data if Docker volumes are pruned - ./gitea-data:/data networks: - proxy ports: # SSH for Git operations mapped to host 2222 - "2222:22" gitea-runner: # Official Gitea Actions Runner image: gitea/act_runner:latest container_name: gitea-runner # Fixed name used by Docker engine restart: unless-stopped depends_on: # Runner requires Gitea to be available - gitea volumes: # Runner uses host Docker daemon to spin up job containers (Docker-out-of-Docker) - /var/run/docker.sock:/var/run/docker.sock # Bind mount instead of volume because: # - Runner identity is stored in /data/.runner # - Must persist across container recreations # - Prevents duplicated runner registrations in Gitea # - Easy to inspect/reset via `./gitea-runner-data/.runner` - ./gitea-runner-data:/data environment: # Base URL of your Gitea instance - GITEA_INSTANCE_URL=${GITEA_INSTANCE_URL} # One-time registration token - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN} # Human-readable name for the runner - GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME} # Runner labels (e.g., ubuntu-latest) - GITEA_RUNNER_LABELS=${GITEA_RUNNER_LABELS} # Set container timezone to UTC for consistent logs - TZ=Etc/UTC networks: - proxy # Start runner using persisted config command: ["act_runner", "daemon", "--config", "/data/.runner"] networks: proxy: # Shared network for Caddy + Gitea (+ later app stack) name: proxy # Default Docker bridge network driver: bridge volumes: # Docker volume for Caddy TLS data (safe to keep inside Docker) caddy_data: name: caddy_data # Docker volume for internal Caddy configs/state caddy_config: name: caddy_config ``` 16. Save the file and exit the editor. - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. 17. Create the `/srv/infra/.env` file with environment variables. ```bash nano .env ``` 18. Paste the following: ```env # Base URL of your Gitea instance (used by the runner to register itself # and to send/receive workflow job information). GITEA_INSTANCE_URL=https://git.avaaz.ai # One-time registration token generated in: # Gitea → Site Administration → Actions → Runners → "Generate Token" # This MUST be filled in once, so the runner can register. # After registration, the runner stores its identity inside ./gitea-runner-data/.runner # and this value is no longer needed (can be left blank). GITEA_RUNNER_REGISTRATION_TOKEN= # Human-readable name for this runner. # This is shown in the Gitea UI so you can distinguish multiple runners: # Example: "vps-runner", "staging-runner", "gpu-runner" GITEA_RUNNER_NAME=gitea-runner # Runner labels allow workflows to choose specific runners. # The label format is: label[:schema[:args]] # - "ubuntu-latest" is the