En este post voy a documentar cómo montar Sublime POS 3 en un VPS con Ubuntu usando un dominio y SSL de modo que:
- El sistema estará siempre detrás de https
- El certificado SSL será obtenido de Let’s encrypt
- Usaremos Nginx como proxy para esta tarea
Hasta este punto:
- Ya tenemos el dominio comprado en Namecheap y configurado con un A Record con Host en
@
, Value en la IP del VPS y TTL en 30 min. - Ya se ha propagado el DNS, de modo que al acceder al dominio ya se traduce a la IP del VPS.
- Sublime POS 3 ya está ejecutándose en el servidor en http://localhost:2106/static/#
No es obligatorio comprar el dominio en Namecheap, solo te estoy contando. Recuerda que no debes comprar nada más que el dominio y el VPS. No instales nada más.
En este caso usaré Ubuntu pero ya he usado Rocky Linux y funciona perfectamente
Entonces comencemos.
Instalando Nginx
Comencemos instalando Nginx en Ubuntu:
sudo apt update
sudo apt install nginx -y
Comprobamos que se haya instalado correctamente:
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-08-27 18:21:45 CST; 1min 0s ago
Docs: man:nginx(8)
Process: 398686 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exite>
Process: 398687 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status>
Main PID: 398776 (nginx)
Tasks: 2 (limit: 498)
Memory: 4.5M
CPU: 38ms
CGroup: /system.slice/nginx.service
├─398776 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
└─398779 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "">
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$
Lo habilitamos:
sudo systemctl enable nginx
Ahora visitamos el dominio y nos debe mostrar la página de bienvenida de Nginx.
Configurar certificado SSL
Ahora instalamos certbot y el plugin para Nginx. Certbot nos permite hacer la instalación y renovación automática del certificado SSL.
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d ejemplo.com
En mi caso no necesito www así que lo he dejado así. Si quieres que también funcione con www entonces sería así:
sudo certbot --nginx -d ejemplo.com -d www.ejemplo.com
Eso te va a pedir tu correo y algunos datos. Luego te dirá algo como lo siguiente que va a cambiar en tu caso:
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
Account registered.
Requesting a certificate for ejemplo.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/ejemplo.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/ejemplo.com/privkey.pem
This certificate expires on 2025-11-25.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for ejemplo.com to /etc/nginx/sites-enabled/default
Congratulations! You have successfully enabled HTTPS on https://ejemplo.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$
Si te dice Congratulations entonces es que ya quedó configurado. De nuevo, recuerda que debes probar en el dominio.
Todavía nos falta revisar si el renovador automático está habilitado. Para ello ejecutamos:
sudo systemctl status certbot.timer
La salida:
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$ sudo systemctl status certbot.timer
● certbot.timer - Run certbot twice daily
Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Wed 2025-08-27 18:27:42 CST; 4min 32s ago
Trigger: Thu 2025-08-28 04:15:26 CST; 9h left
Triggers: ● certbot.service
Aug 27 18:27:42 ubuntu-s-1vcpu-512mb-10gb-sfo3-01 systemd[1]: Started Run certbot twice daily.
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$
Fíjate en que dice twice daily o sea 2 veces por día. Igualmente puedes ejecutar un dry run o ejecución en seco para simular la renovación y ver si todo va bien:
sudo certbot renew --dry-run
La salida es:
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ejemplo.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for ejemplo.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/ejemplo.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:~$
Lo importante es que diga Congratulations, all simulated renewals succeeded
Reenviar tráfico de Nginx a Sublime POS 3
Ahora solo queda usar la función de proxy de Nginx. Abrimos el archivo de configuración:
sudo vim /etc/nginx/sites-available/default
Y como en mi caso solamente voy a usar Nginx como reverse proxy lo modifico de la siguiente manera.
Originalmente certbot genera la configuración algo así:
server {
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name ejemplo.com; # managed by Certbot
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/ejemplo.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/ejemplo.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
}
Solo modifiqué la parte de location /
así:
location / {
proxy_pass http://localhost:2106;
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;
}
Revisamos si la configuración es correcta:
parzibyte@ubuntu-s-1vcpu-512mb-10gb-sfo3-01:/etc/nginx$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reiniciamos el servicio:
sudo systemctl reload nginx
Y listo. Ahora se accede en dominio.com/static/. No pudo ser simplemente dominio.com porque el sistema expone, en su api, la ruta raíz como raíz de la API y a su vez la carpeta static como parte de esta.
Dicho con otras palabras es obligatorio servir la raíz del servidor, pues si se servía directamente /static entonces no había manera de ir una ruta arriba.
En cambio si se sirve simplemente / se puede ir tanto a /static como a las otras rutas definidas en la API
Por cierto, también tuve que modificar el cliente HTTP en http-common.js:
export const RUTA_SERVIDOR_CON_AUTH = `${window.document.location.origin}/auth/`;
const RUTA_SERVIDOR_SIN_AUTH = `${window.document.location.origin}/`;