iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
Deploy the Go program as a compiled Linux binary, run it under a dedicated systemd service on a private loopback port, and let Nginx handle public HTTP(S) traffic. Once DNS points to the server and port 80 is reachable, Certbot can obtain and renew a trusted Let’s Encrypt certificate.
What the finished deployment looks like
A production request follows this path:
- A browser resolves
example.comto your Ubuntu server. - Nginx listens on ports 80 and 443, terminates TLS, and receives the public request.
- Nginx proxies the request to the Go process at a private address such as
127.0.0.1:8080. - The Go application returns the response; Nginx sends it back to the client.
The Go executable does not need the Go toolchain on the production machine. You need the binary, its configuration and assets, a service account, and a supervisor. systemd starts the application at boot, keeps it running after an SSH session ends, restarts it after a failure, and provides a consistent place to inspect logs. Nginx is the public boundary, so the application port can remain inaccessible from the internet.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesThis guide uses a conventional Ubuntu server, a domain named example.com, an application binary named myapp, and port 8080. Replace those values with your own names. Commands that change files under /etc or install packages require sudo.
Choose the deployment shape before installing anything
| Approach | What you manage | When it fits | Trade-offs |
|---|---|---|---|
| Binary plus systemd | A Linux executable, configuration files, a service unit, Nginx and the host firewall | A small or medium application on one Ubuntu server; the simplest path from source to a reliable service | You own host updates, dependency isolation and rollout procedures |
| Containerized Go deployment | A container image, a container runtime or orchestrator, networking, persistent storage and Nginx integration | Several services, repeatable image-based releases, or an existing container platform | More moving parts; logs, restart policy and port exposure must be configured in both the container layer and the host |
The rest of this article uses the binary-plus-systemd model. The same Nginx design can sit in front of a container, but the upstream address and restart commands will differ.
#1 Best Overall
- Powerful Turbo Fan:CAGIWIRU Electric Air Duster have reached speed up to 130000RPM,Can efficient remove dust and debris.With LED light and Three Adjustable Speed to meet with different cleaning tasks.
- With Attached USB C Fasting Charging cable.Charing 3 hours,Enjoy up to 240 minutes of use on the lowest setting, For third speed can use for 25mins.with four charging options to meet with your needs.
- Wide Application: attached 5 different nozzles,making it suitable for a variety of scenes, such as car,pet, pc, keyboards, and other electronic devices. It also serves for office and home clean duster.
- Handy Design & Portable:Cordless air duster electric nozzle is Light weight and small size, design and comfortable to hold and space saving, convenient to carry around. You can put it in your room or inside the car without taking up space.
- Economical &Reusable: Built durable materials with a long-lasting battery,our CAGIWIRU air duster it's a sustainable alternative to disposable air cans.
Prepare the Ubuntu server
Minimum information and access
- An Ubuntu server with administrative access over SSH. An Ubuntu-compatible VPS is a common choice when you need a public IPv4 address and control of DNS and firewall rules.
- A domain name whose DNS records you can edit. Use the final hostname, not a temporary provider hostname, when planning HTTPS.
- The application’s runtime configuration, secrets and any static files it needs. Keep secrets out of the executable and out of a public web directory.
- A build machine or CI job that can produce a Linux binary for the server’s CPU architecture.
Update packages and create a non-root account
sudo apt update
sudo apt upgrade -y
sudo adduser --system --group --home /opt/myapp myapp
sudo install -d -o myapp -g myapp /opt/myapp/bin
sudo install -d -o root -g myapp -m 0750 /etc/myapp
The myapp account has no interactive login by default and owns only the application directory. Running the web process as this user limits the damage an application-level vulnerability can cause. Do not give the account blanket sudo access.
Install the packages used by the host
sudo apt install -y nginx ufw
Install build tools on the server only if you deliberately compile there. A release binary can be built elsewhere and copied to this host, which keeps compilers and source code out of the production environment.
Recommended Free Tools
Build a Linux Go binary
Cross-compile on your workstation or CI
For a 64-bit x86 Ubuntu server, a typical build command is:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" -o myapp ./cmd/myapp
GOOS=linux selects the operating system and GOARCH=amd64 selects the CPU architecture. Use arm64 instead when the server is ARM-based. Confirm the target with uname -m on the server; x86_64 corresponds to amd64 and aarch64 corresponds to arm64.
CGO_ENABLED=0 produces a statically linked binary for applications that do not require C libraries. If your project uses cgo, a database driver with native dependencies, image libraries or another C component, build with the appropriate cross-compiler and deploy the matching shared libraries, or compile directly on a compatible Ubuntu environment. Do not assume a cgo binary built on one distribution will run unchanged on another.
Run the application locally first with the same environment variables and configuration format you plan to use in production. Confirm it listens on the intended address and responds to a health endpoint such as /healthz. A useful production default is to make the listen address configurable, with 127.0.0.1:8080 as the server value.
Copy the release to Ubuntu
scp myapp ubuntu@example.com:/tmp/myapp
ssh ubuntu@example.com
sudo install -o myapp -g myapp -m 0755 /tmp/myapp /opt/myapp/bin/myapp
rm /tmp/myapp
Copy migrations, templates, certificates used by the application, or static assets to dedicated directories under /opt/myapp and set ownership deliberately. A binary that starts from your shell is not yet a service: it still needs an explicit working directory, environment and restart policy.
Rank #2
- Screen Cleaner is Your Screen’s New Bestfriend! - EVEO is proud to present a screen cleaner that’s perfectly suited for your TV. Meet your new screen cleaner, computer screen cleaner, laptop cleaner, iPad cleaner, Macbook,tv cleaner or any other electronic device. Our screen cleaner spray and wipe along with the included plush microfiber cloth, easily removes dust, fingerprints & other smudges on the screen’s surface. Clean effectively for a streak-free screen
- Gentle on your Screens - Our screen cleaner spray and wipes is compatible to be used even for the most sensitive LCD, LED, CRT, and OLED screens in proper use. Be at ease knowing that this product is compatible with all the major brands: LG, SONY, Samsung, Sharp, iPad, iPhone, Android screens, Kindle, PC monitors - we’ve got you covered! Can be used as LCD screen cleaner, tv cleaner, smart tv screen cleaner, and more
- Premium Super Soft Plush Microfiber Cloth - Included in this efficient screen cleaning kit. This screen cleaner spray and wipe has our signature plush microfiber cloth specially designed to comply with screens and monitors and leave them streak-free. Has been shown to effectively absorbs stubborn stains, zero streaks, and no fiber shedding. Always use this together with our screen cleaner for the best results
- Easy-to-Use Screen Cleaner Kit + microfiber cleaning cloth - The EVEO Screen Cleaning Kit will easily be your new favorite tool when it comes to taking care of the things you love most, quick and easy solution for a streak-free screen. Simply screw on the sprayer gun on the screen cleaner bottle. Spray the cleaning liquid onto the microfiber cloth, then wipe the screen until desired cleanliness & shine is achieved.
- Quality Screen Care Kit Worth Purchasing - Enjoy a convenient Screen Cleaner anytime, anywhere you need it. Your satisfaction is our top priority. We stand behind the quality of our products and that’s why, you shouldn’t be worrying at all. We manufacture the Best Screen Cleaner. and can be used for laptop cleaning kit, laptop screen cleaner, tv screen cleaner for smart tv. MacBook screen cleaner, monitor cleaner or screen cleaner spray for electronic devices with microfiber cleaning cloth
Store configuration without exposing secrets
Use a root-owned environment file readable by the service group, or another secret-management system appropriate to your infrastructure. For a simple host deployment:
sudo tee /etc/myapp/myapp.env >/dev/null <<'EOF'
APP_ENV=production
HTTP_ADDR=127.0.0.1:8080
# DATABASE_URL=replace-this-value
EOF
sudo chown root:myapp /etc/myapp/myapp.env
sudo chmod 0640 /etc/myapp/myapp.env
Do not put passwords in a world-readable file, in a unit file committed to a public repository, or in an Nginx document root. If a value contains spaces or shell-sensitive characters, follow systemd’s environment-file syntax and test the resulting value rather than assuming shell quoting rules apply.
Your Go program must actually read the variable names you choose. If the application uses a YAML or JSON configuration file instead, set an explicit path in the unit and make that file readable only by the service and administrators.
Create the systemd service
Write an explicit unit file
Create /etc/systemd/system/myapp.service:
sudo tee /etc/systemd/system/myapp.service >/dev/null <<'EOF'
[Unit]
Description=My Go web application
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/opt/myapp/bin/myapp
Restart=on-failure
RestartSec=5s
# Basic filesystem and privilege restrictions
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target
EOF
An absolute ExecStart path avoids ambiguity about the executable search path. Restart=on-failure handles crashes without creating a tight restart loop; RestartSec gives a failing process time to settle. ProtectSystem, ProtectHome, PrivateTmp and NoNewPrivileges are useful baseline restrictions, but applications that must write outside their working directory may need a narrower, explicit exception. Test the service after adding hardening rather than disabling all protections immediately.
DigitalOcean’s deployment example shows the same core pattern—a dedicated unit and a persistent process—while Ubuntu 24.04 deployment instructions commonly use a hardened unit. The important details are the explicit executable, a non-root identity where practical, a restart policy and a known configuration source. See the example at DigitalOcean’s Go and Nginx deployment guide.
Enable, start and verify it
- Ask systemd to reread unit files:
sudo systemctl daemon-reload. - Enable the service for boot:
sudo systemctl enable myapp. - Start it now:
sudo systemctl start myapp. - Check the state and recent messages:
sudo systemctl status myapp --no-pager. - Read the complete service log when diagnosing startup:
sudo journalctl -u myapp -b --no-pager. - Test the private listener from the server:
curl --fail http://127.0.0.1:8080/healthz.
Use sudo systemctl restart myapp after deploying a new binary or changing its environment. If the service will not start, inspect the journal before changing Nginx: an invalid configuration, missing file, wrong architecture, denied permission or occupied port is a Go-service problem, not a proxy problem.
Keep the Go listener private
Configure the application to bind to 127.0.0.1:8080, not 0.0.0.0:8080. A loopback bind means only processes on the server can connect directly; clients use Nginx instead. Confirm the result with:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
- 【Large size】:Measuring 800 x 300 mm/ 31. 5×12 inches, which is wider and taller than others. Large mouse pad can perfectly fit your keyboard and mouse of any size, and there is also ample space for peripherals such as phones, tablets, etc.
- 【LED backlight mouse pad】:Blade Hawks RGB mouse pad provides 7 static modes and 7 dynamic modes will give you the options you are looking for. Power-off memory function remembers the last lighting mode you selected. The super glow fiber Chroma will give you a colorful gaming setup that you want.
- 【Anti-slip rubber base】:Made from Natural rubber, this gaming mousepad will firmly grip your desktop, allowing you to enjoy the ultimate precision in the games you are most passionate about. It also comes with a texture that enhances this ability even further.
- 【Smooth and waterproof surface】: Micro-textured cloth surface, for extremely precise mouse control and a smooth movement. When liquid splashes on the gaming mouse pad, it forms water droplets and slides down. Will not delay your work or gameplay.
- 【Plug and play】: This mouse and keyboard pad is powered by USB, plug and play, no driver required. One button control light modes. Press one time to change the lighting mode, press twice to change the brightness, press and hold about 3 seconds turn ON/OFF.
sudo ss -ltnp | grep 8080
You should see a listener on 127.0.0.1:8080. If it listens on every interface, change the application setting or firewall rules before publishing the host. Keeping the private port unexposed also prevents users from bypassing Nginx’s TLS policy, request limits and access logging.
Configure Nginx as the reverse proxy
Create a server block
Create /etc/nginx/sites-available/example.com:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
}
}
proxy_pass points Nginx at the private Go listener. The forwarded headers preserve the original host, client address chain and scheme. Your framework must be configured to trust proxy headers only from the local Nginx process (or another explicitly trusted proxy); blindly trusting user-supplied forwarding headers can make IP-based controls and secure-URL redirects unreliable.
Enable the site safely
- Enable the server block:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com. - Remove the default site if it would otherwise catch the hostname:
sudo rm -f /etc/nginx/sites-enabled/default. - Validate the full configuration:
sudo nginx -t. - Only after a successful test, reload without dropping existing connections:
sudo systemctl reload nginx. - Check Nginx’s state if the reload fails:
sudo systemctl status nginx --no-pagerandsudo journalctl -u nginx -b --no-pager.
Run nginx -t before every reload. A syntax error, duplicate server name, missing certificate path or invalid include can prevent the reload; the test reports the file and line that needs correction.
Serve static files directly when that is appropriate
Large, immutable assets do not need to pass through Go. For example, if the release contains files in /opt/myapp/static, add a location before the catch-all proxy:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11location /static/ {
alias /opt/myapp/static/;
try_files $uri =404;
access_log off;
expires 7d;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
}
Use root or alias carefully: the path mapping rules differ, and an incorrect trailing slash can expose the wrong directory. If the Go application performs authorization or generates files dynamically, proxy those paths instead of serving them from disk.
Support WebSockets or long-lived requests when needed
For WebSockets, add an HTTP upgrade map in the Nginx http context and pass the upgrade headers in the relevant location:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# inside the WebSocket location
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
For server-sent events or streaming responses, review buffering and timeout settings for that endpoint rather than applying a global change to every request. Match Nginx timeouts to the Go handler’s expected duration and to any load balancer in front of the server.
Rank #4
- 【Softer and More Comfortable】Vaydeer wrist rest has unique diamond pattern, which is the combination of softness and aesthetics. The materials of wrist rest are improved into higher quality memory foam and covered with silky smooth lycra. The computer wrist rest makes you as comfortable and cushiony as like rest your wrists on clouds.
- 【Ergonomic Wrist Saver】The wrist rests for keyboard and mouse comes with a 17.32×3.15×0.83 inch keyboard wrist pad and a 5.94×3.15×0.83 inch mouse wrist support. Based on ergonomic design, the unique concave shape is the perfect fit for your wrist joints. The wrist rest pad fits most computer keyboards and laptops, improve hand and wrist posture, release your wrist and arm stress.
- 【Non-Slip Rubber Bottom】Featuring an anti-skid silicone base on the bottom, this wrist keyboard support stays firmly in place on your desk, preventing the padding from sliding around, ensuring stable and consistent wrist support during extended computer sessions.
- 【Better Experience & Pain Relief】Our keyboard arm rest is beneficial to alleviate the soreness caused by direct contact and friction between your arm and a hard desk surface, reducing the risk of wrist fatigue or carpal tunnel. The soft texture of memory foam can evenly distribute the pressure around your wrists and provide good support with just enough give.
- 【Helpful in Multiple Scenarios】Whether you're working, studying, writing, typing, gaming, this keyboard and mouse rest combo is an essential accessory to add comfort and support to your hands and wrists. It’s also a great gift for men, women, family, friend, coworker, gamer, teacher, etc.
Point DNS at the server and open only required ports
DNS records
Create an A record for example.com pointing to the server’s public IPv4 address. Add an AAAA record only when IPv6 is configured and reachable end to end; publishing a broken IPv6 address can make some clients fail even though IPv4 works. Add a separate record for www if you included it in server_name, or redirect it deliberately.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →DNS changes are cached according to the record’s TTL. Verify resolution from a system outside the server:
dig +short example.com A
dig +short example.com AAAA
Firewall policy
Allow SSH and web traffic, then enable the firewall:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Do not allow TCP port 8080 from the public internet. If SSH uses a nonstandard port, allow that port before enabling UFW or you can lock yourself out. Cloud-provider security groups or external firewalls must permit the same ports; a local UFW rule cannot compensate for an upstream block.
Add HTTPS with Let’s Encrypt and Certbot
Why port 80 and DNS matter
Ubuntu describes Let’s Encrypt as a free, automated certificate authority whose certificates are trusted by major browsers and clients. The HTTP-01 challenge requires the hostname to resolve to this server and inbound port 80 to be reachable. If DNS is wrong, Nginx is not serving the requested name, or a firewall blocks port 80, certificate issuance fails before Certbot can configure TLS. Ubuntu’s TLS documentation covers the supported methods at Ubuntu’s TLS certificate guide.
Install the Nginx plugin and request a certificate
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Certbot’s Nginx integration discovers the matching server block, obtains the certificate and can add the HTTPS listener and redirect HTTP requests. Read the proposed changes and provide a valid email address for expiry notices. If you only use one hostname, omit the unused -d option.
After Certbot changes Nginx, validate the result and test both the local service and public URL:
Best Value
- 【No Drill Mounted】Cable management tray can be assembled in as little as 3 minutes or less-simply. Side clips easily clampe the edge of desk, pass through the holes on the sides, and secure excess cables with baskets. Desk cable management supports inward or outward installation to meet your needs in different scenarios, and provides you with great convenience when collecting and organizing wires.
- 【Rubber Pad Protects Desk】Wire organizer under desk built-in soft rubber pads on the clamp protect your desk from scratches, so you will not damage your furniture or office.
- 【Sturdy and Beautiful】Cord management under desk is made of high-quality carbon steel and holds about 15 lbs. The wire basket has 2 holes on each side of the tray to enable your cables to pass freely. Cable baskets are suitable for desk thickness use from 0.4" to 2.4".
- 【Space Saving & Keep Organized】Desk cable management tray holds all your power cords, outlet strips, USB hubs and computer transformers hidden from your feet, and the data cables will not enter the vacuum cleaner to keep your desk clean and tidy. Desk wire organizer is also suitable for use in the kitchen and outdoors.
- 【Reduce Safety Risks】Cable tray under desk keeps all plugs away from your kids, no more worry about tripping. Using 2 holes wire tray saves extra space, helps you easily cabling and wire protection. The mesh design is not easy to accumulate dust, but avoids safety accidents caused by messy wires.
sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/
Keep the Go service on its loopback HTTP listener unless you have a specific reason to run end-to-end TLS. Nginx is the TLS termination point in this design, and it forwards requests internally over the private interface.
Understand renewal and test it
Let’s Encrypt certificates are valid for 90 days. Ubuntu states that Certbot installs a systemd timer that attempts renewal twice a day. Confirm the timer and perform a safe renewal simulation:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →systemctl list-timers | grep certbot
sudo certbot renew --dry-run
A successful dry run verifies the renewal path without replacing the live certificate. If you use a webroot or DNS-01 workflow instead of the Nginx plugin, configure the challenge method explicitly. DNS-01 is required for wildcard certificates and is useful when a host cannot accept inbound port 80. Its DNS provider credentials should be restricted and stored as secrets.
If another service terminates TLS, or if Nginx must be reloaded in a special way after renewal, configure a Certbot deploy hook. Check the actual renewal logs after changing the hook; an installed timer is not proof that a renewal will succeed in your network and DNS setup.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Choose between one upstream and several
One Go process
For a single instance, keep proxy_pass http://127.0.0.1:8080;. This is easy to understand and gives systemd one process to supervise. It is appropriate when the application’s capacity and availability requirements fit one server and the process can be restarted during a deployment.
Several Go processes on one host
When you need horizontal concurrency or a gradual rollout, run separate instances on private ports and define an Nginx upstream:
Free tools Windows power users keep installed
One-click scans. No signup required.
upstream myapp_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://myapp_backend;
proxy_http_version 1.1;
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;
}
}
Each instance needs its own service definition or a templated systemd unit, a distinct port and a deployment procedure that removes unhealthy instances from rotation. Nginx can distribute requests, but it does not make an in-memory session store or local uploaded files shared. Use an external session or storage system when requests may reach different instances.
Deploy updates without guesswork
- Build a versioned Linux binary and verify its architecture.
- Copy it to a temporary path such as
/tmp/myapp.new. - Install it atomically with the correct owner and mode:
sudo install -o myapp -g myapp -m 0755 /tmp/myapp.new /opt/myapp/bin/myapp. - Run any compatible database migration using a separately reviewed command; do not hide destructive migrations in the service start command.
- Restart the Go service:
sudo systemctl restart myapp. - Inspect
sudo systemctl status myapp --no-pagerandsudo journalctl -u myapp -n 100 --no-pager. - Call the local health endpoint, then make an HTTPS request through Nginx.
- Keep the previous binary until the new process has passed its checks so you can restore it quickly.
Nginx configuration changes are a separate operation: edit the file, run sudo nginx -t, and reload only after the test succeeds. A Go binary change normally requires a service restart, not an Nginx reload.
Troubleshoot by following the request path
| Symptom | Likely layer | Checks and corrective action |
|---|---|---|
systemctl status myapp shows failed |
Binary, environment or permissions | Read journalctl -u myapp -b; verify ExecStart, executable mode, architecture, working directory, environment-file permissions and required files. |
Local curl 127.0.0.1:8080 fails |
Go listener | Check the configured address, port collisions with ss -ltnp, application logs and whether the health route actually exists. |
| Local request works, public request returns 502 | Nginx-to-Go connection | Confirm the upstream address and port, that the service is running, and that Nginx can connect to the loopback listener. Read the Nginx error log. |
| Public request reaches the wrong site | DNS or server-name matching | Verify dig output, the request hostname, enabled symlinks and the server_name value. Run nginx -T to inspect the loaded configuration. |
| Certbot cannot validate | DNS, port 80 or challenge routing | Resolve the hostname externally, allow TCP 80 in every firewall, ensure Nginx answers that hostname and remove conflicting redirects or proxy rules during validation. |
| HTTPS works but the app generates HTTP links | Forwarded scheme handling | Keep proxy_set_header X-Forwarded-Proto $scheme and configure the Go framework to trust that header from the local proxy only. |
| Renewal dry run fails | ACME renewal path | Run sudo certbot renew --dry-run, inspect Certbot logs, check DNS and port 80, and verify any webroot, DNS credentials or deploy hook. |
Use the narrowest test that isolates the failure: local Go request first, HTTP through Nginx second, then HTTPS and finally an external client. This prevents spending time on DNS when the service is not listening, or on Go code when Nginx is serving a different virtual host.
Operational and security checklist
- Run the Go process as a dedicated non-root user and keep its private port bound to loopback.
- Store secrets outside the binary and restrict configuration-file permissions.
- Allow only SSH, HTTP and HTTPS at the host and cloud firewall layers; never publish port 8080.
- Use
nginx -tbefore every reload and keep Nginx and Ubuntu security updates current. - Review
systemctl statusandjournalctlafter every release. - Provide a health endpoint that checks the process without exposing sensitive configuration or credentials.
- Decide how logs are rotated and where application errors, access logs and audit events are retained.
- Back up databases and user-uploaded data separately from the server image; a binary backup is not a data backup.
- Run
certbot renew --dry-runand monitor renewal failures before the 90-day certificate lifetime becomes urgent. - Document rollback: the previous binary, environment version, migration compatibility and the command that restores service.
Key commands at a glance
| Purpose | Command |
|---|---|
| Inspect the Go service | sudo systemctl status myapp --no-pager |
| Follow Go logs | sudo journalctl -u myapp -f |
| Test the private app | curl --fail http://127.0.0.1:8080/healthz |
| Validate Nginx | sudo nginx -t |
| Reload Nginx | sudo systemctl reload nginx |
| Inspect listening sockets | sudo ss -ltnp |
| Test certificate renewal | sudo certbot renew --dry-run |
What to remember
Build for Linux, copy only the release artifacts and configuration, and let systemd own the Go process. Bind Go to a loopback address, put Nginx in front of it with the original host and forwarding headers, and verify the Nginx configuration before every reload. DNS and firewall reachability must be correct before HTTP-01 certificate issuance. Certbot’s systemd timer attempts renewal twice daily, but a dry run is the check that tells you whether your actual renewal path works.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

