diff --git a/src/blog/posts/2024/5/learning-go-day-8.md b/src/blog/posts/2024/5/learning-go-day-8.md new file mode 100644 index 0000000..94db189 --- /dev/null +++ b/src/blog/posts/2024/5/learning-go-day-8.md @@ -0,0 +1,145 @@ +--- +title: "Learning Go: Day Eight" +date: 2024-05-08T08:00:00.0Z +tags: + - learning + - go +excerpt: "Getting the project deployed via Gitea actions" +--- + +So that I can do the whole build-in-public thing properly, I always want my code to automatically deploy. I've got [Gitea Actions](https://docs.gitea.com/usage/actions/overview) on my Gitea server, so I can use those to build, deploy, and start a Go binary. + +## Building and copying a binary + +This is the simplest part. I had a decent template from my Eleventy action that I was able to take and turn into the following workflow: + +```yaml +name: Build and copy to prod +on: + push: +jobs: + build-and-copy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.22 + - name: Build binary + run: go build -o dist/oopsie + - name: Install SSH Key + uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.SSH_KEY }} + known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + - name: Copy to prod + run: scp -rp dist/* ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:oopsie/ +``` + +This installs Go on the action runner, builds the binary, and then uses SCP to copy the compiled binary onto my server. To facilitate this, I created a user on my VPS, created a new SSH key, and added the public key to the `.ssh/authorized_keys` file. Then I added the private key to the Gitea action secrets, along with the `known_hosts` entry for my git server, the name of the user I created, and the hostname for my VPS. + +## Running the software + +So now I need to run my compiled software. I can create a systemd service to do this, and then run it as the user I've created. First of all I create a new file, `/etc/systemd/user/oopsie.service`: + +```systemd +[Unit] +Description=Daemon for the Oopsie service + +[Service] +Type=simple +#User= +#Group= +ExecStart=/home//oopsie/oopsie +Restart=on-failure +StandardOutput=file:%h/log_file + +[Install] +WantedBy=default.target +``` + +Then, as the user I've created I run: + +```bash +systemctl --user daemon-reload +systemctl --user start oopsie.service +``` + +And can confirm my service is running locally: + +```bash +curl -X POST http://localhost:8000 +> This was a POST request! +``` + +## Nginx proxy + +Next up I need to use Nginx's `proxy_pass` directive to direct any requests to https://oopsie.lewisdale.dev to my running service. Again, this was mostly lifted from an existing template I already had: + +```nginx +server { + listen 80; + listen [::]:80; + server_name oopsie.lewisdale.dev; + rewrite ^ https://$server_name$request_uri? permanent; +} + +server { + # SSL configuration + # + listen 443 ssl; + listen [::]:443 ssl; + server_name oopsie.lewisdale.dev; + + # Include certificate params + include snippets/certs/lewisdale.dev; + ssl_certificate /etc/letsencrypt/live/lewisdale.dev/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/lewisdale.dev/privkey.pem; # managed by Certbot + + include /etc/letsencrypt/options-ssl-nginx.conf; + + location / { + proxy_pass http://localhost:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +Woo, now I can actually access my service over the internet! + +![Screenshot from Mozilla Firefox, showing oopsie.lewisdale.dev responding with "This was a GET request!"](./src/images/oopsie-working.png) + +## Restarting the service + +Finally, I can use the `-o` argument with the `RemoteCommand` [SSH config option](https://linux.die.net/man/5/ssh_config) to execute a command. I can use that to run `systemctl restart`: + +```yaml +- name: Restart the service + run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user restart oopsie.service" +``` + +## Nope + +Ah, that's not quite correct. My first build failed: + +```bash +scp: oopsie//oopsie: Text file busy +``` + +I can't overwrite a file while it's in use. Instead, I have to stop the service, copy the file, and then start the service again: + +```yaml +- name: Stop the service + run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user stop oopsie.service" +- name: Copy to prod + run: scp -rp dist/* ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:oopsie/ +- name: Restart the service + run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user start oopsie.service" +``` + +And that works! It deploys successfully. Ironically, there's a minor bit of downtime while it does, but for now that's really not an issue. You can see the project in progress on [its deployed home](https://oopsie.lewisdale.dev) or [on the Git repo](https://git.lewisdale.dev/lewis/oopsie). \ No newline at end of file diff --git a/src/images/oopsie-working.png b/src/images/oopsie-working.png new file mode 100644 index 0000000..99864b9 Binary files /dev/null and b/src/images/oopsie-working.png differ