28 Nov 2021, 18:24

Replace your docker with 3 easy steps

I don’t like managing servers. This is a well-known fact. My way around it was to set up all my apps using docker, and that made me happy.

After my small server ran out of space with only 5 web apps running, I started changing my mind. On top of this, I used GitHub actions with azure, and loved it.

For that reason I moved my dotnet webapp from docker to a Linux service automatically deployed by github actions.

To better explain this, I am going to use pitaco, a comment box I have created for studying purposes: https://github.com/tiagodll/pitaco

1. Setup the app as a Linux service

clone your app and publish it in your home folder

git clone git@github.com:tiagodll/pitaco.git
cd pitaco
dotnet publish src/Pitaco.Server/ -c Release -o ./publish --self-contained --runtime linux-x64
cp –R ./publish /full/path/to/pitaco

then create an ini file to set it up as a service

[Unit]
Description=Pitaco kestrel service

[Service]
WorkingDirectory=/full/path/to/pitaco
ExecStart=/full/path/to/pitaco/Pitaco.Server
SyslogIdentifier=Pitaco
Restart=always
User=your-user
RestartSec=5
# copied from dotnet documentation at
# https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1#code-try-7
KillSignal=SIGINT
Environment="ASPNETCORE_ENVIRONMENT=Production"
Environment="ASPNETCORE_URLS=http://+:6000"
Environment="CONNECTION_STRING=Data Source=/path/to/pitaco.db;Pooling=True"
Environment="DOTNET_PRINT_TELEMETRY_MESSAGE=false"

[Install]
WantedBy=multi-user.target

then install the service

sudo cp pitaco.service /etc/systemd/system/pitaco.service
sudo systemctl daemon-reload
sudo systemctl start pitaco

2. set up a reverse proxy if you don’t already have it

prerequisite: SSL certificates (you can use lets-encrypt)

remember to use the same port set in the service

server {
    if ($host = pitaco.dalligna.com) {
        return 301 https://$host$request_uri;
    }
    listen 80;
    server_name pitaco.dalligna.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen              443 ssl;
    server_name         pitaco.dalligna.com;
    ssl_certificate     /etc/letsencrypt/live/pitaco.dalligna.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pitaco.dalligna.com/privkey.pem; 

    location / {
        proxy_pass  http://127.0.0.1:6000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

}

3. set up github actions

Create some secrets:

  • SSH_PRIVATE_KEY: your private key
  • REMOTE_HOST: your server pi or domain
  • REMOTE_USER: the user that your service is going to run as
  • REMOTE_TARGET: the folder where your app is deployed

just click in actions, and create your yaml based on this:

name: .NET

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Set up .NET
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: '6.0.x'

      - name: Build with dotnet
        run: dotnet build src/Pitaco.Server/ --configuration Release

      - name: dotnet publish
        run: dotnet publish src/Pitaco.Server/ -c Release -o ./publish --self-contained --runtime linux-x64
      
      - name: copy published files
        uses: easingthemes/ssh-deploy@main
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          SOURCE: "publish/"
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          TARGET: ${{ secrets.REMOTE_TARGET }}

and that is all.

Now your app will be automatically deployed on every commit to main

you are welcome 😄