To deploy my Next.js app to my local Debian server while still having my domain point to it, I had to first enable port forwarding on my router. I forwarded 80 to 80 and 443 to 443. Don't do what some guides say and do 80 to 3000, I can't remember why, but I think it had something to do with nginx. I had to enable some ports through my `ufw` firewall, I don't really remember which. I think one was `sudo ufw allow 'Nginx Full'`. Then `sudo ufw reload`. Speaking of, BEFORE STARTING THE NEXTJS app, go ahead and get nginx setup. This is what my `/etc/nginx/sites-available/nextjs-app` looked like: ``` server { server_name mydomain.com www.mydomain.com; location /.well-known/acme-challenge/ { root /var/www/html; } } ``` Then link it with `sudo ln -s /etc/nginx/sites-available/nextjs-app /etc/nginx/sites-enabled/`. Test with `sudo nginx -t`. Restart with `sudo systemctl restart nginx`. I made sure my DNS records were set up to point to my IP: - Host: @, Type: A, Data: MY_IP_ADDRESS - Host: www, Type: www, Data: MY_IP_ADDRESS Then I ran `sudo certbot --nginx`. This would automatically update my nginx file to accept SSL, but after that I changed it to work with Next.js. This is what it looked like after certbot and the NextJS addition: ``` server { server_name mydomain.com www.mydomain.com; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } location /.well-known/acme-challenge/ { root /var/www/html; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } ``` Then when I had a built version of my app on the server, I ran `pm2 start yarn --name "app_name" -- start` from within the app directory. You can set it to always start on server boot with `pm2 startup`. Then save with `pm2 save`. Now I can do like `pm2 start app_name`, `pm2 stop app_name`, `pm2 restart app_name`, and `pm2 reload app_name` (last one is supposedly zero downtime). After this, I was able to access my app at https://mydomain.com. _9.2.2024_ I then wanted to deploy a second app to my server, using the subdomain example.anotherdomain.com. In order to do this, I added a new A record in Cloudflare: ``` Host: example Type: A Data: MY_IP_ADDRESS ``` I cloned the repo I wanted to run to my server, and started it with: ```bash pm2 start yarn --name "second_example_app" -- start pm2 startup pm2 save ``` Then I had to create a new Nginx server block: ```bash sudo nano /etc/nginx/sites-available/example.anotherdomain.com ``` Where I put: ``` server { server_name example.anotherdomain.com; location /.well-known/acme-challenge/ { root /var/www/html; } location / { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } listen [::]:443 ssl; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/example.anotherdomain.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/example.anotherdomain.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = example.anotherdomain.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name example.anotherdomain.com; return 404; # managed by Certbot ``` Then I enabled the server block with: ```bash sudo ln -s /etc/nginx/sites-available/example.anotherdomain.com /etc/nginx/sites-enabled ``` Tested with: ```bash sudo nginx -t ``` Reloaded nginx: ```bash sudo systemctl reload nginx ``` Got the SSL certificate: ```bash sudo certbot --nginx -d example.anotherdomain.com ``` Restarted the app for good measure: ```bash pm2 restart second_example_app ``` _12.1.2024_ I make no promises as to the security of either of these methods. If there are glaring vulnerabilities or easy ways to harden these, please shoot me an email at [[email protected]](mailto:[email protected]).